[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 2\nindent_style = space\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.{php,xml,htaccess}]\nindent_size = 4\n\n[*.blade.php]\nindent_size = 2\n"
  },
  {
    "path": ".gitattributes",
    "content": "# exclude playgrounds/ since otherwise the project gets classified as mainly php based.\n# https://github.com/github-linguist/linguist/blob/master/docs/overrides.md#summary\nplaygrounds/** linguist-vendored\n\n* text=auto\n"
  },
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "content": "# Code of Conduct\n\nThe Laravel Code of Conduct can be found in the [Laravel documentation](https://laravel.com/docs/contributions#code-of-conduct).\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/0-bug-report.yml",
    "content": "name: Bug Report\ndescription: 'Submit an issue.'\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Please read [our full contribution guide](https://laravel.com/docs/contributions#bug-reports) before submitting bug reports.\n\n        Before submitting, please confirm:\n        - You have **upgraded to the latest version** of both the JS package (`@inertiajs/{adapter}`) and the server-side adapter (`inertiajs/inertia-laravel`) and confirmed the issue still exists\n        - Only Inertia **2.x** and **3.x (beta)** are supported. Issues for 0.x or 1.x will be closed.\n  - type: dropdown\n    attributes:\n      label: Inertia version\n      description: Which major version of Inertia are you using?\n      options:\n        - 2.x (stable)\n        - 3.x (beta)\n    validations:\n      required: true\n  - type: checkboxes\n    attributes:\n      label: Inertia adapter(s) affected\n      description: Select all frontend adapters that are impacted by this issue.\n      options:\n        - label: React\n        - label: Vue 3\n        - label: Svelte\n        - label: Not Applicable\n  - type: input\n    attributes:\n      label: 'JS package version'\n      description: Provide the exact version of `@inertiajs/{adapter}` you are using (e.g. 2.0.3 or 3.0.0-beta.2).\n      placeholder: 2.0.3\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Backend stack (optional)\n      description: If this bug depends on backend integration, provide details such as Laravel version, PHP version, or other relevant environment info.\n      placeholder: |\n        Laravel 12.x\n        PHP 8.4\n    validations:\n      required: false\n  - type: textarea\n    attributes:\n      label: Describe the problem\n      description: Explain the behavior you're seeing that you think is a bug, and describe how you expect it to behave instead.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Steps to reproduce\n      description: Provide clear steps to reproduce the issue. Include a minimal code example that clearly shows the problem.\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/1-bug-report-react.yml",
    "content": "name: Bug Report - React\ndescription: 'Submit a React related issue.'\nlabels: [react]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Please read [our full contribution guide](https://laravel.com/docs/contributions#bug-reports) before submitting bug reports.\n\n        Before submitting, please confirm:\n        - You have **upgraded to the latest version** of both `@inertiajs/react` and `inertiajs/inertia-laravel` and confirmed the issue still exists\n        - Only Inertia **2.x** and **3.x (beta)** are supported. Issues for 0.x or 1.x will be closed.\n  - type: dropdown\n    attributes:\n      label: Inertia version\n      description: Which major version of Inertia are you using?\n      options:\n        - 2.x (stable)\n        - 3.x (beta)\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: '@inertiajs/react Version'\n      description: Provide the exact version of `@inertiajs/react` you are using (e.g. 2.0.3 or 3.0.0-beta.2).\n      placeholder: 2.0.3\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Backend stack (optional)\n      description: If this bug depends on backend integration, provide details such as Laravel version, PHP version, or other relevant environment info.\n      placeholder: |\n        Laravel 12.x\n        PHP 8.4\n    validations:\n      required: false\n  - type: textarea\n    attributes:\n      label: Describe the problem\n      description: Explain the behavior you're seeing that you think is a bug, and describe how you expect it to behave instead.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Steps to reproduce\n      description: Provide clear steps to reproduce the issue. Include a minimal code example that clearly shows the problem.\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/2-bug-report-vue.yml",
    "content": "name: Bug Report - Vue 3\ndescription: 'Submit a Vue 3 related issue.'\nlabels: ['vue 3']\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Please read [our full contribution guide](https://laravel.com/docs/contributions#bug-reports) before submitting bug reports.\n\n        Before submitting, please confirm:\n        - You have **upgraded to the latest version** of both `@inertiajs/vue3` and `inertiajs/inertia-laravel` and confirmed the issue still exists\n        - Only Inertia **2.x** and **3.x (beta)** are supported. Issues for 0.x or 1.x will be closed.\n  - type: dropdown\n    attributes:\n      label: Inertia version\n      description: Which major version of Inertia are you using?\n      options:\n        - 2.x (stable)\n        - 3.x (beta)\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: '@inertiajs/vue3 Version'\n      description: Provide the exact version of `@inertiajs/vue3` you are using (e.g. 2.0.3 or 3.0.0-beta.2).\n      placeholder: 2.0.3\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Backend stack (optional)\n      description: If this bug depends on backend integration, provide details such as Laravel version, PHP version, or other relevant environment info.\n      placeholder: |\n        Laravel 12.x\n        PHP 8.4\n    validations:\n      required: false\n  - type: textarea\n    attributes:\n      label: Describe the problem\n      description: Explain the behavior you're seeing that you think is a bug, and describe how you expect it to behave instead.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Steps to reproduce\n      description: Provide clear steps to reproduce the issue. Include a minimal code example that clearly shows the problem.\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/3-bug-report-svelte.yml",
    "content": "name: Bug Report - Svelte\ndescription: 'Submit a Svelte related issue.'\nlabels: [svelte]\nassignees:\n  - pedroborges\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Please read [our full contribution guide](https://laravel.com/docs/contributions#bug-reports) before submitting bug reports.\n\n        Before submitting, please confirm:\n        - You have **upgraded to the latest version** of both `@inertiajs/svelte` and `inertiajs/inertia-laravel` and confirmed the issue still exists\n        - Only Inertia **2.x** and **3.x (beta)** are supported. Issues for 0.x or 1.x will be closed.\n  - type: dropdown\n    attributes:\n      label: Inertia version\n      description: Which major version of Inertia are you using?\n      options:\n        - 2.x (stable)\n        - 3.x (beta)\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: '@inertiajs/svelte Version'\n      description: Provide the exact version of `@inertiajs/svelte` you are using (e.g. 2.0.3 or 3.0.0-beta.2).\n      placeholder: 2.0.3\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Backend stack (optional)\n      description: If this bug depends on backend integration, provide details such as Laravel version, PHP version, or other relevant environment info.\n      placeholder: |\n        Laravel 12.x\n        PHP 8.4\n    validations:\n      required: false\n  - type: textarea\n    attributes:\n      label: Describe the problem\n      description: Explain the behavior you're seeing that you think is a bug, and describe how you expect it to behave instead.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Steps to reproduce\n      description: Provide clear steps to reproduce the issue. Include a minimal code example that clearly shows the problem.\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Feature Request\n    url: https://github.com/inertiajs/inertia/discussions/new?category=ideas\n    about: 'For ideas or feature requests, start a new discussion'\n  - name: Support Questions & Other\n    url: https://github.com/inertiajs/inertia/discussions/new?category=help\n    about: 'This repository is only for reporting bugs. If you have a question or need help using the library, click:'\n  - name: Documentation issue\n    url: https://github.com/inertiajs/docs\n    about: For documentation issues, open a pull request at the inertiajs/docs repository\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--\nPlease only send a pull request to branches which are currently supported: https://laravel.com/docs/releases#support-policy\n\nIf you are unsure which branch your pull request should be sent to, please read: https://laravel.com/docs/contributions#which-branch\n\nPull requests without a descriptive title, thorough description, or tests will be closed.\n\nIn addition, please describe the benefit to end users; the reasons it does not break any existing features; how it makes building web applications easier, etc.\n-->\n"
  },
  {
    "path": ".github/SECURITY.md",
    "content": "# Security Policy\n\n**PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, [SEE BELOW](#reporting-a-vulnerability).**\n\n## Supported Versions\n\nOnly the latest major version receives security fixes.\n\n## Reporting a Vulnerability\n\nIf you discover a security vulnerability within Laravel, please send an email to Taylor Otwell at taylor@laravel.com. All security vulnerabilities will be promptly addressed.\n\n### Public PGP Key\n\n```\n-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: OpenPGP v2.0.8\nComment: Report Security Vulnerabilities to taylor@laravel.com\n\nxsFNBFugFSQBEACxEKhIY9IoJzcouVTIYKJfWFGvwFgbRjQWBiH3QdHId5vCrbWo\ns2l+4Rv03gMG+yHLJ3rWElnNdRaNdQv59+lShrZF7Bvu7Zvc0mMNmFOM/mQ/K2Lt\nOK/8bh6iwNNbEuyOhNQlarEy/w8hF8Yf55hBeu/rajGtcyURJDloQ/vNzcx4RWGK\nG3CLr8ka7zPYIjIFUvHLt27mcYFF9F4/G7b4HKpn75ICKC4vPoQSaYNAHlHQBLFb\nJg/WPl93SySHLugU5F58sICs+fBZadXYQG5dWmbaF5OWB1K2XgRs45BQaBzf/8oS\nqq0scN8wVhAdBeYlVFf0ImDOxGlZ2suLK1BKJboR6zCIkBAwufKss4NV1R9KSUMv\nYGn3mq13PGme0QoIkvQkua5VjTwWfQx7wFDxZ3VQSsjIlbVyRL/Ac/hq71eAmiIR\nt6ZMNMPFpuSwBfYimrXqqb4EOffrfsTzRenG1Cxm4jNZRzX/6P4an7F/euoqXeXZ\nh37TiC7df+eHKcBI4mL+qOW4ibBqg8WwWPJ+jvuhANyQpRVzf3NNEOwJYCNbQPM/\nPbqYvMruAH+gg7uyu9u0jX3o/yLSxJMV7kF4x/SCDuBKIxSSUI4cgbjIlnxWLXZC\nwl7KW4xAKkerO3wgIPnxNfxQoiYiEKA1c3PShWRA0wHIMt3rVRJxwGM4CwARAQAB\nzRJ0YXlsb3JAbGFyYXZlbC5jb23CwXAEEwEKABoFAlugFSQCGy8DCwkHAxUKCAIe\nAQIXgAIZAQAKCRDKAI7r/Ml7Zo0SD/9zwu9K87rbqXbvZ3TVu7TnN+z7mPvVBzl+\nSFEK360TYq8a4GosghZuGm4aNEyZ90CeUjPQwc5fHwa26tIwqgLRppsG21B/mZwu\n0m8c5RaBFRFX/mCTEjlpvBkOwMJZ8f05nNdaktq6W98DbMN03neUwnpWlNSLeoNI\nu4KYZmJopNFLEax5WGaaDpmqD1J+WDr/aPHx39MUAg2ZVuC3Gj/IjYZbD1nCh0xD\na09uDODje8a9uG33cKRBcKKPRLZjWEt5SWReLx0vsTuqJSWhCybHRBl9BQTc/JJR\ngJu5V4X3f1IYMTNRm9GggxcXrlOAiDCjE2J8ZTUt0cSxedQFnNyGfKxe/l94oTFP\nwwFHbdKhsSDZ1OyxPNIY5OHlMfMvvJaNbOw0xPPAEutPwr1aqX9sbgPeeiJwAdyw\nmPw2x/wNQvKJITRv6atw56TtLxSevQIZGPHCYTSlsIoi9jqh9/6vfq2ruMDYItCq\n+8uzei6TyH6w+fUpp/uFmcwZdrDwgNVqW+Ptu+pD2WmthqESF8UEQVoOv7OPgA5E\nofOMaeH2ND74r2UgcXjPxZuUp1RkhHE2jJeiuLtbvOgrWwv3KOaatyEbVl+zHA1e\n1RHdJRJRPK+S7YThxxduqfOBX7E03arbbhHdS1HKhPwMc2e0hNnQDoNxQcv0GQp4\n2Y6UyCRaus7ATQRboBUkAQgA0h5j3EO2HNvp8YuT1t/VF00uUwbQaz2LIoZogqgC\n14Eb77diuIPM9MnuG7bEOnNtPVMFXxI5UYBIlzhLMxf7pfbrsoR4lq7Ld+7KMzdm\neREqJRgUNfjZhtRZ9Z+jiFPr8AGpYxwmJk4v387uQGh1GC9JCc3CCLJoI62I9t/1\nK2b25KiOzW/FVZ/vYFj1WbISRd5GqS8SEFh4ifU79LUlJ/nEsFv4JxAXN9RqjU0e\nH4S/m1Nb24UCtYAv1JKymcf5O0G7kOzvI0w06uKxk0hNwspjDcOebD8Vv9IdYtGl\n0bn7PpBlVO1Az3s8s6Xoyyw+9Us+VLNtVka3fcrdaV/n0wARAQABwsKEBBgBCgAP\nBQJboBUkBQkPCZwAAhsuASkJEMoAjuv8yXtmwF0gBBkBCgAGBQJboBUkAAoJEA1I\n8aTLtYHmjpIH/A1ZKwTGetHFokJxsd2omvbqv+VtpAjnUbvZEi5g3yZXn+dHJV+K\nUR/DNlfGxLWEcY6datJ3ziNzzD5u8zcPp2CqeTlCxOky8F74FjEL9tN/EqUbvvmR\ntd2LXsSFjHnLJRK5lYfZ3rnjKA5AjqC9MttILBovY2rI7lyVt67kbS3hMHi8AZl8\nEgihnHRJxGZjEUxyTxcB13nhfjAvxQq58LOj5754Rpe9ePSKbT8DNMjHbGpLrESz\ncmyn0VzDMLfxg8AA9uQFMwdlKqve7yRZXzeqvy08AatUpJaL7DsS4LKOItwvBub6\ntHbCE3mqrUw5lSNyUahO3vOcMAHnF7fd4W++eA//WIQKnPX5t3CwCedKn8Qkb3Ow\noj8xUNl2T6kEtQJnO85lKBFXaMOUykopu6uB9EEXEr0ShdunOKX/UdDbkv46F2AB\n7TtltDSLB6s/QeHExSb8Jo3qra86JkDUutWdJxV7DYFUttBga8I0GqdPu4yRRoc/\n0irVXsdDY9q7jz6l7fw8mSeJR96C0Puhk70t4M1Vg/tu/ONRarXQW7fJ8kl21PcD\nUKNWWa242gji/+GLRI8AIpGMsBiX7pHhqmMMth3u7+ne5BZGGJz0uX+CzWboOHyq\nkWgfY4a62t3hM0vwnUkl/D7VgSGy4LiKQrapd3LvU2uuEfFsMu3CDicZBRXPqoXj\nPBjkkPKhwUTNlwEQrGF3QsZhNe0M9ptM2fC34qtxZtMIMB2NLvE4S621rmQ05oQv\nsT0B9WgUL3GYRKdx700+ojHEuwZ79bcLgo1dezvkfPtu/++2CXtieFthDlWHy8x5\nXJJjI1pDfGO+BgX0rS3QrQEYlF/uPQynKwxe6cGI62eZ0ug0hNrPvKEcfMLVqBQv\nw4VH6iGp9yNKMUOgAECLCs4YCxK+Eka9Prq/Gh4wuqjWiX8m66z8YvKf27sFL3fR\nOwGaz3LsnRSxbk/8oSiZuOVLfn44XRcxsHebteZat23lwD93oq54rtKnlJgmZHJY\n4vMgk1jpS4laGnvhZj7OwE0EW6AVJAEIAKJSrUvXRyK3XQnLp3Kfj82uj0St8Dt2\nh8BMeVbrAbg38wCN8XQZzVR9+bRZRR+aCzpKSqwhEQVtH7gdKgfdNdGNhG2DFAVk\nSihMhQz190FKttUZgwY00enzD7uaaA5VwNAZzRIr8skwiASB7UoO+lIhrAYgcQCA\nLpwCSMrUNB3gY1IVa2xi9FljEbS2uMABfOsTfl7z4L4T4DRv/ovDf+ihyZOXsXiH\nRVoUTIpN8ZILCZiiKubE1sMj4fSQwCs06UyDy17HbOG5/dO9awR/LHW53O3nZCxE\nJbCqr5iHa2MdHMC12+luxWJKD9DbVB01LiiPZCTkuKUDswCyi7otpVEAEQEAAcLC\nhAQYAQoADwUCW6AVJAUJDwmcAAIbLgEpCRDKAI7r/Ml7ZsBdIAQZAQoABgUCW6AV\nJAAKCRDxrCjKN7eORjt2B/9EnKVJ9lwB1JwXcQp6bZgJ21r6ghyXBssv24N9UF+v\n5QDz/tuSkTsKK1UoBrBDEinF/xTP2z+xXIeyP4c3mthMHsYdMl7AaGpcCwVJiL62\nfZvd+AiYNX3C+Bepwnwoziyhx4uPaqoezSEMD8G2WQftt6Gqttmm0Di5RVysCECF\nEyhkHwvCcbpXb5Qq+4XFzCUyaIZuGpe+oeO7U8B1CzOC16hEUu0Uhbk09Xt6dSbS\nZERoxFjrGU+6bk424MkZkKvNS8FdTN2s3kQuHoNmhbMY+fRzKX5JNrcQ4dQQufiB\nzFcc2Ba0JVU0nYAMftTeT5ALakhwSqr3AcdD2avJZp3EYfYP/3smPGTeg1cDJV3E\nWIlCtSlhbwviUjvWEWJUE+n9MjhoUNU0TJtHIliUYUajKMG/At5wJZTXJaKVUx32\nUCWr4ioKfSzlbp1ngBuFlvU7LgZRcKbBZWvKj/KRYpxpfvPyPElmegCjAk6oiZYV\nLOV+jFfnMkk9PnR91ZZfTNx/bK+BwjOnO+g7oE8V2g2bA90vHdeSUHR52SnaVN/b\n9ytt07R0f+YtyKojuPmlNsbyAaUYUtJ1o+XNCwdVxzarYEuUabhAfDiVTu9n8wTr\nYVvnriSFOjNvOY9wdLAa56n7/qM8bzuGpoBS5SilXgJvITvQfWPvg7I9C3QhwK1S\nF6B1uquQGbBSze2wlnMbKXmhyGLlv9XpOqpkkejQo3o58B+Sqj4B8DuYixSjoknr\npRbj8gqgqBKlcpf1wD5X9qCrl9vq19asVOHaKhiFZGxZIVbBpBOdvAKaMj4p/uln\nyklN3YFIfgmGPYbL0elvXVn7XfvwSV1mCQV5LtMbLHsFf0VsA16UsG8A/tLWtwgt\n0antzftRHXb+DI4qr+qEYKFkv9F3oCOXyH4QBhPA42EzKqhMXByEkEK9bu6skioL\nmHhDQ7yHjTWcxstqQjkUQ0T/IF9ls+Sm5u7rVXEifpyI7MCb+76kSCDawesvInKt\nWBGOG/qJGDlNiqBYYt2xNqzHCJoC\n=zXOv\n-----END PGP PUBLIC KEY BLOCK-----\n```\n"
  },
  {
    "path": ".github/SUPPORT.md",
    "content": "# Support Questions\n\nThe Laravel support guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions#support-questions).\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Build\non: [push, pull_request]\njobs:\n  build:\n    if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository\n    timeout-minutes: 15\n    runs-on: ubuntu-24.04\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n\n      - name: Install pnpm\n        uses: pnpm/action-setup@v3\n        with:\n          version: 10\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v4\n        with:\n          node-version: 22.14\n          cache: pnpm\n\n      - name: Install dependencies\n        run: pnpm install\n\n      - name: Build Inertia\n        run: pnpm build:all\n"
  },
  {
    "path": ".github/workflows/coding-standards.yml",
    "content": "name: Coding Standards\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n\njobs:\n  format:\n    runs-on: ubuntu-latest\n\n    permissions:\n      contents: write\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Install pnpm\n        uses: pnpm/action-setup@v4\n        with:\n          version: 10\n\n      - name: Install dependencies\n        run: pnpm install\n\n      - name: Format code\n        run: pnpm run format\n\n      - name: Commit linted files\n        uses: stefanzweifel/git-auto-commit-action@v5\n        with:\n          commit_message: 'Fix code style'\n"
  },
  {
    "path": ".github/workflows/es2020-compatibility.yml",
    "content": "name: Compatibility Checks\non: [push, pull_request]\njobs:\n  es2020-compatibility:\n    name: ES2020 (${{ matrix.adapter }})\n    if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository\n    runs-on: ubuntu-24.04\n    timeout-minutes: 15\n\n    strategy:\n      fail-fast: false\n      matrix:\n        adapter: ['core', 'react', 'vue', 'svelte']\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Setup pnpm\n        uses: pnpm/action-setup@v3\n        with:\n          version: 10\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v4\n        with:\n          node-version: 22.14\n          cache: pnpm\n\n      - name: Install dependencies\n        run: pnpm install\n\n      - name: Build core package\n        if: matrix.adapter != 'core'\n        run: pnpm -r --filter ./packages/core build\n\n      - name: Validate ES2020 compatibility\n        run: pnpm -r --filter ./packages/${{ matrix.adapter }}* es2020-check\n"
  },
  {
    "path": ".github/workflows/playwright-chromium.yml",
    "content": "name: Playwright Tests on Chromium\non: [push, pull_request]\njobs:\n  test-chromium:\n    if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository\n    name: Chromium (${{ matrix.adapter }})\n    timeout-minutes: 15\n    runs-on: ubuntu-24.04\n    strategy:\n      matrix:\n        adapter: ['vue', 'react', 'svelte']\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n\n      - name: Install pnpm\n        uses: pnpm/action-setup@v3\n        with:\n          version: 10\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v4\n        with:\n          node-version: 22.14\n          cache: pnpm\n\n      - name: Install dependencies\n        run: pnpm install\n\n      - name: Build Inertia\n        run: pnpm -r --filter ./packages/core --filter ./packages/${{ matrix.adapter }}* build\n\n      - name: Install Playwright Browsers\n        run: pnpm playwright install chromium\n\n      - name: Run Playwright Tests\n        run: pnpm test:${{ matrix.adapter }}\n\n      - name: Upload failure screenshots\n        if: failure()\n        uses: actions/upload-artifact@v4\n        with:\n          name: playwright-failure-screenshots-${{ matrix.adapter }}-chromium\n          path: test-results\n\n  test-chromium-ssr:\n    if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository\n    name: Chromium SSR (${{ matrix.adapter }})\n    timeout-minutes: 15\n    runs-on: ubuntu-24.04\n    strategy:\n      matrix:\n        adapter: ['vue', 'react', 'svelte']\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n\n      - name: Install pnpm\n        uses: pnpm/action-setup@v3\n        with:\n          version: 10\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v4\n        with:\n          node-version: 22.14\n          cache: pnpm\n\n      - name: Install dependencies\n        run: pnpm install\n\n      - name: Build Inertia\n        run: pnpm -r --filter ./packages/core --filter ./packages/${{ matrix.adapter }}* build\n\n      - name: Install Playwright Browsers\n        run: pnpm playwright install chromium\n\n      - name: Run Playwright SSR Tests\n        run: pnpm test:ssr:${{ matrix.adapter }} --project=chromium\n\n      - name: Upload failure screenshots\n        if: failure()\n        uses: actions/upload-artifact@v4\n        with:\n          name: playwright-failure-screenshots-${{ matrix.adapter }}-chromium-ssr\n          path: test-results\n"
  },
  {
    "path": ".github/workflows/playwright-firefox.yml",
    "content": "name: Playwright Tests on Firefox\non: [push, pull_request]\njobs:\n  test-firefox:\n    if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository\n    name: Firefox (${{ matrix.adapter }}) - shard ${{ matrix.shard }} of 3)\n    timeout-minutes: 15\n    runs-on: ubuntu-24.04\n    strategy:\n      matrix:\n        adapter: ['vue', 'react', 'svelte']\n        shard: ['1', '2', '3']\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n\n      - name: Install pnpm\n        uses: pnpm/action-setup@v3\n        with:\n          version: 10\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v4\n        with:\n          node-version: 22.14\n          cache: pnpm\n\n      - name: Install dependencies\n        run: pnpm install\n\n      - name: Build Inertia\n        run: pnpm -r --filter ./packages/core --filter ./packages/${{ matrix.adapter }}* build\n\n      - name: Install Playwright Browsers\n        run: pnpm playwright install firefox\n\n      - name: Run Playwright Tests\n        run: pnpm test:${{ matrix.adapter }} --firefox --shard=${{ matrix.shard }}/3\n\n      - name: Upload failure screenshots\n        if: failure()\n        uses: actions/upload-artifact@v4\n        with:\n          name: playwright-failure-screenshots-${{ matrix.adapter }}-firefox-shard-${{ matrix.shard }}\n          path: test-results\n"
  },
  {
    "path": ".github/workflows/playwright-webkit.yml",
    "content": "name: Playwright Tests on WebKit\non: [push, pull_request]\njobs:\n  test-webkit:\n    if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository\n    name: WebKit (${{ matrix.adapter }} - shard ${{ matrix.shard }} of 4)\n    timeout-minutes: 15\n    runs-on: macos-15\n    strategy:\n      matrix:\n        adapter: ['vue', 'react', 'svelte']\n        shard: ['1', '2', '3', '4']\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n\n      - name: Install pnpm\n        uses: pnpm/action-setup@v3\n        with:\n          version: 10\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v4\n        with:\n          node-version: 22.14\n          cache: pnpm\n\n      - name: Install dependencies\n        run: pnpm install\n\n      - name: Build Inertia\n        run: pnpm -r --filter ./packages/core --filter ./packages/${{ matrix.adapter }}* build\n\n      - name: Install Playwright Browsers\n        run: pnpm playwright install webkit\n\n      - name: Run Playwright Tests\n        run: pnpm test:${{ matrix.adapter }} --webkit --shard=${{ matrix.shard }}/4\n\n      - name: Upload failure screenshots\n        if: failure()\n        uses: actions/upload-artifact@v4\n        with:\n          name: playwright-failure-screenshots-${{ matrix.adapter }}-webkit-shard-${{ matrix.shard }}\n          path: test-results\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "name: Publish Packages\n\non:\n  release:\n    types: [released, prereleased]\n\npermissions:\n  id-token: write # Required for OIDC\n  contents: read\n\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        adapter: ['core', 'vue3', 'react', 'svelte']\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Install pnpm\n        uses: pnpm/action-setup@v4\n        with:\n          version: 10\n\n      - uses: actions/setup-node@v6\n        with:\n          node-version: 24\n          registry-url: 'https://registry.npmjs.org'\n          cache: pnpm\n\n      # Ensure npm 11.5.1 or later is installed\n      - name: Update npm\n        run: npm install -g npm@latest\n\n      - name: Install dependencies\n        run: pnpm install\n\n      - name: 'Publish ${{ matrix.adapter }}'\n        run: pnpm -r --filter ./packages/core --filter ./packages/${{ matrix.adapter }} build\n\n      - name: 'Publish ${{ matrix.adapter }} to npm'\n        run: cd ./packages/${{ matrix.adapter }} && pnpm publish --no-git-checks\n"
  },
  {
    "path": ".github/workflows/test-app-quality.yml",
    "content": "name: Test App Quality\non: [push, pull_request]\njobs:\n  test-app-quality:\n    if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository\n    timeout-minutes: 15\n    runs-on: ubuntu-24.04\n    strategy:\n      matrix:\n        adapter: ['vue', 'react', 'svelte']\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n\n      - name: Install pnpm\n        uses: pnpm/action-setup@v3\n        with:\n          version: 10\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v4\n        with:\n          node-version: 22.14\n          cache: pnpm\n\n      - name: Install dependencies\n        run: pnpm install\n\n      - name: Build Inertia\n        run: pnpm -r --filter ./packages/core --filter ./packages/${{ matrix.adapter }}* build\n\n      - name: Type-check test-app\n        run: cd packages/${{ matrix.adapter == 'vue' && 'vue3' || matrix.adapter }}/test-app && pnpm run type-check\n\n      - name: ESLint test-app\n        run: cd packages/${{ matrix.adapter == 'vue' && 'vue3' || matrix.adapter }}/test-app && pnpm run lint\n"
  },
  {
    "path": ".github/workflows/update-changelog.yml",
    "content": "name: update changelog\n\non:\n  release:\n    types: [released]\n\npermissions: {}\n\njobs:\n  update:\n    permissions:\n      contents: write\n    uses: laravel/.github/.github/workflows/update-changelog.yml@main\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n.idea\n/packages/*/test-app/test-results/.last-run.json\n/packages/svelte/test-app/vite.config.js.timestamp-*.mjs\n/playwright-report\n/test-results\nnode_modules\n"
  },
  {
    "path": ".prettierignore",
    "content": "# Dependencies\nnode_modules/\n**/vendor/\n\n# Build outputs\n**/dist/\n**/.svelte-kit\n**/bootstrap/ssr\n**/public/build\n\n# Files we don't want to format\npnpm-lock.yaml\n*.lock\n*.md\n*.timestamp-*.mjs\n\n# Vue files with parsing issues (dual script blocks)\npackages/vue3/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageA.vue\npackages/vue3/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageB.vue\npackages/vue3/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageA.vue\npackages/vue3/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageB.vue\npackages/vue3/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.vue\npackages/vue3/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.vue\n\n# Directories we don't want to format\n**/test-results/\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\nFor changes prior to v1.0.0, see the [legacy releases](https://legacy.inertiajs.com/releases).\n\n## [Unreleased](https://github.com/inertiajs/inertia/compare/v2.3.18...master)\n\n- Nothing yet\n\n## [v2.3.18](https://github.com/inertiajs/inertia/compare/v2.3.17...v2.3.18) - 2026-03-12\n\n### What's Changed\n\n* Bump [@sveltejs](https://github.com/sveltejs)/kit from 2.53.2 to 2.53.3 by [@dependabot](https://github.com/dependabot)[bot] in https://github.com/inertiajs/inertia/pull/2919\n* Bump multer from 2.0.2 to 2.1.1 by [@dependabot](https://github.com/dependabot)[bot] in https://github.com/inertiajs/inertia/pull/2923\n* [2.x] Remove request from stream on network failure by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2948\n* Use SharedPageProps in GlobalEventsMap event types by [@hamedelasma](https://github.com/hamedelasma) in https://github.com/inertiajs/inertia/pull/2946\n* [2.x] fix: include SharedPageProps in createInertiaApp and onSuccess types by [@isaackaara](https://github.com/isaackaara) in https://github.com/inertiajs/inertia/pull/2931\n* [2.x] Remove `server-renderer` dependency from Vue adapter type by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2955\n* [2.x] fix(types): module augmentation example by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2954\n* [2.x] fix: always fire flash event regardless of partial reload equality by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2953\n* fix: skip view transition when document visibility is hidden by [@mortenhauberg](https://github.com/mortenhauberg) in https://github.com/inertiajs/inertia/pull/2957\n\n### New Contributors\n\n* [@hamedelasma](https://github.com/hamedelasma) made their first contribution in https://github.com/inertiajs/inertia/pull/2946\n* [@mortenhauberg](https://github.com/mortenhauberg) made their first contribution in https://github.com/inertiajs/inertia/pull/2957\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.17...v2.3.18\n\n## [v2.3.17](https://github.com/inertiajs/inertia/compare/v2.3.16...v2.3.17) - 2026-02-26\n\n### What's Changed\n\n* Include resources directory in published packages by [@pushpak1300](https://github.com/pushpak1300) in https://github.com/inertiajs/inertia/pull/2914\n* [2.x] Bump deps by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2916\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.16...v2.3.17\n\n## [v2.3.16](https://github.com/inertiajs/inertia/compare/v2.3.15...v2.3.16) - 2026-02-24\n\n### What's Changed\n\n* Bump [@sveltejs](https://github.com/sveltejs)/kit from 2.50.2 to 2.52.2 by [@dependabot](https://github.com/dependabot)[bot] in https://github.com/inertiajs/inertia/pull/2904\n* Add Boost Guidelines & Skills by [@pushpak1300](https://github.com/pushpak1300) in https://github.com/inertiajs/inertia/pull/2896\n\n### New Contributors\n\n* [@pushpak1300](https://github.com/pushpak1300) made their first contribution in https://github.com/inertiajs/inertia/pull/2896\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.15...v2.3.16\n\n## [v2.3.15](https://github.com/inertiajs/inertia/compare/v2.3.14...v2.3.15) - 2026-02-13\n\n### What's Changed\n\n* Bump axios from 1.13.2 to 1.13.5 by [@dependabot](https://github.com/dependabot)[bot] in https://github.com/inertiajs/inertia/pull/2888\n* [2.x] Fix flash data being cleared by `history.replaceState` by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2889\n* [2.x] Handle `bfcache` restoration for encrypted history by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2890\n* [2.x] Bump dependencies by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2891\n* [2.x] Fix InfiniteScroll loading all pages in reverse mode with flex/grid layouts by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2893\n* [2.x] Improve flaky tests and test app quality by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2895\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.14...v2.3.15\n\n## [v2.3.14](https://github.com/inertiajs/inertia/compare/v2.3.13...v2.3.14) - 2026-02-11\n\n### What's Changed\n\n* [2.x] Shut down entire cluster on SSR shutdown by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2876\n* [2.x] Fix `useForm` type inference when passing data as callback by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2878\n* Add global configuration support for withAllErrors in form components by [@skryukov](https://github.com/skryukov) in https://github.com/inertiajs/inertia/pull/2865\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.13...v2.3.14\n\n## [v2.3.13](https://github.com/inertiajs/inertia/compare/v2.3.12...v2.3.13) - 2026-01-30\n\n### What's Changed\n\n* Fix `useForm` type inference in generic wrapper components by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2851\n* Support wildcard paths in `validate()` method by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2854\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.12...v2.3.13\n\n## [v2.3.12](https://github.com/inertiajs/inertia/compare/v2.3.11...v2.3.12) - 2026-01-27\n\n### What's Changed\n\n* Bump lodash from 4.17.21 to 4.17.23 by [@dependabot](https://github.com/dependabot)[bot] in https://github.com/inertiajs/inertia/pull/2835\n* Bump lodash-es from 4.17.22 to 4.17.23 by [@dependabot](https://github.com/dependabot)[bot] in https://github.com/inertiajs/inertia/pull/2836\n* Fix cancellation of concurrent partial reloads with query parameters by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2843\n* Support for the `formTarget` attribute in the `<Form>` component by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2844\n* Clear stale form errors on resubmit by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2845\n* Prevent `<Deferred>` from rendering children with undefined props by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2846\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.11...v2.3.12\n\n## [v2.3.11](https://github.com/inertiajs/inertia/compare/v2.3.10...v2.3.11) - 2026-01-20\n\n### What's Changed\n\n* Bump and cleanup dependencies by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2822\n* Add test for Precognition validation with transform key changes by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2827\n* TS and console error on conflicting `useForm()` keys by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2823\n* Allow `useForm` without arguments by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2830\n* Pass `true` to `inert` attribute in React 19 by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2831\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.10...v2.3.11\n\n## [v2.3.10](https://github.com/inertiajs/inertia/compare/v2.3.9...v2.3.10) - 2026-01-15\n\n### What's Changed\n\n* Add `async` and `sync` options to `cancelAll` method by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2814\n* Fix smooth scrolling in Firefox and add Firefox to CI by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2815\n* Improve flaky `<InfiniteScroll>` test in WebKit CI by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2818\n* Pass `onceProps` as second argument in client-side visit props callback by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2816\n* Prevent converting a string response to an object by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2821\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.9...v2.3.10\n\n## [v2.3.9](https://github.com/inertiajs/inertia/compare/v2.3.8...v2.3.9) - 2026-01-14\n\n### What's Changed\n\n* Fix React Precognition Error Sync (issue #2806) by [@joetifa2003](https://github.com/joetifa2003) in https://github.com/inertiajs/inertia/pull/2808\n* Add tests for deferred scroll props by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2811\n* Fix deferred props not loading after back button navigation by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2812\n* Add test for concurrent reloads by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2813\n* Cancel in-flight deferred prop requests on navigation by [@alexspeller](https://github.com/alexspeller) in https://github.com/inertiajs/inertia/pull/2656\n* fix: preserve query parameters in test server responses by [@alexspeller](https://github.com/alexspeller) in https://github.com/inertiajs/inertia/pull/2665\n* [2.x] Add Form Context Support by [@laserhybiz](https://github.com/laserhybiz) in https://github.com/inertiajs/inertia/pull/2671\n\n### New Contributors\n\n* [@joetifa2003](https://github.com/joetifa2003) made their first contribution in https://github.com/inertiajs/inertia/pull/2808\n* [@alexspeller](https://github.com/alexspeller) made their first contribution in https://github.com/inertiajs/inertia/pull/2656\n* [@laserhybiz](https://github.com/laserhybiz) made their first contribution in https://github.com/inertiajs/inertia/pull/2671\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.8...v2.3.9\n\n## [v2.3.8](https://github.com/inertiajs/inertia/compare/v2.3.7...v2.3.8) - 2026-01-09\n\n### What's Changed\n\n* fix: update has more state when resetting before updating page by [@AydinHassan](https://github.com/AydinHassan) in https://github.com/inertiajs/inertia/pull/2787\n* Ensure Flash Data listener is registered before event is fired by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2799\n* Improve indices detection in `mergeDataIntoQueryString()` by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2798\n* Fix `<WhenVisible>` re-registering observer when params change by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2804\n\n### New Contributors\n\n* [@AydinHassan](https://github.com/AydinHassan) made their first contribution in https://github.com/inertiajs/inertia/pull/2787\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.7...v2.3.8\n\n## [v2.3.7](https://github.com/inertiajs/inertia/compare/v2.3.6...v2.3.7) - 2026-01-07\n\n### What's Changed\n\n* Add `dontRemember()` method to form helper by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2792\n* Only call `replaceState()` when page data has actually changed by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2793\n* Fix `@typescript-eslint/unbound-method` warning when destructuring `useForm()` methods by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2794\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.6...v2.3.7\n\n## [v2.3.6](https://github.com/inertiajs/inertia/compare/v2.3.5...v2.3.6) - 2025-12-31\n\n### What's Changed\n\n* Bump qs from 6.14.0 to 6.14.1 by [@dependabot](https://github.com/dependabot)[bot] in https://github.com/inertiajs/inertia/pull/2790\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.5...v2.3.6\n\n## [v2.3.5](https://github.com/inertiajs/inertia/compare/v2.3.4...v2.3.5) - 2025-12-31\n\n### What's Changed\n\n* Refresh the Infinite Scroll triggers after partial reload by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2784\n* Fix `hasAnyState()` to actually check for browser history by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2785\n* Handle WebKit history throttle errors by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2786\n* Merge `data` and `params` props in `<WhenVisible>` by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2789\n* Handle `QuotaExceededError` in WebKit by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2788\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.4...v2.3.5\n\n## [v2.3.4](https://github.com/inertiajs/inertia/compare/v2.3.3...v2.3.4) - 2025-12-19\n\n### What's Changed\n\n* Only restore Infinite Scroll state from history on back/forward navigation by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2777\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.3...v2.3.4\n\n## [v2.3.3](https://github.com/inertiajs/inertia/compare/v2.3.2...v2.3.3) - 2025-12-17\n\n### What's Changed\n\n* Add support for protocol-relative urls in url.ts by [@machour](https://github.com/machour) in https://github.com/inertiajs/inertia/pull/2769\n* Fix brackets notation qs parsing by [@skryukov](https://github.com/skryukov) in https://github.com/inertiajs/inertia/pull/2722\n* Support for Flash Data by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2757\n\n### New Contributors\n\n* [@machour](https://github.com/machour) made their first contribution in https://github.com/inertiajs/inertia/pull/2769\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.2...v2.3.3\n\n## [v2.3.2](https://github.com/inertiajs/inertia/compare/v2.3.1...v2.3.2) - 2025-12-16\n\n### What's Changed\n\n* Expose InertiaPrecognitiveForm type by [@lcdss](https://github.com/lcdss) in https://github.com/inertiajs/inertia/pull/2756\n* Test for loading deferred props on `router.reload()` without `only`/`except` by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2761\n* Expose `fetching` in default `<WhenVisible>` slot by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2766\n* Include submitter element value in Form component submission by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2770\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.1...v2.3.2\n\n## [v2.3.1](https://github.com/inertiajs/inertia/compare/v2.3.0...v2.3.1) - 2025-12-12\n\n### What's Changed\n\n* Test for Form + Vue Options API by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2750\n* Fix for validating items in dynamic arrays by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2753\n* Escape forward slashes when using useScriptElementForInitialPage by [@kirk-loretz-fsn](https://github.com/kirk-loretz-fsn) in https://github.com/inertiajs/inertia/pull/2751\n* Sync Playground configs by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2754\n* Fix race condition when restoring scroll regions by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2755\n\n### New Contributors\n\n* [@kirk-loretz-fsn](https://github.com/kirk-loretz-fsn) made their first contribution in https://github.com/inertiajs/inertia/pull/2751\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.3.0...v2.3.1\n\n## [v2.3.0](https://github.com/inertiajs/inertia/compare/v2.2.21...v2.3.0) - 2025-12-11\n\n### What's Changed\n\n* Support for Precognition in `useForm()` by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2684\n* Support for Precognition in `<Form>` component by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2700\n* Improve Precognition examples in Playgrounds by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2746\n* Improve flaky tests by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2747\n* bugfix(whenVisible-vue): Fix loaded state when data already exists by [@ClaraLeigh](https://github.com/ClaraLeigh) in https://github.com/inertiajs/inertia/pull/2748\n\n### New Contributors\n\n* [@ClaraLeigh](https://github.com/ClaraLeigh) made their first contribution in https://github.com/inertiajs/inertia/pull/2748\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.21...v2.3.0\n\n## [v2.2.21](https://github.com/inertiajs/inertia/compare/v2.2.20...v2.2.21) - 2025-12-10\n\n### What's Changed\n\n* Add `viewTransition` to `FormComponentOptions` type  by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2741\n* Preserve untouched Once Props on Partial Reload + Once Props in Playground  by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2743\n* Only preserve loaded Deferred + Once props by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2745\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.20...v2.2.21\n\n## [v2.2.20](https://github.com/inertiajs/inertia/compare/v2.2.19...v2.2.20) - 2025-12-09\n\n### What's Changed\n\n* Bump express from 5.1.0 to 5.2.0 by [@dependabot](https://github.com/dependabot)[bot] in https://github.com/inertiajs/inertia/pull/2727\n* Add tests for SSR server by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2730\n* Preserve errors when loading deferred props by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2729\n* Optimize page data size and parsing (37% size reduction!) by [@bram-pkg](https://github.com/bram-pkg) in https://github.com/inertiajs/inertia/pull/2687\n* Support for `once()` props by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2732\n* Fix for sequential Client Side Visits by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2737\n* Refactor duplicated initial page code by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2738\n\n### New Contributors\n\n* [@bram-pkg](https://github.com/bram-pkg) made their first contribution in https://github.com/inertiajs/inertia/pull/2687\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.19...v2.2.20\n\n## [v2.2.19](https://github.com/inertiajs/inertia/compare/v2.2.18...v2.2.19) - 2025-11-27\n\n### What's Changed\n\n* Bump dependencies by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2710\n* TypeScript fix accessing error keys of optional nested object by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2718\n* Use FormValue in Form component by [@skryukov](https://github.com/skryukov) in https://github.com/inertiajs/inertia/pull/2709\n* Fix anchor hash scrolling on initial page visit in React by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2719\n* Ensure page is rendered before scrolling to top by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2721\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.18...v2.2.19\n\n## [v2.2.18](https://github.com/inertiajs/inertia/compare/v2.2.17...v2.2.18) - 2025-11-17\n\n### What's Changed\n\n* Ensure `objectsAreEqual()` checks all keys in both objects by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2705\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.17...v2.2.18\n\n## [v2.2.17](https://github.com/inertiajs/inertia/compare/v2.2.16...v2.2.17) - 2025-11-14\n\n### What's Changed\n\n* Reset `<WhenVisible>` loading state after a page reload by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2699\n* Add test for reloading deferred props by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2698\n* Force `indices` array format when submitting data using `FormData` by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2701\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.16...v2.2.17\n\n## [v2.2.16](https://github.com/inertiajs/inertia/compare/v2.2.15...v2.2.16) - 2025-11-13\n\n### What's Changed\n\n* Added test for `defaultValue` in Form component by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2685\n* Prevent navigation on right-click on `<Link>` with `prefetch=\"click\"` by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2676\n* Export page component type for React adapter by [@skryukov](https://github.com/skryukov) in https://github.com/inertiajs/inertia/pull/2691\n* Switch `useContext` to `use` in `usePage()` hook by [@HichemTab-tech](https://github.com/HichemTab-tech) in https://github.com/inertiajs/inertia/pull/2680\n* Improve serialization in `formDataToObject()` when mixing numeric and non-numeric object keys by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2692\n* Fix `InfiniteScroll` scroll preservation by [@skryukov](https://github.com/skryukov) in https://github.com/inertiajs/inertia/pull/2689\n* Export Inertia `App` component by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2695\n* Ignore `preserveScroll` and `preserveState` when finding cached response by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2694\n* Upgrade Express server for test apps to v5 by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2693\n* Add WebKit browser testing to CI with Safari compatibility fixes by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2696\n* Bump symfony/http-foundation from 7.3.4 to 7.3.7 in /playgrounds/vue3 by [@dependabot](https://github.com/dependabot)[bot] in https://github.com/inertiajs/inertia/pull/2697\n* Fix array keys misalignment in form data and query by [@skryukov](https://github.com/skryukov) in https://github.com/inertiajs/inertia/pull/2690\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.15...v2.2.16\n\n## [v2.2.15](https://github.com/inertiajs/inertia/compare/v2.2.14...v2.2.15) - 2025-10-30\n\n### What's Changed\n\n* TS Fix for circularly references in form data  by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2673\n* Improve TS for config defaults by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2674\n* [v2.x] feat: allow adding type to `router.restore` by [@peaklabs-dev](https://github.com/peaklabs-dev) in https://github.com/inertiajs/inertia/pull/2545\n* Configurable prefetch hover delay by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2675\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.14...v2.2.15\n\n## [v2.2.14](https://github.com/inertiajs/inertia/compare/v2.2.13...v2.2.14) - 2025-10-28\n\n### What's Changed\n\n* TS cleanup for `<Link>` component + View Transition prop in Svelte by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2667\n* Improve support for `any` as form data value by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2668\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.13...v2.2.14\n\n## [v2.2.13](https://github.com/inertiajs/inertia/compare/v2.2.12...v2.2.13) - 2025-10-28\n\n### What's Changed\n\n* Support for View Transitions by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2658\n* Opt-in to using `data-inertia` attribute in `<Head>` component by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2663\n* Opt-in to using `<dialog>` for error modals by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2664\n* feat: give access to underlying data as object and as form data object by [@MeiKatz](https://github.com/MeiKatz) in https://github.com/inertiajs/inertia/pull/2605\n\n### New Contributors\n\n* [@MeiKatz](https://github.com/MeiKatz) made their first contribution in https://github.com/inertiajs/inertia/pull/2605\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.12...v2.2.13\n\n## [v2.2.12](https://github.com/inertiajs/inertia/compare/v2.2.11...v2.2.12) - 2025-10-27\n\n### What's Changed\n\n* Clone page props before writing it to the browser's history by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2662\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.11...v2.2.12\n\n## [v2.2.11](https://github.com/inertiajs/inertia/compare/v2.2.10...v2.2.11) - 2025-10-24\n\n### What's Changed\n\n* Configure global defaults and update during runtime by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2655\n* Stabilize prop references when visiting the same page by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2657\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.10...v2.2.11\n\n## [v2.2.10](https://github.com/inertiajs/inertia/compare/v2.2.9...v2.2.10) - 2025-10-23\n\n### What's Changed\n\n* Restore uppercase `Component` object key in React's `App.ts` by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2654\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.9...v2.2.10\n\n## [v2.2.9](https://github.com/inertiajs/inertia/compare/v2.2.8...v2.2.9) - 2025-10-21\n\n### What's Changed\n\n* Use local `@inertiajs/core` in Playgrounds + dependencies bump by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2633\n* Introduce types for Head Manager by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2634\n* Fix resolving `preserveScroll` and `preserveState` in Client Side Visits by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2635\n* Support for type-hinting shared Page Props by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2636\n* Add `globals.d.ts` file to Playgrounds by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2637\n* Remove wrong `shouldIntercept()` call in `keydown` event handler in `<Link>` component by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2638\n* Introduce `CancelToken` and `CancelTokenCallback` types to replace Axios imports by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2639\n* Internal TypeScript improvements by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2640\n* Tests and TS improvements for the `<Head>` component by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2641\n* Make `data` prop of `<InfiniteScroll>` required by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2642\n* TS fixes in Vue adapter for `useRemember` and `remember` mixin by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2643\n* Bump vite from 5.4.20 to 5.4.21 by [@dependabot](https://github.com/dependabot)[bot] in https://github.com/inertiajs/inertia/pull/2647\n* TypeScript improvements to `createInertiaApp()` and unifying it across adapters by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2648\n* ESLint check for test-apps by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2560\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.8...v2.2.9\n\n## [v2.2.8](https://github.com/inertiajs/inertia/compare/v2.2.7...v2.2.8) - 2025-10-09\n\n### What's Changed\n\n* Prevent false positives in `getScrollableParent()` by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2626\n* Restore scroll regions after navigation by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2627\n* Prevent replacing history state when scroll regions are unchanged to fix popstate behavior in WebKit by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2629\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.7...v2.2.8\n\n## [v2.2.7](https://github.com/inertiajs/inertia/compare/v2.2.6...v2.2.7) - 2025-10-07\n\n### What's Changed\n\n* Preserve relative URL when `<InfiniteScroll>` updates query string by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2623\n* Use `SlotsType` to type-hint Vue slots by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2620\n* Fix race condition in `history.ts` by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2624\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.6...v2.2.7\n\n## [v2.2.6](https://github.com/inertiajs/inertia/compare/v2.2.5...v2.2.6) - 2025-10-03\n\n### What's Changed\n\n* SSR fixes for `<InfiniteScroll>` component. by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2616\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.5...v2.2.6\n\n## [v2.2.5](https://github.com/inertiajs/inertia/compare/v2.2.4...v2.2.5) - 2025-10-02\n\n### What's Changed\n\n* Improve `<InfiniteScroll>` cleanup after navigating away by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2610\n* Fix for `<Form>` component when using React SSR by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2612\n* Fix conflicting Client Side Visits by queuing the URL synchronization by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2613\n* Improvements to `<InfiniteScroll>` in Svelte adapter by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2614\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.4...v2.2.5\n\n## [v2.2.4](https://github.com/inertiajs/inertia/compare/v2.2.3...v2.2.4) - 2025-09-30\n\n### What's Changed\n\n* Compile TS while developing + improve CLI output by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2600\n* Improve testing of scroll restoration by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2602\n* Fix for reloading an unrelated prop affecting infinite scroll by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2603\n* Add `preserve-url` prop to `<Link>` component by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2541\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.3...v2.2.4\n\n## [v2.2.3](https://github.com/inertiajs/inertia/compare/v2.2.2...v2.2.3) - 2025-09-29\n\n### What's Changed\n\n* Preserve `ScrollProp` on Partial Reloads by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2597\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.2...v2.2.3\n\n## [v2.2.2](https://github.com/inertiajs/inertia/compare/v2.2.1...v2.2.2) - 2025-09-28\n\n### What's Changed\n\n* Reset `ScrollProp` when requested by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2595\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.1...v2.2.2\n\n## [v2.2.1](https://github.com/inertiajs/inertia/compare/v2.2.0...v2.2.1) - 2025-09-28\n\n### What's Changed\n\n* Don't restore remembered state after a refresh by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2591\n* Remember Infinite Scroll state by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2592\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.2.0...v2.2.1\n\n## [v2.2.0](https://github.com/inertiajs/inertia/compare/v2.1.11...v2.2.0) - 2025-09-26\n\n### What's Changed\n\n* Support for merging nested prop paths by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2561\n* Client-side visit helpers to update props by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2589\n* Introduction of the `<InfiniteScroll>` component by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2580\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.1.11...v2.2.0\n\n## [v2.1.11](https://github.com/inertiajs/inertia/compare/v2.1.10...v2.1.11) - 2025-09-24\n\n### What's Changed\n\n* Fix flaky tests in CI by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2582\n* Bump Playwright by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2585\n* Progress indicator API by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2581\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.1.10...v2.1.11\n\n## [v2.1.10](https://github.com/inertiajs/inertia/compare/v2.1.9...v2.1.10) - 2025-09-22\n\n### What's Changed\n\n* Fix PNPM publishing by [@joetannenbaum](https://github.com/joetannenbaum) in https://github.com/inertiajs/inertia/pull/2578\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.1.9...v2.1.10\n\n## [v2.1.9](https://github.com/inertiajs/inertia/compare/v2.1.8...v2.1.9) - 2025-09-22\n\n### What's Changed\n\n* Fix PNPM build by [@joetannenbaum](https://github.com/joetannenbaum) in https://github.com/inertiajs/inertia/pull/2577\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.1.8...v2.1.9\n\n## [v2.1.8](https://github.com/inertiajs/inertia/compare/v2.1.7...v2.1.8) - 2025-09-22\n\n### What's Changed\n\n* Publish packages in CI by [@joetannenbaum](https://github.com/joetannenbaum) in https://github.com/inertiajs/inertia/pull/2575\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.1.7...v2.1.8\n\n## [v2.1.7](https://github.com/inertiajs/inertia/compare/v2.1.6...v2.1.7) - 2025-09-18\n\n### What's Changed\n\n* Bump axios from 1.11.0 to 1.12.0 by [@dependabot](https://github.com/dependabot)[bot] in https://github.com/inertiajs/inertia/pull/2568\n* Bump dependencies by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2571\n* TypeScript upgrade by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2573\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.1.6...v2.1.7\n\n## [v2.1.6](https://github.com/inertiajs/inertia/compare/v2.1.5...v2.1.6) - 2025-09-12\n\n### What's Changed\n\n* Invalidate prefetch cache when page is received from a network request by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2567\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.1.5...v2.1.6\n\n## [v2.1.5](https://github.com/inertiajs/inertia/compare/v2.1.4...v2.1.5) - 2025-09-05\n\n### What's Changed\n\n* Fix race condition when combining Deferred Props with an instant Partial Reload on mount by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2562\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.1.4...v2.1.5\n\n## [v2.1.4](https://github.com/inertiajs/inertia/compare/v2.1.3...v2.1.4) - 2025-09-03\n\n### What's Changed\n\n* Replace html-escape with built-in function on Svelte package by [@kresnasatya](https://github.com/kresnasatya) in https://github.com/inertiajs/inertia/pull/2535\n* Update dirty state after DOM changes (React only) by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2558\n* Prevent errors caused by null href value by [@fritz-c](https://github.com/fritz-c) in https://github.com/inertiajs/inertia/pull/2550\n* Remove data from the dependency array of setDefaults by [@jasonlbeggs](https://github.com/jasonlbeggs) in https://github.com/inertiajs/inertia/pull/2554\n\n### New Contributors\n\n* [@fritz-c](https://github.com/fritz-c) made their first contribution in https://github.com/inertiajs/inertia/pull/2550\n* [@jasonlbeggs](https://github.com/jasonlbeggs) made their first contribution in https://github.com/inertiajs/inertia/pull/2554\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.1.3...v2.1.4\n\n## [v2.1.3](https://github.com/inertiajs/inertia/compare/v2.1.2...v2.1.3) - 2025-08-27\n\n### What's Changed\n\n* Code formatting with Prettier by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2515\n* Add EditorConfig and fix some whitespace issues by [@jrmajor](https://github.com/jrmajor) in https://github.com/inertiajs/inertia/pull/2516\n* Fix for nullable object types in `useForm` by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2528\n* Fix for Form Component in Svelte when resetting use input/button by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2525\n* Improve Link component `as` prop by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2524\n* [v2.x] fix: type error by changing page props type to `any` by [@peaklabs-dev](https://github.com/peaklabs-dev) in https://github.com/inertiajs/inertia/pull/2520\n* Revert to back to Lodash to retain ES2020 compatibility by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2527\n* Verify ES2020 compatibility in CI by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2530\n* [Vue] Fixing action attribute on Form Component when using Wayfinder by [@nicolagianelli](https://github.com/nicolagianelli) in https://github.com/inertiajs/inertia/pull/2532\n* Make package.json structure in Svelte package Consistent as Vue and React by [@kresnasatya](https://github.com/kresnasatya) in https://github.com/inertiajs/inertia/pull/2529\n* Remove Svelte 5-next version constraint by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2533\n* improve typescript configuration by [@sudo-barun](https://github.com/sudo-barun) in https://github.com/inertiajs/inertia/pull/2470\n* Format JSON files with Prettier by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2534\n* Fix warning about `inert` attribute in React < 19 by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2536\n* Fix keyboard activation when using `prefetch: 'click'` by [@pedroborges](https://github.com/pedroborges) in https://github.com/inertiajs/inertia/pull/2538\n* Fix `useForm` to respect manual `setDefaults()` calls in `onSuccess` and unify timing across adapters by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2539\n* Run Playwright in parallel in CI by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2540\n* Fix Coding Standards workflow by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2547\n* bumpup axios to fix CVE-2025-7783 by [@vallerydelexy](https://github.com/vallerydelexy) in https://github.com/inertiajs/inertia/pull/2546\n* Bump `@sveltejs/kit` version by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2548\n\n### New Contributors\n\n* [@peaklabs-dev](https://github.com/peaklabs-dev) made their first contribution in https://github.com/inertiajs/inertia/pull/2520\n* [@nicolagianelli](https://github.com/nicolagianelli) made their first contribution in https://github.com/inertiajs/inertia/pull/2532\n* [@kresnasatya](https://github.com/kresnasatya) made their first contribution in https://github.com/inertiajs/inertia/pull/2529\n* [@vallerydelexy](https://github.com/vallerydelexy) made their first contribution in https://github.com/inertiajs/inertia/pull/2546\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.1.2...v2.1.3\n\n## [v2.1.2](https://github.com/inertiajs/inertia/compare/v2.1.1...v2.1.2) - 2025-08-15\n\n### What's Changed\n\n* Fix for manipulating form after redirect in `onSubmitComplete` by [@joetannenbaum](https://github.com/joetannenbaum) in https://github.com/inertiajs/inertia/pull/2510\n* Support for passing Wayfinder objects to router methods by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2497\n* Tag-based cache invalidation for prefetch requests by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2484\n* Add `resetOnError`, `resetOnSuccess`, `setDefaultsOnSuccess` to Form component by [@joetannenbaum](https://github.com/joetannenbaum) in https://github.com/inertiajs/inertia/pull/2514\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.1.1...v2.1.2\n\n## [v2.1.1](https://github.com/inertiajs/inertia/compare/v2.1.0...v2.1.1) - 2025-08-14\n\n### What's Changed\n\n* Improve `Link` component types and support for prefetch events by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2464\n* allow passing partial errors object to `setError()` by [@sudo-barun](https://github.com/sudo-barun) in https://github.com/inertiajs/inertia/pull/2461\n* Add missing generic type support to PendingVisit and VisitHelperOptions by [@HichemTab-tech](https://github.com/HichemTab-tech) in https://github.com/inertiajs/inertia/pull/2454\n* Revamp useForm's generic types across adaptors by [@Spice-King](https://github.com/Spice-King) in https://github.com/inertiajs/inertia/pull/2335\n* TypeScript improvements for `Link` component and Client Side Visits by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2472\n* Further TS improvements for `useForm` by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2475\n* Improve consistency in `useForm` across adapters by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2482\n* Improve TypeScript support for Client Side Visit `props` callback by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2483\n* TS improvements to Svelte's `<Form>` and `useForm()` implementations by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2489\n* Typescript Improvements by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2468\n* Test apps in TypeScript by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2469\n* Fix empty action in `<Form>` component when the current URL has more than one segment by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2501\n* Support uppercase method in `<Form>` component by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2502\n* Add `Form` component `disableWhileProcessing` prop by [@joetannenbaum](https://github.com/joetannenbaum) in https://github.com/inertiajs/inertia/pull/2504\n* Reset form fields by name in Form components by [@skryukov](https://github.com/skryukov) in https://github.com/inertiajs/inertia/pull/2499\n* Add `onSubmitComplete` prop to `Form` component by [@joetannenbaum](https://github.com/joetannenbaum) in https://github.com/inertiajs/inertia/pull/2503\n* Remove failed prefetch requests from in-flight array by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2500\n* Add `defaults()` method to Form component by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2507\n* Release script by [@joetannenbaum](https://github.com/joetannenbaum) in https://github.com/inertiajs/inertia/pull/2508\n* Only `reset()` and `defaults()` in `onSubmitComplete` by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2509\n\n### New Contributors\n\n* [@sudo-barun](https://github.com/sudo-barun) made their first contribution in https://github.com/inertiajs/inertia/pull/2461\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.1.0...v2.1.1\n\n## [v2.1.0](https://github.com/inertiajs/inertia/compare/v2.0.17...v2.1.0) - 2025-08-13\n\n### What's Changed\n\n* Support for passing custom component to `as` prop of `Link` component. by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2443\n* Use `nodemon` to trigger new files and deleted files in test apps by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2442\n* Use ReactNode type for children props by [@chack1172](https://github.com/chack1172) in https://github.com/inertiajs/inertia/pull/2385\n* Allow function as children component in react Deferred and WhenVisible by [@chack1172](https://github.com/chack1172) in https://github.com/inertiajs/inertia/pull/2386\n* Improve test that waits for scroll position restoration by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2473\n* Introduction of the `Form` component by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2474\n* Improve `children` prop of `<Form>` Component by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2487\n* Add Form component ref support by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2496\n* Make Svelte's <Deferred> not crash in an SSR environment by [@dkulchenko](https://github.com/dkulchenko) in https://github.com/inertiajs/inertia/pull/2396\n* Fix core: Queue processing when an item fails by [@pintend](https://github.com/pintend) in https://github.com/inertiajs/inertia/pull/2467\n* Migrate playgrounds to Tailwind 4 by [@jrmajor](https://github.com/jrmajor) in https://github.com/inertiajs/inertia/pull/2369\n\n### New Contributors\n\n* [@dkulchenko](https://github.com/dkulchenko) made their first contribution in https://github.com/inertiajs/inertia/pull/2396\n* [@pintend](https://github.com/pintend) made their first contribution in https://github.com/inertiajs/inertia/pull/2467\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.0.17...v2.1.0\n\n## [v2.0.17](https://github.com/inertiajs/inertia/compare/v2.0.16...v2.0.17) - 2025-07-18\n\n### What's Changed\n\n* Bump multer from 2.0.1 to 2.0.2 by [@dependabot](https://github.com/dependabot)[bot] in https://github.com/inertiajs/inertia/pull/2447\n* Bump vite from 5.4.12 to 5.4.19 by [@dependabot](https://github.com/dependabot)[bot] in https://github.com/inertiajs/inertia/pull/2450\n* Bump esbuild from 0.21.5 to 0.25.0 by [@dependabot](https://github.com/dependabot)[bot] in https://github.com/inertiajs/inertia/pull/2451\n* Explicit string coercion in `Head` component by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2453\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.0.16...v2.0.17\n\n## [v2.0.16](https://github.com/inertiajs/inertia/compare/v2.0.15...v2.0.16) - 2025-07-18\n\n### What's Changed\n\n* Make errorBag parameter optional by [@joelstein](https://github.com/joelstein) in https://github.com/inertiajs/inertia/pull/2445\n\n### New Contributors\n\n* [@joelstein](https://github.com/joelstein) made their first contribution in https://github.com/inertiajs/inertia/pull/2445\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.0.15...v2.0.16\n\n## [v2.0.15](https://github.com/inertiajs/inertia/compare/v2.0.14...v2.0.15) - 2025-07-17\n\n### What's Changed\n\n* Improve GitHub issue templates by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2418\n* Escape the attribute values that are passed into the `Head` component by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2403\n* Introduce single method to reset form state and clear errors by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2414\n* Use `CacheForOption` type in React `Link` component by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2426\n* Improve query string merging in `mergeDataIntoQueryString()`  by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2417\n* Improve scrolling when using anchor hash by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2428\n* Cancel sync request on popstate event by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2429\n* Support for path traversal by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2413\n* Add event callbacks to `ClientSideVisitOptions` by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2405\n* Pass parameters to `onFinish` and `onSuccess` callbacks on Client Side Visits by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2433\n* Prevent JS builds and test apps from being minified by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2424\n* Migrate to pnpm by [@jrmajor](https://github.com/jrmajor) in https://github.com/inertiajs/inertia/pull/2276\n* Fix single-use prefetching by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2440\n* Change defaults values order in onSuccess callback of useForm by [@yilanboy](https://github.com/yilanboy) in https://github.com/inertiajs/inertia/pull/2437\n* Improve reactivity of Link components by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2441\n\n### New Contributors\n\n* [@yilanboy](https://github.com/yilanboy) made their first contribution in https://github.com/inertiajs/inertia/pull/2437\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.0.14...v2.0.15\n\n## [v2.0.14](https://github.com/inertiajs/inertia/compare/v2.0.13...v2.0.14) - 2025-06-26\n\n### What's Changed\n\n* fix: fixed type error in `useForm SetDataAction` type by [@fxnm](https://github.com/fxnm) in https://github.com/inertiajs/inertia/pull/2395\n* Call `provider.update` outside useEffect block to support SSR by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2397\n* Improve state restore logic in `useRemember` by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2401\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.0.13...v2.0.14\n\n## [v2.0.13](https://github.com/inertiajs/inertia/compare/v2.0.12...v2.0.13) - 2025-06-20\n\n### What's Changed\n\n* Allow deepMerge on custom properties by [@mpociot](https://github.com/mpociot) in https://github.com/inertiajs/inertia/pull/2344\n* fix: React StrictMode breaking Inertia Head by [@jordanhavard](https://github.com/jordanhavard) in https://github.com/inertiajs/inertia/pull/2328\n* Bump multer from 1.4.4 to 2.0.1 in /tests/app by [@dependabot](https://github.com/dependabot) in https://github.com/inertiajs/inertia/pull/2373\n* Initialize router before components in React by [@chack1172](https://github.com/chack1172) in https://github.com/inertiajs/inertia/pull/2379\n* Prevent duplicate render of the initial page in React by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2377\n* Update default state when `setDefault()` is called right after `setData()` is called by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2364\n* [2.x] Restore `router.resolveComponent()` method by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2039\n* Move `currentIsInitialPage` variable outside of `App` by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2381\n* Don't overwrite Vite class in Svelte playgrounds by [@jrmajor](https://github.com/jrmajor) in https://github.com/inertiajs/inertia/pull/2368\n* Dependency update + Prevent Playwright 1.53.0 due to Svelte bug by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2382\n* Update to Vite 6 by [@SuperDJ](https://github.com/SuperDJ) in https://github.com/inertiajs/inertia/pull/2315\n* Fix React scroll restoration on popState by [@sebastiandedeyne](https://github.com/sebastiandedeyne) in https://github.com/inertiajs/inertia/pull/2357\n* feat(useForm): export granular setData types and introduce SetDataAction<TForm> by [@hasib-devs](https://github.com/hasib-devs) in https://github.com/inertiajs/inertia/pull/2356\n* Refactor `mergeStrategies` to `matchOn` by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2384\n* Remove `setSwapComponent` method and cleanup after PR #2379 by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2383\n\n### New Contributors\n\n* [@jordanhavard](https://github.com/jordanhavard) made their first contribution in https://github.com/inertiajs/inertia/pull/2328\n* [@chack1172](https://github.com/chack1172) made their first contribution in https://github.com/inertiajs/inertia/pull/2379\n* [@jrmajor](https://github.com/jrmajor) made their first contribution in https://github.com/inertiajs/inertia/pull/2368\n* [@SuperDJ](https://github.com/SuperDJ) made their first contribution in https://github.com/inertiajs/inertia/pull/2315\n* [@hasib-devs](https://github.com/hasib-devs) made their first contribution in https://github.com/inertiajs/inertia/pull/2356\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.0.12...v2.0.13\n\n## [v2.0.12](https://github.com/inertiajs/inertia/compare/v2.0.11...v2.0.12) - 2025-06-10\n\n### What's Changed\n\n* Send `Purpose: prefetch` header on prefetching by [@pascalbaljet](https://github.com/pascalbaljet) in https://github.com/inertiajs/inertia/pull/2367\n\n### New Contributors\n\n* [@pascalbaljet](https://github.com/pascalbaljet) made their first contribution in https://github.com/inertiajs/inertia/pull/2367\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.0.11...v2.0.12\n\n## [v2.0.11](https://github.com/inertiajs/inertia/compare/v2.0.10...v2.0.11) - 2025-05-16\n\n### What's Changed\n\n* Fix progress bar not showing on subsequent page clicks by [@joetannenbaum](https://github.com/joetannenbaum) in https://github.com/inertiajs/inertia/pull/2349\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.0.10...v2.0.11\n\n## [v2.0.10](https://github.com/inertiajs/inertia/compare/v2.0.9...v2.0.10) - 2025-05-15\n\n### What's Changed\n\n* Don't show progress bar on prefetch hover by [@joetannenbaum](https://github.com/joetannenbaum) in https://github.com/inertiajs/inertia/pull/2347\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.0.9...v2.0.10\n\n## [v2.0.9](https://github.com/inertiajs/inertia/compare/v2.0.8...v2.0.9) - 2025-05-09\n\n### What's Changed\n\n* Bump [@sveltejs](https://github.com/sveltejs)/kit from 2.11.1 to 2.20.6 by [@dependabot](https://github.com/dependabot) in https://github.com/inertiajs/inertia/pull/2312\n* Bump vite from 5.4.17 to 5.4.18 by [@dependabot](https://github.com/dependabot) in https://github.com/inertiajs/inertia/pull/2307\n* Fix for deferred props + prefetch links by [@joetannenbaum](https://github.com/joetannenbaum) in https://github.com/inertiajs/inertia/pull/2321\n* Progress: Make hide and reveal CSP-compatible by [@flexponsive](https://github.com/flexponsive) in https://github.com/inertiajs/inertia/pull/2316\n* Corrected URL search parameter merge logic to match behavior prior to v2.0.8 by [@joetannenbaum](https://github.com/joetannenbaum) in https://github.com/inertiajs/inertia/pull/2341\n* Corrects url search parameter merge logic to match behavior prior to v2.0.8 by [@CTOJoe](https://github.com/CTOJoe) in https://github.com/inertiajs/inertia/pull/2320\n* Bump vite from 5.4.18 to 5.4.19 by [@dependabot](https://github.com/dependabot) in https://github.com/inertiajs/inertia/pull/2334\n* On back button, fetch from server if version hash is not current by [@joetannenbaum](https://github.com/joetannenbaum) in https://github.com/inertiajs/inertia/pull/2342\n* Allow custom URL protocols by [@mpociot](https://github.com/mpociot) in https://github.com/inertiajs/inertia/pull/2329\n\n### New Contributors\n\n* [@flexponsive](https://github.com/flexponsive) made their first contribution in https://github.com/inertiajs/inertia/pull/2316\n* [@CTOJoe](https://github.com/CTOJoe) made their first contribution in https://github.com/inertiajs/inertia/pull/2320\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.0.8...v2.0.9\n\n## [v2.0.8](https://github.com/inertiajs/inertia/compare/v2.0.7...v2.0.8) - 2025-04-10\n\n### What's Changed\n\n* Add deepMerge Support for Merging Nested Arrays and Objects in Props by [@HichemTab-tech](https://github.com/HichemTab-tech) in https://github.com/inertiajs/inertia/pull/2069\n* fix: build error because of invalid type definitions by [@fxnm](https://github.com/fxnm) in https://github.com/inertiajs/inertia/pull/2301\n* fix(vue/useForm/defaults): untrack before assign by [@Dsaquel](https://github.com/Dsaquel) in https://github.com/inertiajs/inertia/pull/2112\n* Improve type checking of request data by [@7nohe](https://github.com/7nohe) in https://github.com/inertiajs/inertia/pull/2304\n* Remove empty payload from GET requests by [@edgars-vasiljevs](https://github.com/edgars-vasiljevs) in https://github.com/inertiajs/inertia/pull/2305\n\n### New Contributors\n\n* [@HichemTab-tech](https://github.com/HichemTab-tech) made their first contribution in https://github.com/inertiajs/inertia/pull/2069\n* [@fxnm](https://github.com/fxnm) made their first contribution in https://github.com/inertiajs/inertia/pull/2301\n* [@Dsaquel](https://github.com/Dsaquel) made their first contribution in https://github.com/inertiajs/inertia/pull/2112\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.0.7...v2.0.8\n\n## [v2.0.7](https://github.com/inertiajs/inertia/compare/v2.0.6...v2.0.7) - 2025-04-08\n\n### What's Changed\n\n* Added missing pages to React and Svelte5 playrounds by [@Verox001](https://github.com/Verox001) in https://github.com/inertiajs/inertia/pull/2217\n* chore: replace lodash to decrease bundle size by [@lcdss](https://github.com/lcdss) in https://github.com/inertiajs/inertia/pull/2210\n* do not pass url when storing scroll state to history by [@miDeb](https://github.com/miDeb) in https://github.com/inertiajs/inertia/pull/2280\n* fix: react `Deferred` component error on partial visits by [@KaioFelps](https://github.com/KaioFelps) in https://github.com/inertiajs/inertia/pull/2223\n* Bump vite from 5.4.16 to 5.4.17 by [@dependabot](https://github.com/dependabot) in https://github.com/inertiajs/inertia/pull/2295\n* [2.x] SSR clustering by [@RobertBoes](https://github.com/RobertBoes) in https://github.com/inertiajs/inertia/pull/2206\n* Allow Object type for href prop by [@nckrtl](https://github.com/nckrtl) in https://github.com/inertiajs/inertia/pull/2292\n* Update GitHub Actions to Ubuntu 24.04 by [@joetannenbaum](https://github.com/joetannenbaum) in https://github.com/inertiajs/inertia/pull/2299\n* [2.x]: Support for nested paths in forms by [@joaopalopes24](https://github.com/joaopalopes24) in https://github.com/inertiajs/inertia/pull/2181\n\n### New Contributors\n\n* [@Verox001](https://github.com/Verox001) made their first contribution in https://github.com/inertiajs/inertia/pull/2217\n* [@lcdss](https://github.com/lcdss) made their first contribution in https://github.com/inertiajs/inertia/pull/2210\n* [@miDeb](https://github.com/miDeb) made their first contribution in https://github.com/inertiajs/inertia/pull/2280\n* [@KaioFelps](https://github.com/KaioFelps) made their first contribution in https://github.com/inertiajs/inertia/pull/2223\n* [@nckrtl](https://github.com/nckrtl) made their first contribution in https://github.com/inertiajs/inertia/pull/2292\n* [@joaopalopes24](https://github.com/joaopalopes24) made their first contribution in https://github.com/inertiajs/inertia/pull/2181\n\n**Full Changelog**: https://github.com/inertiajs/inertia/compare/v2.0.6...v2.0.7\n\n## [v2.0.6](https://github.com/inertiajs/inertia/compare/v2.0.5...v2.0.6)\n\n- Deferred: More descriptive Deferred data prop error ([#2284](https://github.com/inertiajs/inertia/pull/2284))\n- Bump vite from 5.4.12 to 5.4.16 ([#2288](https://github.com/inertiajs/inertia/pull/2288))\n- Fix location return history decryption throwing error ([#2282](https://github.com/inertiajs/inertia/pull/2282))\n- Make isDirty reactive to defaults ([#2236](https://github.com/inertiajs/inertia/pull/2236))\n- Fix playground WhenVisible always ([#2203](https://github.com/inertiajs/inertia/pull/2203))\n- Wayfinder support ([#2290](https://github.com/inertiajs/inertia/pull/2290))\n\n## [v2.0.5](https://github.com/inertiajs/inertia/compare/v2.0.4...v2.0.5)\n\n- Fix history state errors by nicholaspufal ([#2265](https://github.com/inertiajs/inertia/pull/2265))\n- Bump axios from 1.7.9 to 1.8.2 ([#2269](https://github.com/inertiajs/inertia/pull/2269))\n- Bump esbuild from 0.16.17 to 0.25.0 #2231 ([#2231](https://github.com/inertiajs/inertia/pull/2231))\n- Bump vite from 5.4.11 to 5.4.12 ([#2201](https://github.com/inertiajs/inertia/pull/2201))\n\n## [v2.0.4](https://github.com/inertiajs/inertia/compare/v2.0.3...v2.0.4)\n\n- Fix anchor links on initial visits ([#2258](https://github.com/inertiajs/inertia/pull/2258))\n\n## [v2.0.3](https://github.com/inertiajs/inertia/compare/v2.0.2...v2.0.3)\n\n- Fix: Reload on mount ([#2200](https://github.com/inertiajs/inertia/pull/2200))\n\n## [v2.0.2](https://github.com/inertiajs/inertia/compare/v2.0.1...v2.0.2)\n\n- Fix SSR with scroll restoration ([#2190](https://github.com/inertiajs/inertia/pull/2190))\n- Fix for scroll + back bug ([#2191](https://github.com/inertiajs/inertia/pull/2191))\n- Backport 1.x fixes from [v1.3.0](https://github.com/inertiajs/inertia/releases/tag/v1.3.0) release ([#2193](https://github.com/inertiajs/inertia/pull/2193))\n\n## [v2.0.1](https://github.com/inertiajs/inertia/compare/v2.0.0...v2.0.1)\n\n- Fix playground dependencies ([#2070](https://github.com/inertiajs/inertia/pull/2070))\n- Removed Vitest tests + dependencies ([#2175](https://github.com/inertiajs/inertia/pull/2175))\n- Augment `vue` instead of `@vue/runtime-core` ([#2099](https://github.com/inertiajs/inertia/pull/2099))\n- Fix prefetch missing `cacheFor` default value ([#2136](https://github.com/inertiajs/inertia/pull/2136))\n- Fix `useForm` re-renders by memoizing functions in React [#2146](https://github.com/inertiajs/inertia/pull/2146)\n- WhenVisible useEffect function is not recreated when params change. ([#2153](https://github.com/inertiajs/inertia/pull/2153))\n- Ensure callback execution ([#2163](https://github.com/inertiajs/inertia/pull/2163))\n- More resilient logic for stripping the origin from page URLs ([#2164](https://github.com/inertiajs/inertia/pull/2164))\n- Add helper scripts for running tests ([#2173](https://github.com/inertiajs/inertia/pull/2173))\n- Export `InertiaFormProps` in React ([#2161](https://github.com/inertiajs/inertia/pull/2161))\n- Use default empty object in `useForm` Vue and Svelte ([#2052](https://github.com/inertiajs/inertia/pull/2052))\n- Remove `data` option from `useForm` options type ([#2060](https://github.com/inertiajs/inertia/pull/2060))\n- Take over scroll restoration from browser ([#2051](https://github.com/inertiajs/inertia/pull/2051))\n\n## [v2.0.0](https://github.com/inertiajs/inertia/compare/v1.2.0...v2.0.0)\n\n### Added\n\n- Add polling\n- Add link prefetching\n- Add deferred props\n- Add lazy loading of data when scrolling\n- Add history encryption API\n- Add React 19 support ([#2131](https://github.com/inertiajs/inertia/pull/2131))\n- Add client side visits ([#2130](https://github.com/inertiajs/inertia/pull/2130))\n\n### Changed\n\n- Removal of NProgress dependency ([#2045](https://github.com/inertiajs/inertia/pull/2045))\n- Change TypeScript module resolution in the Svelte adapter ([#2035](https://github.com/inertiajs/inertia/pull/2035))\n- Refactor `createInertiaApp` in Svelte adapter ([#2036](https://github.com/inertiajs/inertia/pull/2036))\n\n### Fixed\n\n- Fix: make Link href prop reactive ([#2089](https://github.com/inertiajs/inertia/pull/2089))\n\n## [v1.3.0](https://github.com/inertiajs/inertia/compare/v1.2.0...v1.3.0)\n\n### Added\n\n- Add React 19 support ([#2121](https://github.com/inertiajs/inertia/pull/2121))\n- Add Svelte 5 support ([#1970](https://github.com/inertiajs/inertia/pull/1970))\n- Add TypeScript support to Svelte adapter ([#1866](https://github.com/inertiajs/inertia/pull/1866), [69292e](https://github.com/inertiajs/inertia/commit/69292ef3592ccca5e0f05f7ce131a53f6c1ba22b), [#2003](https://github.com/inertiajs/inertia/pull/2003), [#2005](https://github.com/inertiajs/inertia/pull/2005))\n\n### Changed\n\n- Skip intercepting non-left button clicks on links ([#1908](https://github.com/inertiajs/inertia/pull/1908), [#1910](https://github.com/inertiajs/inertia/pull/1910))\n- Changed `preserveScroll` to be `true` on initial page visit ([#1360](https://github.com/inertiajs/inertia/pull/1360))\n- Return early when using `router.on()` during SSR ([#1715](https://github.com/inertiajs/inertia/pull/1715))\n- Use updater function in `setData` in `useForm` hook in React adapter ([#1859](https://github.com/inertiajs/inertia/pull/1859))\n\n### Fixed\n\n- Fix history navigation issue on Chrome iOS ([#1984](https://github.com/inertiajs/inertia/pull/1984), [#1992](https://github.com/inertiajs/inertia/pull/1992))\n- Fix `setNavigationType` for Safari 10 ([#1957](https://github.com/inertiajs/inertia/pull/1957))\n- Export `InertiaFormProps` in all adapters ([#1596](https://github.com/inertiajs/inertia/pull/1596), [#1734](https://github.com/inertiajs/inertia/pull/1734))\n- Fix `isDirty` after `form.defaults()` call in Vue 3 ([#1985](https://github.com/inertiajs/inertia/pull/1985))\n- Fix scroll reset on page navigation ([#1980](https://github.com/inertiajs/inertia/pull/1980))\n- Fix scroll position restoration for `[scroll-region]` elements ([#1782](https://github.com/inertiajs/inertia/pull/1782), [#1980](https://github.com/inertiajs/inertia/pull/1980))\n- Fix `useForm` re-renders by memoizing functions in React adapter ([#1607](https://github.com/inertiajs/inertia/pull/1607))\n- Fix doubling hash when using `<React.StrictMode>` ([#1728](https://github.com/inertiajs/inertia/pull/1728))\n- Fix type augmentation in Vue 3 adapter ([#1958](https://github.com/inertiajs/inertia/pull/1958))\n- Fix form helper `transform` return type in React adapter ([#1896](https://github.com/inertiajs/inertia/pull/1896))\n- Fix props reactivity in Svelte adapter ([#1969](https://github.com/inertiajs/inertia/pull/1969))\n- Fix `<Render />` component to respect `preserveState` option in Svelte adapter ([#1943](https://github.com/inertiajs/inertia/pull/1943))\n- Fix 'received an unexpected slot \"default\"' warning in Svelte adapter ([#1941](https://github.com/inertiajs/inertia/pull/1941))\n- Fix command + click behavior on links in React adapter ([#2132](https://github.com/inertiajs/inertia/pull/2132))\n- Fix import in Svelte adapter ([#2002](https://github.com/inertiajs/inertia/pull/2002))\n\n## [v1.2.0](https://github.com/inertiajs/inertia/compare/v1.1.0...v1.2.0)\n\n- Fix `preserveScroll` and `preserveState` types ([#1882](https://github.com/inertiajs/inertia/pull/1882))\n- Revert \"merge props from partial reloads\" ([#1895](https://github.com/inertiajs/inertia/pull/1895))\n\n## [v1.1.0](https://github.com/inertiajs/inertia/compare/v1.0.16...v1.1.0)\n\n- Add new `except` visit option to exclude props from partial reloads ([#1876](https://github.com/inertiajs/inertia/pull/1876))\n- Deep merge props from partial reloads ([#1877](https://github.com/inertiajs/inertia/pull/1877))\n\n## [v1.0.16](https://github.com/inertiajs/inertia/compare/v1.0.15...v1.0.16)\n\n- Fix Svelte 4 slot rendering issues ([#1763](https://github.com/inertiajs/inertia/pull/1763))\n- Fix accessibility warning in Svelte `Link` component ([#1858](https://github.com/inertiajs/inertia/pull/1858))\n- Use `Omit` instead of `Exclude` in router types ([#1857](https://github.com/inertiajs/inertia/pull/1857))\n\n## [v1.0.15](https://github.com/inertiajs/inertia/compare/v1.0.14...v1.0.15)\n\n- Bump axios from `v1.4.0` to `v1.6.0` ([#1723](https://github.com/inertiajs/inertia/pull/1723))\n\n## [v1.0.14](https://github.com/inertiajs/inertia/compare/v1.0.13...v1.0.14)\n\n- Revert \"Clear errors on form reset (#1568)\" ([#1716](https://github.com/inertiajs/inertia/pull/1716))\n\n## [v1.0.13](https://github.com/inertiajs/inertia/compare/v1.0.12...v1.0.13)\n\n- Clear errors on form reset ([#1568](https://github.com/inertiajs/inertia/pull/1568))\n- Fix `Link` type in React ([#1659](https://github.com/inertiajs/inertia/pull/1659))\n\n## [v1.0.12](https://github.com/inertiajs/inertia/compare/v1.0.11...v1.0.12)\n\n- Fix type of `onClick` for `Link` component in React and Vue ([#1699](https://github.com/inertiajs/inertia/pull/1699), [#1701](https://github.com/inertiajs/inertia/pull/1701))\n\n## [v1.0.11](https://github.com/inertiajs/inertia/compare/v1.0.10...v1.0.11)\n\n- Fix form helper types for `setDefaults()` method (React) and `defaults()` method (Vue) ([#1504](https://github.com/inertiajs/inertia/pull/1504))\n- Fix interface issue with `useForm()` in React and Vue adapters ([#1649](https://github.com/inertiajs/inertia/pull/1649))\n\n## [v1.0.10](https://github.com/inertiajs/inertia/compare/v1.0.9...v1.0.10)\n\n- Fix Svelte's `useForm` helper ([#1610](https://github.com/inertiajs/inertia/pull/1610))\n\n## [v1.0.9](https://github.com/inertiajs/inertia/compare/v1.0.8...v1.0.9)\n\n- Fix `<Head>` vNode handling in Vue 3 adapter ([#1590](https://github.com/inertiajs/inertia/pull/1590))\n- Add Svelte 4 support ([60699c7](https://github.com/inertiajs/inertia/commit/60699c7c5978eebd393e0333b567d8e465f4b58f))\n\n## [v1.0.8](https://github.com/inertiajs/inertia/compare/v1.0.7...v1.0.8)\n\n### Fixed\n\n- Fix `<Head>` vNode handling in Vue 3 adapter ([#1570](https://github.com/inertiajs/inertia/pull/1570))\n- Fix watching remembered data in Vue 3 adapter ([#1571](https://github.com/inertiajs/inertia/pull/1571))\n\n## [v1.0.7](https://github.com/inertiajs/inertia/compare/v1.0.6...v1.0.7)\n\n### Fixed\n\n- Fix `<Head>` fragment detection in Vue 3 adapter ([#1509](https://github.com/inertiajs/inertia/pull/1509))\n\n## [v1.0.6](https://github.com/inertiajs/inertia/compare/v1.0.5...v1.0.6)\n\n### Fixed\n\n- Fix `usePage()` null object error in Vue 3 adapter ([#1530](https://github.com/inertiajs/inertia/pull/1530))\n\n## [v1.0.5](https://github.com/inertiajs/inertia/compare/v1.0.4...v1.0.5)\n\n### Fixed\n\n- Fix `usePage()` reactivity in Vue 2 adapter ([#1527](https://github.com/inertiajs/inertia/pull/1527))\n\n### Changed\n\n- Simplify the Vue 2 form helper ([#1529](https://github.com/inertiajs/inertia/pull/1529))\n\n## [v1.0.4](https://github.com/inertiajs/inertia/compare/v1.0.3...v1.0.4)\n\n### Added\n\n- Added `displayName` to `Link` component in React adapter ([#1512](https://github.com/inertiajs/inertia/pull/1512))\n\n### Fixed\n\n- Fix `usePage()` reactivity in Vue 3 adapter ([#1469](https://github.com/inertiajs/inertia/pull/1469))\n\n## [v1.0.3](https://github.com/inertiajs/inertia/compare/v1.0.2...v1.0.3)\n\n### Added\n\n- Added initialization callback to form helper in Vue adapters ([#1516](https://github.com/inertiajs/inertia/pull/1516))\n\n## [v1.0.2](https://github.com/inertiajs/inertia/compare/v1.0.1...v1.0.2)\n\n### Fixed\n\n- Added explicit children to `InertiaHeadProps` ([#1448](https://github.com/inertiajs/inertia/pull/1448))\n- Exported `InertiaLinkProps` type ([#1450](https://github.com/inertiajs/inertia/pull/1450))\n- Improved React `usePage` generic type ([#1451](https://github.com/inertiajs/inertia/pull/1451))\n\n## [v1.0.1](https://github.com/inertiajs/inertia/compare/v1.0.0...v1.0.1)\n\n### Fixed\n\n- Fixed Vue type overrides for `$page` and `$inertia` ([#1393](https://github.com/inertiajs/inertia/pull/1393))\n- Restored React `usePage` generic type ([#1396](https://github.com/inertiajs/inertia/pull/1396))\n- Prevented need to use `Method` enum with the Link component ([#1392](https://github.com/inertiajs/inertia/pull/1392))\n- Restored Vue 3 `usePage` generic type ([#1394](https://github.com/inertiajs/inertia/pull/1394))\n- Fixed export of server types ([#1397](https://github.com/inertiajs/inertia/pull/1397))\n- Updated form types to support nested data ([#1401](https://github.com/inertiajs/inertia/pull/1401))\n- Allowed stronger type support with Vue `useForm` ([#1413](https://github.com/inertiajs/inertia/pull/1413))\n- Fixed Vue 2 `setup` prop types ([#1418](https://github.com/inertiajs/inertia/pull/1418))\n- Fixed issue when passing multiple children to React `Head` component ([#1433](https://github.com/inertiajs/inertia/pull/1433))\n\n## [v1.0.0](https://github.com/inertiajs/inertia/compare/7ce91ec...v1.0.0) - 2023-01-14\n\n### Added\n\n- Added SSR support to Svelte library ([#1349](https://github.com/inertiajs/inertia/pull/1349))\n- Added first-class TypeScript support to React adapter\n- Added first-class TypeScript support to Vue 2 adapter\n- Added first-class TypeScript support to Vue 3 adapter\n- Added new `useForm()` hook to Vue 2 adapter ([ff59196](https://github.com/inertiajs/inertia/commit/ff59196))\n\n### Changed\n\n- Renamed `@inertiajs/inertia` library to `@inertiajs/core` ([#1282](https://github.com/inertiajs/inertia/pull/1282))\n- Renamed `@inertiajs/inertia-react` library to `@inertiajs/react` ([#1282](https://github.com/inertiajs/inertia/pull/1282))\n- Renamed `@inertiajs/inertia-svelte` library to `@inertiajs/svelte` ([#1282](https://github.com/inertiajs/inertia/pull/1282))\n- Renamed `@inertiajs/inertia-vue` library to `@inertiajs/vue2` ([#1282](https://github.com/inertiajs/inertia/pull/1282))\n- Renamed `@inertiajs/inertia-vue3` library to `@inertiajs/vue3` ([#1282](https://github.com/inertiajs/inertia/pull/1282))\n- Merged progress library to core and deprecated `@inertiajs/progress` library ([#1282](https://github.com/inertiajs/inertia/pull/1282), [0b5f773](https://github.com/inertiajs/inertia/commit/0b5f773))\n- Merged server library to core and deprecated `@inertiajs/server` library ([#1282](https://github.com/inertiajs/inertia/pull/1282))\n- Renamed `Inertia` named export to `router` ([#1282](https://github.com/inertiajs/inertia/pull/1282), [e556703](https://github.com/inertiajs/inertia/commit/e556703))\n- Removed deprecated named exports ([#1282](https://github.com/inertiajs/inertia/pull/1282), [e556703](https://github.com/inertiajs/inertia/commit/e556703))\n- Removed deprecated `app` argument from `createInertiaApp()` in Vue adapters ([#1282](https://github.com/inertiajs/inertia/pull/1282), [65f8a5f](https://github.com/inertiajs/inertia/commit/65f8a5f))\n- Updated axios to 1.x ([#1377](https://github.com/inertiajs/inertia/pull/1377))\n- Simplified `usePage()` hook in Vue 3 adapter ([#1373](https://github.com/inertiajs/inertia/pull/1373))\n- Improved Svelte `use:inertia` and `<Link />` component ([#1344](https://github.com/inertiajs/inertia/pull/1344))\n- Removed global `visitOptions()` hook ([#1282](https://github.com/inertiajs/inertia/pull/1282), [30908c2](https://github.com/inertiajs/inertia/commit/30908c2))\n- Switched bundler from Microbundle to ESbuild ([f711b46](https://github.com/inertiajs/inertia/commit/f711b46), [8093713](https://github.com/inertiajs/inertia/commit/8093713), [342312d](https://github.com/inertiajs/inertia/commit/342312d), [c9e12b3](https://github.com/inertiajs/inertia/commit/c9e12b3))\n\n### Fixed\n\n- Fixed `<title>` tag not always being included when a `title` callback is defined in `createInertiaApp()` ([#1055](https://github.com/inertiajs/inertia/pull/1055))\n- Fixed types to include `undefined` as a valid `FormDataConvertable` option ([#1165](https://github.com/inertiajs/inertia/pull/1165))\n- Fixed issue where remembered state wasn't clear on a full page reload ([769f643](https://github.com/inertiajs/inertia/commit/769f643))\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nThank you for your interest in contributing to Inertia.js! Your contributions help make this project better for everyone.\n\nInertia.js is maintained as a monorepo using [pnpm workspaces](https://pnpm.io/workspaces). Below you'll find an overview of the repository and how to get your development environment running.\n\n> **Note:** You'll need **pnpm version 10 or higher**. If you're unsure which version you have, run `pnpm -v`.\n\n## Repository Overview\n\n```\ninertia/\n├── packages/          Core libraries and framework adapters\n│   ├── core/          Framework-agnostic core library\n│   ├── react/         React adapter\n│   │   └── test-app/  React test application\n│   ├── svelte/        Svelte adapter\n│   │   └── test-app/  Svelte test application\n│   └── vue3/          Vue 3 adapter\n│       └── test-app/  Vue 3 test application\n├── playgrounds/       Full Laravel applications for manual testing\n│   ├── react/         Laravel + React\n│   ├── svelte4/       Laravel + Svelte 4\n│   ├── svelte5/       Laravel + Svelte 5\n│   └── vue3/          Laravel + Vue 3\n└── tests/             End-to-end tests and test server\n    ├── app/           Shared Node.js backend\n    └── *.spec.ts      Playwright test suite\n```\n\n### Key Components\n\n- **Core Library:** The framework-agnostic engine powering all adapters (`packages/core`).\n- **Adapters:** Framework-specific integrations for React, Svelte, and Vue.\n- **Test Applications:** Minimal frontend apps used for automated testing (`packages/*/test-app/`).\n- **Playwright Tests:** Framework-agnostic end-to-end tests that verify behavior across adapters (`tests/*.spec.ts`).\n- **Playgrounds:** Full Laravel applications for manual testing (`playgrounds/`). These are optional and may eventually be removed.\n\n## Getting Started\n\nClone the repository and install the dependencies:\n\n```sh\ngit clone https://github.com/inertiajs/inertia.git inertia\ncd inertia\npnpm install\n```\n\nThen, start the development environment:\n\n```sh\npnpm dev\n```\n\nThis builds the core library and all adapters, and starts a file watcher that will automatically rebuild each package when changes are made.\n\nIf you prefer, you can also start individual watchers from each package directory. For example:\n\n```sh\ncd packages/core && pnpm dev\ncd packages/react && pnpm dev\n```\n\n> **Note:** The core package (`packages/core`) must always be running, as all adapters depend on it.\n\n## Running Tests\n\nInertia.js uses Playwright to run a shared end-to-end test suite against each adapter. This is how we verify that Inertia behaves the same across React, Svelte, and Vue.\n\nRun the test suite for a specific adapter:\n\n```sh\npnpm test:react\npnpm test:svelte\npnpm test:vue\n```\n\nThese commands automatically set a `PACKAGE` environment variable that tells the Node.js test server which adapter to serve. For example, when running `pnpm test:react`, the test server loads the React test application.\n\nIf you want to run Playwright directly, you can pass the environment variable yourself:\n\n```sh\nPACKAGE=react playwright test\n```\n\nYou may filter tests by name:\n\n```sh\npnpm test:react -g \"partial reload\"\n```\n\nRun tests in headed mode (to see the browser):\n\n```sh\npnpm test:vue --headed\n```\n\nOr in debug mode:\n\n```sh\npnpm test:vue --debug\n```\n\n### How the Test Setup Works\n\nAll adapters use the same Node.js backend and Playwright test suite. The only difference is which adapter's test app is served.\n\n```\ntests/app/server.js         Shared Node.js backend\n├── serves: react test app  (when PACKAGE=react)\n├── serves: svelte test app (when PACKAGE=svelte)\n└── serves: vue test app    (when PACKAGE=vue3)\n\ntests/*.spec.ts             Shared Playwright test suite\n```\n\nWhen running a test command, the correct adapter is selected automatically:\n\n| Adapter | `PACKAGE` value | Test server port | App URL                                            |\n| ------- | --------------- | ---------------- | -------------------------------------------------- |\n| React   | `react`         | 13716            | [http://localhost:13716/](http://localhost:13716/) |\n| Svelte  | `svelte`        | 13717            | [http://localhost:13717/](http://localhost:13717/) |\n| Vue 3   | `vue3`          | 13715            | [http://localhost:13715/](http://localhost:13715/) |\n\n### Automatic Test Server Boot\n\nYou do not need to start the test server manually. When you run a test, Playwright automatically builds the frontend for the selected adapter and boots the Node.js test server before running the tests. This is configured in the Playwright config (`playwright.config.ts`) using the [`webServer`](https://playwright.dev/docs/test-configuration#webserver) option. If a server is already running (for example, during local development), Playwright will reuse it.\n\n## Running Test Applications\n\nThe test applications are the primary development environments for Inertia.js. These minimal apps cover all supported features and are used for both manual development and automated end-to-end testing.\n\nRun all test apps at once:\n\n```sh\npnpm dev:test-app\n```\n\nOr start an individual one:\n\n```sh\npnpm dev:test-app:react\npnpm dev:test-app:svelte\npnpm dev:test-app:vue\n```\n\nEach test app runs two servers:\n\n- A Node.js backend that automatically restarts when changed\n- A Vite development server for the frontend\n\nIf you are developing a new feature or fixing a bug, you can use these test apps to develop and test your changes.\n\n## Adding Tests\n\nIf you are fixing a bug, adding a feature, or improving existing functionality, please verify that your changes work across all adapters, not just one.\n\n### 1. Add Frontend Pages\n\nCreate the same frontend page in each test application:\n\n```\npackages/react/test-app/Pages/YourFeature.jsx\npackages/svelte/test-app/Pages/YourFeature.svelte\npackages/vue3/test-app/Pages/YourFeature.vue\n```\n\nEach page should provide the same behavior and functionality.\n\n### 2. Add Backend Routes (If Needed)\n\nIf your change requires a backend route, add it to the shared Node.js test server:\n\n```javascript\n// tests/app/server.js\napp.get('/your-feature', (req, res) =>\n  inertia.render(req, res, {\n    component: 'YourFeature',\n    props: { foo: 'bar' },\n  }),\n)\n```\n\n### 3. Write a Playwright Test\n\nAdd a new Playwright test to verify your change. Playwright allows us to test features across all adapters without duplicating test logic.\n\n```typescript\n// tests/your-feature.spec.ts\nimport { test, expect } from '@playwright/test'\n\ntest('your feature works', async ({ page }) => {\n  await page.goto('/your-feature')\n  // Your assertions here\n})\n```\n\n### 4. Run the Tests in All Adapters\n\nBe sure to run your test for each adapter:\n\n```sh\npnpm test:react -g \"your feature\"\npnpm test:svelte -g \"your feature\"\npnpm test:vue -g \"your feature\"\n```\n\nYour work is not considered complete until it works consistently across all frameworks.\n\n## Using the Playgrounds (Optional)\n\nThe repository also includes several full Laravel applications that integrate Inertia.js. These are optional and mostly useful for manually exploring how Inertia works inside a real Laravel app.\n\nThe playgrounds are provided as-is and are not part of the automated test setup. They may be removed in the future.\n\n### Getting Started\n\nTo start a playground, simply run:\n\n```sh\npnpm playground:react\n```\n\nThe playground script will automatically handle initial setup if needed:\n- Installing PHP dependencies via Composer\n- Installing Node.js dependencies via pnpm\n- Creating the `.env` file from `.env.example`\n- Generating the application key\n- Setting up the SQLite database\n- Running migrations with seed data\n\nVisit the application at [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nEach playground has its own pnpm script:\n\n```sh\npnpm playground:react\npnpm playground:svelte4\npnpm playground:svelte5\npnpm playground:vue\n```\n\n## Publishing (Maintainers Only)\n\nReleasing is handled by the included release script. You'll need both the `git` CLI and the GitHub CLI ([`gh`](https://cli.github.com)) installed. To create a new release:\n\n```sh\n./release.sh\n```\n\nThe script will:\n- Ensure you're on the master branch with a clean working tree\n- Prompt you to select the type of version bump (patch, minor, or major)\n- Update all package versions automatically\n- Update the lockfile\n- Create a git commit and tag\n- Push changes and tags to GitHub\n- Create a GitHub release with auto-generated notes\n- Trigger the CI publishing workflow\n\nPublishing is handled securely using GitHub + npm [trusted publishing](https://docs.npmjs.com/trusted-publishers).\n"
  },
  {
    "path": "LICENSE.md",
    "content": "MIT License\n\nCopyright (c) Jonathan Reinink <jonathan@reinink.ca>\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": "[![Inertia.js](https://raw.githubusercontent.com/inertiajs/inertia/master/.github/LOGO.png)](https://inertiajs.com/)\n\nInertia.js lets you quickly build modern single-page React, Vue and Svelte apps using classic server-side routing and controllers. Find full documentation at [inertiajs.com](https://inertiajs.com/).\n\n## Contributing\n\nThank you for considering contributing to Inertia! You can read the contribution guide [here](CONTRIBUTING.md).\n\n## Code of Conduct\n\nIn order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).\n\n## Security Vulnerabilities\n\nPlease review [our security policy](https://github.com/inertiajs/inertia/security/policy) on how to report security vulnerabilities.\n\n## License\n\nInertia is open-sourced software licensed under the [MIT license](LICENSE.md).\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"inertia\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build:all\": \"pnpm -r --filter './packages/*' build\",\n    \"dev\": \"pnpx concurrently -c \\\"#b794f4,#61dafb,#d43008,#32a06f\\\" \\\"pnpm dev:core\\\" \\\"pnpm dev:react\\\" \\\"pnpm dev:svelte\\\" \\\"pnpm dev:vue\\\" --names=core,react,svelte,vue\",\n    \"dev:core\": \"cd packages/core && pnpm run dev\",\n    \"dev:vue\": \"cd packages/vue3 && pnpm run dev\",\n    \"dev:react\": \"cd packages/react && pnpm run dev\",\n    \"dev:svelte\": \"cd packages/svelte && pnpm run dev\",\n    \"dev:test-app\": \"pnpx concurrently -c \\\"#61dafb,#d43008,#32a06f\\\" \\\"pnpm dev:test-app:react\\\" \\\"pnpm dev:test-app:svelte\\\" \\\"pnpm dev:test-app:vue\\\" --names=react,svelte,vue\",\n    \"dev:test-app:react\": \"pnpx concurrently -c \\\"#c4b5fd,#ffa800\\\" \\\"cd tests/app && PACKAGE=react pnpm serve:watch\\\" \\\"cd packages/react/test-app && pnpm run dev\\\" --names=server,vite\",\n    \"dev:test-app:svelte\": \"pnpx concurrently -c \\\"#c4b5fd,#ffa800\\\" \\\"cd tests/app && PACKAGE=svelte pnpm serve:watch\\\" \\\"cd packages/svelte/test-app && pnpm run dev\\\" --names=server,vite\",\n    \"dev:test-app:vue\": \"pnpx concurrently -c \\\"#c4b5fd,#ffa800\\\" \\\"cd tests/app && PACKAGE=vue3 pnpm serve:watch\\\" \\\"cd packages/vue3/test-app && pnpm run dev\\\" --names=server,vite\",\n    \"es2020-check\": \"pnpm -r --filter './packages/*' es2020-check\",\n    \"lint:test-app\": \"pnpm -r --filter './packages/*/test-app' lint\",\n    \"lint:test-app:react\": \"cd packages/react/test-app && pnpm run lint\",\n    \"lint:test-app:svelte\": \"cd packages/svelte/test-app && pnpm run lint\",\n    \"lint:test-app:vue\": \"cd packages/vue3/test-app && pnpm run lint\",\n    \"type-check:test-app\": \"pnpm -r --filter './packages/*/test-app' type-check\",\n    \"type-check:test-app:react\": \"cd packages/react/test-app && pnpm run type-check\",\n    \"type-check:test-app:svelte\": \"cd packages/svelte/test-app && pnpm run type-check\",\n    \"type-check:test-app:vue\": \"cd packages/vue3/test-app && pnpm run type-check\",\n    \"test:react\": \"PACKAGE=react node playwright.js\",\n    \"test:svelte\": \"PACKAGE=svelte node playwright.js\",\n    \"test:vue\": \"PACKAGE=vue3 node playwright.js\",\n    \"test:ssr:react\": \"PACKAGE=react SSR=true npx playwright test\",\n    \"test:ssr:svelte\": \"PACKAGE=svelte SSR=true npx playwright test\",\n    \"test:ssr:vue\": \"PACKAGE=vue3 SSR=true npx playwright test\",\n    \"playground:react\": \"cd playgrounds/react && ./init.sh && composer run dev\",\n    \"playground:svelte4\": \"cd playgrounds/svelte4 && ./init.sh && composer run dev\",\n    \"playground:svelte5\": \"cd playgrounds/svelte5 && ./init.sh && composer run dev\",\n    \"playground:vue\": \"cd playgrounds/vue3 && ./init.sh && composer run dev\",\n    \"format\": \"prettier --write .\"\n  },\n  \"dependencies\": {\n    \"@playwright/test\": \"^1.58.2\",\n    \"prettier\": \"^3.8.1\",\n    \"prettier-plugin-organize-imports\": \"^4.3.0\",\n    \"prettier-plugin-svelte\": \"^3.5.0\",\n    \"prettier-plugin-tailwindcss\": \"^0.7.2\"\n  },\n  \"optionalDependencies\": {\n    \"@rollup/rollup-linux-x64-gnu\": \"^4.59.0\"\n  },\n  \"pnpm\": {\n    \"overrides\": {\n      \"cookie\": \">=0.7.0\",\n      \"esbuild\": \">=0.25.0\"\n    }\n  }\n}\n"
  },
  {
    "path": "packages/core/.gitignore",
    "content": "dist\ntypes\nnode_modules\npackage-lock.json\nyarn.lock\n"
  },
  {
    "path": "packages/core/LICENSE",
    "content": "MIT License\n\nCopyright (c) Jonathan Reinink <jonathan@reinink.ca>\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": "packages/core/build.js",
    "content": "#!/usr/bin/env node\nimport esbuild from 'esbuild'\nimport { nodeExternalsPlugin } from 'esbuild-node-externals'\n\nconst watch = process.argv.slice(1).includes('--watch')\nconst withDeps = process.argv.slice(1).includes('--with-deps')\n\nconst config = {\n  bundle: true,\n  minify: false,\n  sourcemap: withDeps ? false : true,\n  target: 'es2020',\n  plugins: [\n    ...(withDeps ? [] : [nodeExternalsPlugin()]),\n    {\n      name: 'inertia',\n      setup(build) {\n        let count = 0\n        build.onEnd((result) => {\n          if (count++ !== 0) {\n            console.log(`Rebuilding ${build.initialOptions.entryPoints} (${build.initialOptions.format})…`)\n          }\n        })\n      },\n    },\n  ],\n}\n\nconst builds = [\n  { entryPoints: ['src/index.ts'], format: 'esm', outfile: 'dist/index.esm.js', platform: 'browser' },\n  { entryPoints: ['src/index.ts'], format: 'cjs', outfile: 'dist/index.js', platform: 'browser' },\n  { entryPoints: ['src/server.ts'], format: 'esm', outfile: 'dist/server.esm.js', platform: 'node' },\n  { entryPoints: ['src/server.ts'], format: 'cjs', outfile: 'dist/server.js', platform: 'node' },\n]\n\nbuilds.forEach(async (build) => {\n  const context = await esbuild.context({ ...config, ...build })\n\n  if (watch) {\n    console.log(`Watching ${build.entryPoints} (${build.format})…`)\n    await context.watch()\n  } else {\n    await context.rebuild()\n    context.dispose()\n    console.log(`Built ${build.entryPoints} (${build.format}) ${withDeps ? '(with-deps)' : ''}…`)\n  }\n})\n"
  },
  {
    "path": "packages/core/package.json",
    "content": "{\n  \"name\": \"@inertiajs/core\",\n  \"version\": \"2.3.18\",\n  \"license\": \"MIT\",\n  \"description\": \"A framework for creating server-driven single page apps.\",\n  \"contributors\": [\n    \"Jonathan Reinink <jonathan@reinink.ca>\",\n    \"Claudio Dekker <claudio@ubient.net>\",\n    \"Sebastian De Deyne <sebastiandedeyne@gmail.com>\"\n  ],\n  \"homepage\": \"https://inertiajs.com/\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/inertiajs/inertia.git\",\n    \"directory\": \"packages/inertia\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/inertiajs/inertia/issues\"\n  },\n  \"files\": [\n    \"dist\",\n    \"types\"\n  ],\n  \"type\": \"module\",\n  \"main\": \"dist/index.js\",\n  \"types\": \"types/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./types/index.d.ts\",\n      \"import\": \"./dist/index.esm.js\",\n      \"require\": \"./dist/index.js\"\n    },\n    \"./server\": {\n      \"types\": \"./types/server.d.ts\",\n      \"import\": \"./dist/server.esm.js\",\n      \"require\": \"./dist/server.js\"\n    }\n  },\n  \"typesVersions\": {\n    \"*\": {\n      \"server\": [\n        \"types/server.d.ts\"\n      ]\n    }\n  },\n  \"scripts\": {\n    \"build\": \"pnpm clean && ./build.js && tsc\",\n    \"build:with-deps\": \"./build.js --with-deps\",\n    \"clean\": \"rm -rf types && rm -rf dist\",\n    \"dev\": \"pnpx concurrently -c \\\"#ffcf00,#3178c6\\\" \\\"pnpm dev:build\\\" \\\"pnpm dev:types\\\" --names build,types\",\n    \"dev:build\": \"./build.js --watch\",\n    \"dev:types\": \"tsc --watch --preserveWatchOutput\",\n    \"es2020-check\": \"pnpm build:with-deps && es-check es2020 \\\"dist/index.esm.js\\\" --checkFeatures --module --noCache --verbose\"\n  },\n  \"dependencies\": {\n    \"@types/lodash-es\": \"^4.17.12\",\n    \"axios\": \"^1.13.5\",\n    \"laravel-precognition\": \"^1.0.2\",\n    \"lodash-es\": \"^4.17.23\",\n    \"qs\": \"^6.15.0\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^18.19.130\",\n    \"@types/qs\": \"^6.14.0\",\n    \"es-check\": \"^9.6.1\",\n    \"esbuild\": \"^0.27.3\",\n    \"esbuild-node-externals\": \"^1.20.1\",\n    \"typescript\": \"^5.9.3\"\n  }\n}\n"
  },
  {
    "path": "packages/core/readme.md",
    "content": "# Inertia.js\n\nInertia.js lets you quickly build modern single-page React, Vue and Svelte apps using classic server-side routing and controllers.\n\nVisit [inertiajs.com](https://inertiajs.com/) to learn more.\n"
  },
  {
    "path": "packages/core/src/config.ts",
    "content": "import { get, has, set } from 'lodash-es'\nimport { InertiaAppConfig } from './types'\n\n// Generate all possible nested paths\ntype ConfigKeys<T> = T extends Function\n  ? never\n  : string extends keyof T\n    ? string\n    :\n        | Extract<keyof T, string>\n        | {\n            [Key in Extract<keyof T, string>]: T[Key] extends object ? `${Key}.${ConfigKeys<T[Key]> & string}` : never\n          }[Extract<keyof T, string>]\n\n// Extract the value type at a given path\ntype ConfigValue<T, K extends ConfigKeys<T>> = K extends `${infer P}.${infer Rest}`\n  ? P extends keyof T\n    ? Rest extends ConfigKeys<T[P]>\n      ? ConfigValue<T[P], Rest>\n      : never\n    : never\n  : K extends keyof T\n    ? T[K]\n    : never\n\n// Helper type for setting multiple config values with an object\ntype ConfigSetObject<T> = {\n  [K in ConfigKeys<T>]?: ConfigValue<T, K>\n}\n\ntype FirstLevelOptional<T> = {\n  [K in keyof T]?: T[K] extends object ? { [P in keyof T[K]]?: T[K][P] } : T[K]\n}\n\nexport class Config<TConfig extends {} = {}> {\n  protected config: FirstLevelOptional<TConfig> = {}\n  protected defaults: TConfig\n\n  public constructor(defaults: TConfig) {\n    this.defaults = defaults\n  }\n\n  public extend<TExtension extends {}>(defaults?: TExtension): Config<TConfig & TExtension> {\n    if (defaults) {\n      this.defaults = { ...this.defaults, ...defaults } as TConfig & TExtension\n    }\n\n    return this as unknown as Config<TConfig & TExtension>\n  }\n\n  public replace(newConfig: FirstLevelOptional<TConfig>): void {\n    this.config = newConfig\n  }\n\n  public get<K extends ConfigKeys<TConfig>>(key: K): ConfigValue<TConfig, K> {\n    return (has(this.config, key) ? get(this.config, key) : get(this.defaults, key)) as ConfigValue<TConfig, K>\n  }\n\n  public set<K extends ConfigKeys<TConfig>>(\n    keyOrValues: K | Partial<ConfigSetObject<TConfig>>,\n    value?: ConfigValue<TConfig, K>,\n  ): void {\n    if (typeof keyOrValues === 'string') {\n      set(this.config, keyOrValues, value)\n    } else {\n      Object.entries(keyOrValues).forEach(([key, val]) => {\n        set(this.config, key, val)\n      })\n    }\n  }\n}\n\nexport const config = new Config<InertiaAppConfig>({\n  form: {\n    recentlySuccessfulDuration: 2_000,\n    forceIndicesArrayFormatInFormData: true,\n    withAllErrors: false,\n  },\n  future: {\n    preserveEqualProps: false,\n    useDataInertiaHeadAttribute: false,\n    useDialogForErrorModal: false,\n    useScriptElementForInitialPage: false,\n  },\n  prefetch: {\n    cacheFor: 30_000,\n    hoverDelay: 75,\n  },\n})\n"
  },
  {
    "path": "packages/core/src/debounce.ts",
    "content": "export default function debounce<F extends (...params: any[]) => ReturnType<F>>(fn: F, delay: number): F {\n  let timeoutID: NodeJS.Timeout\n  return function (...args: unknown[]) {\n    clearTimeout(timeoutID)\n    timeoutID = setTimeout(() => fn.apply(this, args), delay)\n  } as F\n}\n"
  },
  {
    "path": "packages/core/src/debug.ts",
    "content": "export const stackTrace = (autolog = true) => {\n  try {\n    throw new Error()\n  } catch (e) {\n    const stack = (e as Error).stack\n\n    if (!autolog) {\n      return stack\n    }\n\n    console.log(stack)\n  }\n}\n"
  },
  {
    "path": "packages/core/src/dialog.ts",
    "content": "import modal from './modal'\n\nexport default {\n  show(html: Record<string, unknown> | string): void {\n    const { iframe, page } = modal.createIframeAndPage(html)\n\n    iframe.style.boxSizing = 'border-box'\n    iframe.style.display = 'block'\n\n    const dialog = document.createElement('dialog')\n    dialog.id = 'inertia-error-dialog'\n\n    // Style the dialog to mimic 50px padding\n    Object.assign(dialog.style, {\n      width: 'calc(100vw - 100px)',\n      height: 'calc(100vh - 100px)',\n      padding: '0',\n      margin: 'auto',\n      border: 'none',\n      backgroundColor: 'transparent',\n    })\n\n    // There's no way to directly style the backdrop of a dialog, so we need to use a style element...\n    const dialogStyleElement = document.createElement('style')\n    dialogStyleElement.textContent = `\n      dialog#inertia-error-dialog::backdrop {\n        background-color: rgba(0, 0, 0, 0.6);\n      }\n\n      dialog#inertia-error-dialog:focus {\n        outline: none;\n      }\n    `\n    document.head.appendChild(dialogStyleElement)\n\n    dialog.addEventListener('click', (event: MouseEvent) => {\n      if (event.target === dialog) {\n        dialog.close()\n      }\n    })\n\n    dialog.addEventListener('close', () => {\n      dialogStyleElement.remove()\n      dialog.remove()\n    })\n\n    dialog.appendChild(iframe)\n    document.body.prepend(dialog)\n    dialog.showModal()\n\n    // Focus the dialog so the 'Escape' key works immediately\n    dialog.focus()\n\n    if (!iframe.contentWindow) {\n      throw new Error('iframe not yet ready.')\n    }\n\n    iframe.contentWindow.document.open()\n    iframe.contentWindow.document.write(page.outerHTML)\n    iframe.contentWindow.document.close()\n  },\n}\n"
  },
  {
    "path": "packages/core/src/domUtils.ts",
    "content": "const elementInViewport = (el: HTMLElement) => {\n  if (el.offsetParent === null) {\n    // Element is not participating in layout (e.g., display: none)\n    return false\n  }\n\n  const rect = el.getBoundingClientRect()\n\n  // We check both vertically and horizontally for containers that scroll in either direction\n  const verticallyVisible = rect.top < window.innerHeight && rect.bottom >= 0\n  const horizontallyVisible = rect.left < window.innerWidth && rect.right >= 0\n\n  return verticallyVisible && horizontallyVisible\n}\n\nexport const getScrollableParent = (element: HTMLElement | null): HTMLElement | null => {\n  const allowsVerticalScroll = (el: HTMLElement): boolean => {\n    const computedStyle = window.getComputedStyle(el)\n\n    if (['scroll', 'overlay'].includes(computedStyle.overflowY)) {\n      return true\n    }\n\n    if (computedStyle.overflowY !== 'auto') {\n      return false\n    }\n\n    if (['visible', 'clip'].includes(computedStyle.overflowX)) {\n      return true\n    }\n\n    return hasDimensionConstraint(computedStyle.maxHeight, el.style.height) || isConstrainedByLayout(el, 'height')\n  }\n\n  const allowsHorizontalScroll = (el: HTMLElement): boolean => {\n    const computedStyle = window.getComputedStyle(el)\n\n    if (['scroll', 'overlay'].includes(computedStyle.overflowX)) {\n      return true\n    }\n\n    if (computedStyle.overflowX !== 'auto') {\n      return false\n    }\n\n    if (['visible', 'clip'].includes(computedStyle.overflowY)) {\n      return true\n    }\n\n    return hasDimensionConstraint(computedStyle.maxWidth, el.style.width) || isConstrainedByLayout(el, 'width')\n  }\n\n  const hasDimensionConstraint = (computedMaxDimension: string, inlineStyleDimension: string): boolean => {\n    if (computedMaxDimension && computedMaxDimension !== 'none' && computedMaxDimension !== '0px') {\n      return true\n    }\n\n    if (inlineStyleDimension && inlineStyleDimension !== 'auto' && inlineStyleDimension !== '0') {\n      return true\n    }\n\n    return false\n  }\n\n  // When overflow is set to 'auto' on one axis, the browser implicitly sets the other axis\n  // to 'auto' as well (CSS spec), which causes the 'visible'/'clip' checks above to fail.\n  // In flex/grid layouts, the element's size may be constrained by the parent layout rather\n  // than explicit dimension properties, so we check for that here.\n  const isConstrainedByLayout = (el: HTMLElement, dimension: 'height' | 'width'): boolean => {\n    const parent = el.parentElement\n\n    if (!parent) {\n      return false\n    }\n\n    const parentStyle = window.getComputedStyle(parent)\n\n    if (['flex', 'inline-flex'].includes(parentStyle.display)) {\n      const isColumnLayout = ['column', 'column-reverse'].includes(parentStyle.flexDirection)\n      return dimension === 'height' ? isColumnLayout : !isColumnLayout\n    }\n\n    return ['grid', 'inline-grid'].includes(parentStyle.display)\n  }\n\n  let parent = element?.parentElement\n\n  while (parent) {\n    const allowsScroll = allowsVerticalScroll(parent) || allowsHorizontalScroll(parent)\n\n    if (window.getComputedStyle(parent).display !== 'contents' && allowsScroll) {\n      return parent\n    }\n\n    parent = parent.parentElement\n  }\n\n  return null\n}\n\nexport const getElementsInViewportFromCollection = (\n  elements: HTMLElement[],\n  referenceElement?: HTMLElement,\n): HTMLElement[] => {\n  if (!referenceElement) {\n    return elements.filter((element) => elementInViewport(element))\n  }\n\n  const referenceIndex = elements.indexOf(referenceElement)\n  const upwardElements: HTMLElement[] = []\n  const downwardElements: HTMLElement[] = []\n\n  // Traverse upwards until an element is not visible\n  for (let i = referenceIndex; i >= 0; i--) {\n    const element = elements[i]\n\n    if (elementInViewport(element)) {\n      upwardElements.push(element)\n    } else {\n      break\n    }\n  }\n\n  // Traverse downwards until an element is not visible\n  for (let i = referenceIndex + 1; i < elements.length; i++) {\n    const element = elements[i]\n\n    if (elementInViewport(element)) {\n      downwardElements.push(element)\n    } else {\n      break\n    }\n  }\n\n  // Reverse upward elements to maintain DOM order, then append downward elements\n  return [...upwardElements.reverse(), ...downwardElements]\n}\n\nexport const requestAnimationFrame = (cb: () => void, times: number = 1): void => {\n  window.requestAnimationFrame(() => {\n    if (times > 1) {\n      requestAnimationFrame(cb, times - 1)\n    } else {\n      cb()\n    }\n  })\n}\n\nexport const getInitialPageFromDOM = <T>(id: string, useScriptElement: boolean = false): T | null => {\n  if (typeof window === 'undefined') {\n    return null\n  }\n\n  if (!useScriptElement) {\n    const el = document.getElementById(id)\n\n    if (el?.dataset.page) {\n      return JSON.parse(el.dataset.page)\n    }\n  }\n\n  const scriptEl = document.querySelector(`script[data-page=\"${id}\"][type=\"application/json\"]`)\n\n  if (scriptEl?.textContent) {\n    return JSON.parse(scriptEl.textContent)\n  }\n\n  return null\n}\n"
  },
  {
    "path": "packages/core/src/encryption.ts",
    "content": "import { SessionStorage } from './sessionStorage'\n\nexport const encryptHistory = async (data: any): Promise<ArrayBuffer> => {\n  if (typeof window === 'undefined') {\n    throw new Error('Unable to encrypt history')\n  }\n\n  const iv = getIv()\n  const storedKey = await getKeyFromSessionStorage()\n  const key = await getOrCreateKey(storedKey)\n\n  if (!key) {\n    throw new Error('Unable to encrypt history')\n  }\n\n  const encrypted = await encryptData(iv, key, data)\n\n  return encrypted\n}\n\nexport const historySessionStorageKeys = {\n  key: 'historyKey',\n  iv: 'historyIv',\n}\n\nexport const decryptHistory = async (data: any): Promise<any> => {\n  const iv = getIv()\n  const storedKey = await getKeyFromSessionStorage()\n\n  if (!storedKey) {\n    throw new Error('Unable to decrypt history')\n  }\n\n  return await decryptData(iv, storedKey, data)\n}\n\nconst encryptData = async (iv: BufferSource, key: CryptoKey, data: any) => {\n  if (typeof window === 'undefined') {\n    throw new Error('Unable to encrypt history')\n  }\n\n  if (typeof window.crypto.subtle === 'undefined') {\n    console.warn('Encryption is not supported in this environment. SSL is required.')\n\n    return Promise.resolve(data)\n  }\n\n  const textEncoder = new TextEncoder()\n  const str = JSON.stringify(data)\n  const encoded = new Uint8Array(str.length * 3)\n\n  const result = textEncoder.encodeInto(str, encoded)\n\n  return window.crypto.subtle.encrypt(\n    {\n      name: 'AES-GCM',\n      iv,\n    },\n    key,\n    encoded.subarray(0, result.written),\n  )\n}\n\nconst decryptData = async (iv: BufferSource, key: CryptoKey, data: any) => {\n  if (typeof window.crypto.subtle === 'undefined') {\n    console.warn('Decryption is not supported in this environment. SSL is required.')\n\n    return Promise.resolve(data)\n  }\n\n  const decrypted = await window.crypto.subtle.decrypt(\n    {\n      name: 'AES-GCM',\n      iv,\n    },\n    key,\n    data,\n  )\n\n  return JSON.parse(new TextDecoder().decode(decrypted))\n}\n\nconst getIv = (): BufferSource => {\n  const ivString = SessionStorage.get(historySessionStorageKeys.iv)\n\n  if (ivString) {\n    return new Uint8Array(ivString)\n  }\n\n  const iv = window.crypto.getRandomValues(new Uint8Array(12))\n\n  SessionStorage.set(historySessionStorageKeys.iv, Array.from(iv))\n\n  return iv\n}\n\nconst createKey = async () => {\n  if (typeof window.crypto.subtle === 'undefined') {\n    console.warn('Encryption is not supported in this environment. SSL is required.')\n\n    return Promise.resolve(null)\n  }\n\n  return window.crypto.subtle.generateKey(\n    {\n      name: 'AES-GCM',\n      length: 256,\n    },\n    true,\n    ['encrypt', 'decrypt'],\n  )\n}\n\nconst saveKey = async (key: CryptoKey) => {\n  if (typeof window.crypto.subtle === 'undefined') {\n    console.warn('Encryption is not supported in this environment. SSL is required.')\n\n    return Promise.resolve()\n  }\n\n  const keyData = await window.crypto.subtle.exportKey('raw', key)\n\n  SessionStorage.set(historySessionStorageKeys.key, Array.from(new Uint8Array(keyData)))\n}\n\nconst getOrCreateKey = async (key: CryptoKey | null) => {\n  if (key) {\n    return key\n  }\n\n  const newKey = await createKey()\n\n  if (!newKey) {\n    return null\n  }\n\n  await saveKey(newKey)\n\n  return newKey\n}\n\nconst getKeyFromSessionStorage = async (): Promise<CryptoKey | null> => {\n  const stringKey = SessionStorage.get(historySessionStorageKeys.key)\n\n  if (!stringKey) {\n    return null\n  }\n\n  const key = await window.crypto.subtle.importKey(\n    'raw',\n    new Uint8Array(stringKey),\n    {\n      name: 'AES-GCM',\n      length: 256,\n    },\n    true,\n    ['encrypt', 'decrypt'],\n  )\n\n  return key\n}\n"
  },
  {
    "path": "packages/core/src/eventHandler.ts",
    "content": "import debounce from './debounce'\nimport { fireNavigateEvent } from './events'\nimport { history } from './history'\nimport { router } from './index'\nimport { page as currentPage } from './page'\nimport { Scroll } from './scroll'\nimport { GlobalEvent, GlobalEventNames, GlobalEventResult, InternalEvent } from './types'\nimport { hrefToUrl } from './url'\n\nclass EventHandler {\n  protected internalListeners: {\n    event: InternalEvent\n    listener: (...args: any[]) => void\n  }[] = []\n\n  public init() {\n    if (typeof window !== 'undefined') {\n      window.addEventListener('popstate', this.handlePopstateEvent.bind(this))\n      window.addEventListener('pageshow', this.handlePageshowEvent.bind(this))\n      window.addEventListener('scroll', debounce(Scroll.onWindowScroll.bind(Scroll), 100), true)\n    }\n\n    if (typeof document !== 'undefined') {\n      document.addEventListener('scroll', debounce(Scroll.onScroll.bind(Scroll), 100), true)\n    }\n  }\n\n  public onGlobalEvent<TEventName extends GlobalEventNames>(\n    type: TEventName,\n    callback: (event: GlobalEvent<TEventName>) => GlobalEventResult<TEventName>,\n  ): VoidFunction {\n    const listener = ((event: GlobalEvent<TEventName>) => {\n      const response = callback(event)\n\n      if (event.cancelable && !event.defaultPrevented && response === false) {\n        event.preventDefault()\n      }\n    }) as EventListener\n\n    return this.registerListener(`inertia:${type}`, listener)\n  }\n\n  public on(event: InternalEvent, callback: (...args: any[]) => void): VoidFunction {\n    this.internalListeners.push({ event, listener: callback })\n\n    return () => {\n      this.internalListeners = this.internalListeners.filter((listener) => listener.listener !== callback)\n    }\n  }\n\n  public onMissingHistoryItem() {\n    // At this point, the user has probably cleared the state\n    // Mark the current page as cleared so that we don't try to write anything to it.\n    currentPage.clear()\n    // Fire an event so that that any listeners can handle this situation\n    this.fireInternalEvent('missingHistoryItem')\n  }\n\n  public fireInternalEvent(event: InternalEvent, ...args: any[]): void {\n    this.internalListeners\n      .filter((listener) => listener.event === event)\n      .forEach((listener) => listener.listener(...args))\n  }\n\n  protected registerListener(type: string, listener: EventListener): VoidFunction {\n    document.addEventListener(type, listener)\n\n    return () => document.removeEventListener(type, listener)\n  }\n\n  // bfcache restores pages without firing `popstate`, so we use `pageshow` to\n  // re-validate encrypted history entries after `clearHistory` removed the keys.\n  // https://web.dev/articles/bfcache\n  protected handlePageshowEvent(event: PageTransitionEvent): void {\n    if (event.persisted) {\n      history.decrypt().catch(() => this.onMissingHistoryItem())\n    }\n  }\n\n  protected handlePopstateEvent(event: PopStateEvent): void {\n    const state = event.state || null\n\n    if (state === null) {\n      const url = hrefToUrl(currentPage.get().url)\n      url.hash = window.location.hash\n\n      history.replaceState({ ...currentPage.getWithoutFlashData(), url: url.href })\n      Scroll.reset()\n\n      return\n    }\n\n    if (!history.isValidState(state)) {\n      return this.onMissingHistoryItem()\n    }\n\n    history\n      .decrypt(state.page)\n      .then((data) => {\n        if (currentPage.get().version !== data.version) {\n          this.onMissingHistoryItem()\n          return\n        }\n\n        // Cancel ongoing requests except prefetch requests\n        router.cancelAll({ prefetch: false })\n\n        currentPage.setQuietly(data, { preserveState: false }).then(() => {\n          Scroll.restore(history.getScrollRegions())\n          fireNavigateEvent(currentPage.get())\n\n          const pendingDeferred: Record<string, string[]> = {}\n          const pageProps = currentPage.get().props\n\n          for (const [group, props] of Object.entries(data.initialDeferredProps ?? data.deferredProps ?? {})) {\n            const missing = props.filter((prop) => pageProps[prop] === undefined)\n\n            if (missing.length > 0) {\n              pendingDeferred[group] = missing\n            }\n          }\n\n          if (Object.keys(pendingDeferred).length > 0) {\n            this.fireInternalEvent('loadDeferredProps', pendingDeferred)\n          }\n        })\n      })\n      .catch(() => {\n        this.onMissingHistoryItem()\n      })\n  }\n}\n\nexport const eventHandler = new EventHandler()\n"
  },
  {
    "path": "packages/core/src/events.ts",
    "content": "import { GlobalEventDetails, GlobalEventNames, GlobalEventTrigger } from './types'\n\nfunction fireEvent<TEventName extends GlobalEventNames>(\n  name: TEventName,\n  options: CustomEventInit<GlobalEventDetails<TEventName>>,\n): boolean {\n  return document.dispatchEvent(new CustomEvent(`inertia:${name}`, options))\n}\n\nexport const fireBeforeEvent: GlobalEventTrigger<'before'> = (visit) => {\n  return fireEvent('before', { cancelable: true, detail: { visit } })\n}\n\nexport const fireErrorEvent: GlobalEventTrigger<'error'> = (errors) => {\n  return fireEvent('error', { detail: { errors } })\n}\n\nexport const fireExceptionEvent: GlobalEventTrigger<'exception'> = (exception) => {\n  return fireEvent('exception', { cancelable: true, detail: { exception } })\n}\n\nexport const fireFinishEvent: GlobalEventTrigger<'finish'> = (visit) => {\n  return fireEvent('finish', { detail: { visit } })\n}\n\nexport const fireInvalidEvent: GlobalEventTrigger<'invalid'> = (response) => {\n  return fireEvent('invalid', { cancelable: true, detail: { response } })\n}\n\nexport const fireBeforeUpdateEvent: GlobalEventTrigger<'beforeUpdate'> = (page) => {\n  return fireEvent('beforeUpdate', { detail: { page } })\n}\n\nexport const fireNavigateEvent: GlobalEventTrigger<'navigate'> = (page) => {\n  return fireEvent('navigate', { detail: { page } })\n}\n\nexport const fireProgressEvent: GlobalEventTrigger<'progress'> = (progress) => {\n  return fireEvent('progress', { detail: { progress } })\n}\n\nexport const fireStartEvent: GlobalEventTrigger<'start'> = (visit) => {\n  return fireEvent('start', { detail: { visit } })\n}\n\nexport const fireSuccessEvent: GlobalEventTrigger<'success'> = (page) => {\n  return fireEvent('success', { detail: { page } })\n}\n\nexport const firePrefetchedEvent: GlobalEventTrigger<'prefetched'> = (response, visit) => {\n  return fireEvent('prefetched', { detail: { fetchedAt: Date.now(), response: response.data, visit } })\n}\n\nexport const firePrefetchingEvent: GlobalEventTrigger<'prefetching'> = (visit) => {\n  return fireEvent('prefetching', { detail: { visit } })\n}\n\nexport const fireFlashEvent: GlobalEventTrigger<'flash'> = (flash) => {\n  return fireEvent('flash', { detail: { flash } })\n}\n"
  },
  {
    "path": "packages/core/src/files.ts",
    "content": "import { FormDataConvertible, RequestPayload } from './types'\n\nexport const isFile = (value: unknown): boolean =>\n  (typeof File !== 'undefined' && value instanceof File) ||\n  value instanceof Blob ||\n  (typeof FileList !== 'undefined' && value instanceof FileList && value.length > 0)\n\nexport function hasFiles(data: RequestPayload | FormDataConvertible): boolean {\n  return (\n    isFile(data) ||\n    (data instanceof FormData && Array.from(data.values()).some((value) => hasFiles(value))) ||\n    (typeof data === 'object' && data !== null && Object.values(data).some((value) => hasFiles(value)))\n  )\n}\n"
  },
  {
    "path": "packages/core/src/formData.ts",
    "content": "import type { FormDataConvertible, QueryStringArrayFormatOption } from './types'\n\nexport const isFormData = (value: any): value is FormData => value instanceof FormData\n\nexport function objectToFormData(\n  source: Record<string, FormDataConvertible>,\n  form: FormData = new FormData(),\n  parentKey: string | null = null,\n  queryStringArrayFormat: QueryStringArrayFormatOption = 'brackets',\n): FormData {\n  source = source || {}\n\n  for (const key in source) {\n    if (Object.prototype.hasOwnProperty.call(source, key)) {\n      append(form, composeKey(parentKey, key, 'indices'), source[key], queryStringArrayFormat)\n    }\n  }\n\n  return form\n}\n\nfunction composeKey(parent: string | null, key: string, format: QueryStringArrayFormatOption): string {\n  if (!parent) {\n    return key\n  }\n\n  return format === 'brackets' ? `${parent}[]` : `${parent}[${key}]`\n}\n\nfunction append(form: FormData, key: string, value: FormDataConvertible, format: QueryStringArrayFormatOption): void {\n  if (Array.isArray(value)) {\n    return Array.from(value.keys()).forEach((index) =>\n      append(form, composeKey(key, index.toString(), format), value[index], format),\n    )\n  } else if (value instanceof Date) {\n    return form.append(key, value.toISOString())\n  } else if (value instanceof File) {\n    return form.append(key, value, value.name)\n  } else if (value instanceof Blob) {\n    return form.append(key, value)\n  } else if (typeof value === 'boolean') {\n    return form.append(key, value ? '1' : '0')\n  } else if (typeof value === 'string') {\n    return form.append(key, value)\n  } else if (typeof value === 'number') {\n    return form.append(key, `${value}`)\n  } else if (value === null || value === undefined) {\n    return form.append(key, '')\n  }\n\n  objectToFormData(value, form, key, format)\n}\n"
  },
  {
    "path": "packages/core/src/formObject.ts",
    "content": "import { get, set } from 'lodash-es'\nimport { isFile } from './files'\nimport { FormDataConvertible } from './types'\n\n/**\n * Transform dotted notation to bracket notation.\n *\n * Examples:\n *   user.name => user[name]\n *   user.profile.city => user[profile][city]\n *   user.skills[] => user[skills][]\n *   users.company[address].street => users[company][address][street]\n *   config\\.app\\.name => config.app.name (escaped, literal)\n */\nfunction undotKey(key: string): string {\n  if (!key.includes('.')) {\n    return key\n  }\n\n  const transformSegment = (segment: string): string => {\n    if (segment.startsWith('[') && segment.endsWith(']')) {\n      return segment // Already in bracket notation - leave untouched\n    }\n\n    // Convert dotted segment to bracket notation: \"user.name\" → \"user[name]\"\n    return segment.split('.').reduce((result, part, index) => (index === 0 ? part : `${result}[${part}]`))\n  }\n\n  return key\n    .replace(/\\\\\\./g, '__ESCAPED_DOT__') // Temporarily replace escaped dots (\\.) to protect them from transformation\n    .split(/(\\[[^\\]]*\\])/) // Split on bracket notation while preserving the brackets in the result array\n    .filter(Boolean) // Remove empty strings from the split operation\n    .map(transformSegment) // Transform each segment: dotted parts become bracketed, existing brackets stay as-is\n    .join('') // Reassemble all segments back into a single string\n    .replace(/__ESCAPED_DOT__/g, '.') // Restore the escaped dots as literal dots in the final result\n}\n\n/**\n * Parse a key into an array of path segments.\n *\n * Examples:\n * - \"user[name]\" => [\"user\", \"name\"]\n * - \"tags[]\" => [\"tags\", \"\"]\n * - \"items[0][name]\" => [\"items\", 0, \"name\"]\n */\nfunction parseKey(key: string): (string | number | '')[] {\n  const path: (string | number | '')[] = []\n  const pattern = /([^\\[\\]]+)|\\[(\\d*)\\]/g\n  let match: RegExpExecArray | null\n\n  while ((match = pattern.exec(key)) !== null) {\n    if (match[1] !== undefined) {\n      path.push(match[1])\n    } else if (match[2] !== undefined) {\n      path.push(match[2] === '' ? '' : Number(match[2]))\n    }\n  }\n\n  return path\n}\n\n/**\n * Set value in nested object, always creating objects (never arrays).\n * This ensures we can analyze the final structure before deciding what should be arrays.\n */\nfunction setNestedObject(obj: Record<string, any>, path: string[], value: any): void {\n  let current = obj\n\n  for (let i = 0; i < path.length - 1; i++) {\n    if (!(path[i] in current)) {\n      current[path[i]] = {}\n    }\n\n    current = current[path[i]]\n  }\n\n  current[path[path.length - 1]] = value\n}\n\n/**\n * Check if an object has sequential numeric keys (0, 1, 2, ...).\n */\nfunction objectHasSequentialNumericKeys(value: any): boolean {\n  const keys = Object.keys(value)\n  const numericKeys = keys\n    .filter((k) => /^\\d+$/.test(k))\n    .map(Number)\n    .sort((a, b) => a - b)\n\n  return (\n    keys.length === numericKeys.length &&\n    numericKeys.length > 0 &&\n    numericKeys[0] === 0 &&\n    numericKeys.every((n, i) => n === i)\n  )\n}\n\n/**\n * Convert objects with sequential numeric keys (0, 1, 2, ...) to arrays.\n */\nfunction convertSequentialObjectsToArrays(value: any): any {\n  if (Array.isArray(value)) {\n    return value.map(convertSequentialObjectsToArrays)\n  }\n\n  if (typeof value !== 'object' || value === null || isFile(value)) {\n    return value\n  }\n\n  if (objectHasSequentialNumericKeys(value)) {\n    const result = []\n\n    for (let i = 0; i < Object.keys(value).length; i++) {\n      result[i] = convertSequentialObjectsToArrays(value[i])\n    }\n\n    return result\n  }\n\n  // Keep as object, recursively process values\n  const result: Record<string, any> = {}\n\n  for (const key in value) {\n    result[key] = convertSequentialObjectsToArrays(value[key])\n  }\n\n  return result\n}\n\n/**\n * Convert a FormData instance into an object structure.\n */\nexport function formDataToObject(source: FormData): Record<string, FormDataConvertible> {\n  const form: Record<string, any> = {}\n\n  // formData.entries() returns an iterator where the first element is the key and the second element\n  // is the value. Examples of the keys are \"user[name]\", \"tags[]\", \"items[0][name]\", \"user.name\", etc.\n  // We should construct a new (nested) object based on these keys.\n  for (const [key, value] of source.entries()) {\n    if (value instanceof File && value.size === 0 && value.name === '') {\n      // Check if the given value is an empty file. We want to filter\n      // those out as they prevent us from comparing objects with\n      // each other, which we do to set the isDirty prop.\n      continue\n    }\n\n    const path = parseKey(undotKey(key))\n\n    // If the key ends with an empty string (''), treat it as an array push (e.g., \"tags[]\")\n    if (path[path.length - 1] === '') {\n      const arrayPath = path.slice(0, -1)\n      const existing = get(form, arrayPath)\n\n      if (Array.isArray(existing)) {\n        existing.push(value)\n      } else if (existing && typeof existing === 'object' && !isFile(existing)) {\n        // If existing is an object with numeric keys, convert to array (treating indices as relative)\n        const numericKeys = Object.keys(existing)\n          .filter((k) => /^\\d+$/.test(k))\n          .map(Number)\n          .sort((a, b) => a - b)\n\n        set(form, arrayPath, numericKeys.length > 0 ? [...numericKeys.map((k) => existing[k]), value] : [value])\n      } else {\n        set(form, arrayPath, [value])\n      }\n\n      continue\n    }\n\n    // Always build nested objects first, then convert sequential numeric keys to arrays.\n    // This prevents the creation of sparse arrays when mixing numeric and string keys.\n    setNestedObject(form, path.map(String), value)\n  }\n\n  // Convert objects with sequential numeric keys (0, 1, 2, ...) to arrays\n  return convertSequentialObjectsToArrays(form)\n}\n"
  },
  {
    "path": "packages/core/src/head.ts",
    "content": "import { config, HeadManager, HeadManagerOnUpdateCallback, HeadManagerTitleCallback } from '.'\nimport debounce from './debounce'\n\nconst Renderer = {\n  preferredAttribute(): 'data-inertia' | 'inertia' {\n    return config.get('future.useDataInertiaHeadAttribute') ? 'data-inertia' : 'inertia'\n  },\n\n  buildDOMElement(tag: string): ChildNode {\n    const template = document.createElement('template')\n    template.innerHTML = tag\n    const node = template.content.firstChild as Element\n\n    if (!tag.startsWith('<script ')) {\n      return node\n    }\n\n    const script = document.createElement('script')\n    script.innerHTML = node.innerHTML\n    node.getAttributeNames().forEach((name) => {\n      script.setAttribute(name, node.getAttribute(name) || '')\n    })\n\n    return script\n  },\n\n  isInertiaManagedElement(element: Element): boolean {\n    return element.nodeType === Node.ELEMENT_NODE && element.getAttribute(this.preferredAttribute()) !== null\n  },\n\n  findMatchingElementIndex(element: Element, elements: Array<Element>): number {\n    const attribute = this.preferredAttribute()\n    const key = element.getAttribute(attribute)\n    if (key !== null) {\n      return elements.findIndex((element) => element.getAttribute(attribute) === key)\n    }\n\n    return -1\n  },\n\n  update: debounce(function (elements: Array<string>) {\n    const sourceElements = elements.map((element) => this.buildDOMElement(element))\n    const targetElements = Array.from(document.head.childNodes).filter((element) =>\n      this.isInertiaManagedElement(element as Element),\n    )\n\n    targetElements.forEach((targetElement) => {\n      const index = this.findMatchingElementIndex(targetElement as Element, sourceElements)\n      if (index === -1) {\n        targetElement?.parentNode?.removeChild(targetElement)\n        return\n      }\n\n      const sourceElement = sourceElements.splice(index, 1)[0]\n      if (sourceElement && !targetElement.isEqualNode(sourceElement)) {\n        targetElement?.parentNode?.replaceChild(sourceElement, targetElement)\n      }\n    })\n\n    sourceElements.forEach((element) => document.head.appendChild(element))\n  }, 1),\n}\n\nexport default function createHeadManager(\n  isServer: boolean,\n  titleCallback: HeadManagerTitleCallback,\n  onUpdate: HeadManagerOnUpdateCallback,\n): HeadManager {\n  const states: Record<string, Array<string>> = {}\n  let lastProviderId = 0\n\n  function connect(): string {\n    const id = (lastProviderId += 1)\n    states[id] = []\n    return id.toString()\n  }\n\n  function disconnect(id: string): void {\n    if (id === null || Object.keys(states).indexOf(id) === -1) {\n      return\n    }\n\n    delete states[id]\n    commit()\n  }\n\n  function reconnect(id: string): void {\n    if (Object.keys(states).indexOf(id) === -1) {\n      states[id] = []\n    }\n  }\n\n  function update(id: string, elements: Array<string> = []): void {\n    if (id !== null && Object.keys(states).indexOf(id) > -1) {\n      states[id] = elements\n    }\n\n    commit()\n  }\n\n  function collect(): Array<string> {\n    const title = titleCallback('')\n    const attribute = Renderer.preferredAttribute()\n\n    const defaults: Record<string, string> = {\n      ...(title ? { title: `<title ${attribute}=\"\">${title}</title>` } : {}),\n    }\n\n    const elements = Object.values(states)\n      .reduce((carry, elements) => carry.concat(elements), [])\n      .reduce((carry, element) => {\n        if (element.indexOf('<') === -1) {\n          return carry\n        }\n\n        if (element.indexOf('<title ') === 0) {\n          const title = element.match(/(<title [^>]+>)(.*?)(<\\/title>)/)\n          carry.title = title ? `${title[1]}${titleCallback(title[2])}${title[3]}` : element\n          return carry\n        }\n\n        const match = element.match(attribute === 'inertia' ? / inertia=\"[^\"]+\"/ : / data-inertia=\"[^\"]+\"/)\n        if (match) {\n          carry[match[0]] = element\n        } else {\n          carry[Object.keys(carry).length] = element\n        }\n\n        return carry\n      }, defaults)\n\n    return Object.values(elements)\n  }\n\n  function commit(): void {\n    isServer ? onUpdate(collect()) : Renderer.update(collect())\n  }\n\n  // By committing during initialization, we can guarantee that the default\n  // tags are set, as well as that they exist during SSR itself.\n  commit()\n\n  return {\n    forceUpdate: commit,\n    createProvider: function () {\n      const id = connect()\n\n      return {\n        preferredAttribute: Renderer.preferredAttribute,\n        reconnect: () => reconnect(id),\n        update: (elements) => update(id, elements),\n        disconnect: () => disconnect(id),\n      }\n    },\n  }\n}\n"
  },
  {
    "path": "packages/core/src/history.ts",
    "content": "import { cloneDeep, isEqual } from 'lodash-es'\nimport { decryptHistory, encryptHistory, historySessionStorageKeys } from './encryption'\nimport { eventHandler } from './eventHandler'\nimport { page as currentPage } from './page'\nimport Queue from './queue'\nimport { SessionStorage } from './sessionStorage'\nimport { Page, ScrollRegion } from './types'\n\nconst isServer = typeof window === 'undefined'\nconst queue = new Queue<Promise<void>>()\nconst isChromeIOS = !isServer && /CriOS/.test(window.navigator.userAgent)\n\nclass History {\n  public rememberedState = 'rememberedState' as const\n  public scrollRegions = 'scrollRegions' as const\n  public preserveUrl = false\n  protected current: Partial<Page> = {}\n  // We need initialState for `restore`\n  protected initialState: Partial<Page> | null = null\n\n  public remember(data: unknown, key: string): void {\n    this.replaceState({\n      ...currentPage.getWithoutFlashData(),\n      rememberedState: {\n        ...(currentPage.get()?.rememberedState ?? {}),\n        [key]: data,\n      },\n    })\n  }\n\n  public restore(key: string): unknown {\n    if (!isServer) {\n      return this.current[this.rememberedState]?.[key] !== undefined\n        ? this.current[this.rememberedState]?.[key]\n        : this.initialState?.[this.rememberedState]?.[key]\n    }\n  }\n\n  public pushState(page: Page, cb: (() => void) | null = null): void {\n    if (isServer) {\n      return\n    }\n\n    if (this.preserveUrl) {\n      cb && cb()\n      return\n    }\n\n    this.current = page\n\n    queue.add(() => {\n      return this.getPageData(page).then((data) => {\n        // Defer history.pushState to the next event loop tick to prevent timing conflicts.\n        // Ensure any previous history.replaceState completes before pushState is executed.\n        const doPush = () => this.doPushState({ page: data }, page.url).then(() => cb?.())\n\n        if (isChromeIOS) {\n          return new Promise((resolve) => {\n            setTimeout(() => doPush().then(resolve))\n          })\n        }\n\n        return doPush()\n      })\n    })\n  }\n\n  protected clonePageProps(page: Page): Page {\n    try {\n      structuredClone(page.props)\n      return page\n    } catch {\n      // Props contain non-serializable data (e.g., Proxies, functions).\n      // Clone them to ensure they can be safely stored in browser history.\n      return {\n        ...page,\n        props: cloneDeep(page.props),\n      }\n    }\n  }\n\n  protected getPageData(page: Page): Promise<Page | ArrayBuffer> {\n    const pageWithClonedProps = this.clonePageProps(page)\n\n    return new Promise((resolve) => {\n      return page.encryptHistory ? encryptHistory(pageWithClonedProps).then(resolve) : resolve(pageWithClonedProps)\n    })\n  }\n\n  public processQueue(): Promise<void> {\n    return queue.process()\n  }\n\n  public decrypt(page: Page | null = null): Promise<Page> {\n    if (isServer) {\n      return Promise.resolve(page ?? currentPage.get())\n    }\n\n    const pageData = page ?? window.history.state?.page\n\n    return this.decryptPageData(pageData).then((data) => {\n      if (!data) {\n        throw new Error('Unable to decrypt history')\n      }\n\n      if (this.initialState === null) {\n        this.initialState = data ?? undefined\n      } else {\n        this.current = data ?? {}\n      }\n\n      return data\n    })\n  }\n\n  protected decryptPageData(pageData: ArrayBuffer | Page | null): Promise<Page | null> {\n    return pageData instanceof ArrayBuffer ? decryptHistory(pageData) : Promise.resolve(pageData)\n  }\n\n  public saveScrollPositions(scrollRegions: ScrollRegion[]): void {\n    queue.add(() => {\n      return Promise.resolve().then(() => {\n        if (!window.history.state?.page) {\n          return\n        }\n\n        if (isEqual(this.getScrollRegions(), scrollRegions)) {\n          return\n        }\n\n        return this.doReplaceState({\n          page: window.history.state.page,\n          scrollRegions,\n        })\n      })\n    })\n  }\n\n  public saveDocumentScrollPosition(scrollRegion: ScrollRegion): void {\n    queue.add(() => {\n      return Promise.resolve().then(() => {\n        if (!window.history.state?.page) {\n          return\n        }\n\n        if (isEqual(this.getDocumentScrollPosition(), scrollRegion)) {\n          return\n        }\n\n        return this.doReplaceState({\n          page: window.history.state.page,\n          documentScrollPosition: scrollRegion,\n        })\n      })\n    })\n  }\n\n  public getScrollRegions(): ScrollRegion[] {\n    return window.history.state?.scrollRegions || []\n  }\n\n  public getDocumentScrollPosition(): ScrollRegion {\n    return window.history.state?.documentScrollPosition || { top: 0, left: 0 }\n  }\n\n  public replaceState(page: Page, cb: (() => void) | null = null): void {\n    if (isEqual(this.current, page)) {\n      cb && cb()\n      return\n    }\n\n    // Exclude flash from the merge to prevent callers (like router.remember())\n    // from accidentally clearing flash data on the current page.\n    const { flash, ...pageWithoutFlash } = page\n    currentPage.merge(pageWithoutFlash)\n\n    if (isServer) {\n      return\n    }\n\n    if (this.preserveUrl) {\n      cb && cb()\n      return\n    }\n\n    this.current = page\n\n    queue.add(() => {\n      return this.getPageData(page).then((data) => {\n        // Defer history.replaceState to the next event loop tick to prevent timing conflicts.\n        // Ensure any previous history.pushState completes before replaceState is executed.\n        const doReplace = () => this.doReplaceState({ page: data }, page.url).then(() => cb?.())\n\n        if (isChromeIOS) {\n          return new Promise((resolve) => {\n            setTimeout(() => doReplace().then(resolve))\n          })\n        }\n\n        return doReplace()\n      })\n    })\n  }\n\n  protected isHistoryThrottleError(error: unknown): error is Error & { name: 'SecurityError' } {\n    return (\n      error instanceof Error &&\n      error.name === 'SecurityError' &&\n      (error.message.includes('history.pushState') || error.message.includes('history.replaceState'))\n    )\n  }\n\n  protected isQuotaExceededError(error: unknown): error is Error & { name: 'QuotaExceededError' } {\n    return error instanceof Error && error.name === 'QuotaExceededError'\n  }\n\n  protected withThrottleProtection<T = void>(cb: () => T): Promise<T | undefined> {\n    return Promise.resolve().then(() => {\n      try {\n        return cb()\n      } catch (error) {\n        if (!this.isHistoryThrottleError(error)) {\n          throw error\n        }\n\n        console.error(error.message)\n      }\n    })\n  }\n\n  protected doReplaceState(\n    data: {\n      page: Page | ArrayBuffer\n      scrollRegions?: ScrollRegion[]\n      documentScrollPosition?: ScrollRegion\n    },\n    url?: string,\n  ): Promise<void> {\n    return this.withThrottleProtection(() => {\n      window.history.replaceState(\n        {\n          ...data,\n          scrollRegions: data.scrollRegions ?? window.history.state?.scrollRegions,\n          documentScrollPosition: data.documentScrollPosition ?? window.history.state?.documentScrollPosition,\n        },\n        '',\n        url,\n      )\n    })\n  }\n\n  protected doPushState(\n    data: {\n      page: Page | ArrayBuffer\n      scrollRegions?: ScrollRegion[]\n      documentScrollPosition?: ScrollRegion\n    },\n    url: string,\n  ): Promise<void> {\n    return this.withThrottleProtection(() => {\n      try {\n        window.history.pushState(data, '', url)\n      } catch (error) {\n        if (!this.isQuotaExceededError(error)) {\n          throw error\n        }\n\n        eventHandler.fireInternalEvent('historyQuotaExceeded', url)\n      }\n    })\n  }\n\n  public getState<T>(key: keyof Page, defaultValue?: T): any {\n    return this.current?.[key] ?? defaultValue\n  }\n\n  public deleteState(key: keyof Page) {\n    if (this.current[key] !== undefined) {\n      delete this.current[key]\n      this.replaceState(this.current as Page)\n    }\n  }\n\n  public clearInitialState(key: keyof Page) {\n    if (this.initialState && this.initialState[key] !== undefined) {\n      delete this.initialState[key]\n    }\n  }\n\n  public browserHasHistoryEntry(): boolean {\n    return !isServer && !!window.history.state?.page\n  }\n\n  public clear() {\n    SessionStorage.remove(historySessionStorageKeys.key)\n    SessionStorage.remove(historySessionStorageKeys.iv)\n  }\n\n  public setCurrent(page: Page): void {\n    this.current = page\n  }\n\n  public isValidState(state: any): boolean {\n    return !!state.page\n  }\n\n  public getAllState(): Page {\n    return this.current as Page\n  }\n}\n\nif (typeof window !== 'undefined' && window.history.scrollRestoration) {\n  window.history.scrollRestoration = 'manual'\n}\n\nexport const history = new History()\n"
  },
  {
    "path": "packages/core/src/index.ts",
    "content": "import { Config } from './config'\nimport { Router } from './router'\n\nexport { UseFormUtils } from './useFormUtils'\n\nexport { config } from './config'\nexport { getInitialPageFromDOM, getScrollableParent } from './domUtils'\nexport { objectToFormData } from './formData'\nexport { formDataToObject } from './formObject'\nexport { default as createHeadManager } from './head'\nexport { default as useInfiniteScroll } from './infiniteScroll'\nexport { shouldIntercept, shouldNavigate } from './navigationEvents'\nexport { hide as hideProgress, progress, reveal as revealProgress, default as setupProgress } from './progress'\nexport { FormComponentResetSymbol, resetFormFields } from './resetFormFields'\nexport * from './types'\nexport {\n  hrefToUrl,\n  isUrlMethodPair,\n  mergeDataIntoQueryString,\n  urlHasProtocol,\n  urlToString,\n  urlWithoutHash,\n} from './url'\nexport { type Config, type Router }\n\nexport const router = new Router()\n"
  },
  {
    "path": "packages/core/src/infiniteScroll/data.ts",
    "content": "import { router } from '../index'\nimport { page as currentPage } from '../page'\nimport { Page, PendingVisit, ReloadOptions, ScrollProp, UseInfiniteScrollDataManager } from '../types'\n\nconst MERGE_INTENT_HEADER = 'X-Inertia-Infinite-Scroll-Merge-Intent'\n\ntype Side = 'previous' | 'next'\ntype ScrollPropPageNames = keyof Pick<ScrollProp, 'previousPage' | 'nextPage'>\n\ntype InfiniteScrollState = {\n  previousPage: number | string | null\n  nextPage: number | string | null\n  lastLoadedPage: number | string | null\n  requestCount: number\n}\n\nexport const useInfiniteScrollData = (options: {\n  getPropName: () => string\n  onBeforeUpdate: () => void\n  onBeforePreviousRequest: () => void\n  onBeforeNextRequest: () => void\n  onCompletePreviousRequest: (loadedPage: string | number | null) => void\n  onCompleteNextRequest: (loadedPage: string | number | null) => void\n  onReset?: () => void\n}): UseInfiniteScrollDataManager => {\n  const getScrollPropFromCurrentPage = (): ScrollProp => {\n    const scrollProp = currentPage.get().scrollProps?.[options.getPropName()]\n\n    if (scrollProp) {\n      return scrollProp\n    }\n\n    throw new Error(`The page object does not contain a scroll prop named \"${options.getPropName()}\".`)\n  }\n\n  const state = {\n    component: null,\n    loading: false,\n    previousPage: null,\n    nextPage: null,\n    lastLoadedPage: null,\n    requestCount: 0,\n  } as {\n    component: string | null\n    loading: boolean\n  } & InfiniteScrollState\n\n  const resetState = () => {\n    const scrollProp = getScrollPropFromCurrentPage()\n\n    state.component = currentPage.get().component\n    state.loading = false\n    state.previousPage = scrollProp.previousPage\n    state.nextPage = scrollProp.nextPage\n    state.lastLoadedPage = scrollProp.currentPage\n    state.requestCount = 0\n  }\n\n  const getRememberKey = () => `inertia:infinite-scroll-data:${options.getPropName()}`\n\n  if (typeof window !== 'undefined') {\n    resetState()\n\n    const rememberedState = router.restore(getRememberKey()) as InfiniteScrollState | undefined\n\n    if (\n      rememberedState &&\n      typeof rememberedState === 'object' &&\n      rememberedState.lastLoadedPage === getScrollPropFromCurrentPage().currentPage\n    ) {\n      // Restore remembered state only when it's consistent with the current scroll prop,\n      // which ensures back/forward navigation works while direct URL visits reset properly.\n      state.previousPage = rememberedState.previousPage\n      state.nextPage = rememberedState.nextPage\n      state.lastLoadedPage = rememberedState.lastLoadedPage\n      state.requestCount = rememberedState.requestCount || 0\n    }\n  }\n\n  const removeEventListener = router.on('success', (event) => {\n    if (state.component === event.detail.page.component && getScrollPropFromCurrentPage().reset) {\n      resetState()\n      options.onReset?.()\n    }\n  })\n\n  const getScrollPropKeyForSide = (side: Side): ScrollPropPageNames => {\n    return side === 'next' ? 'nextPage' : 'previousPage'\n  }\n\n  const findPageToLoad = (side: Side) => {\n    const pagePropName = getScrollPropKeyForSide(side)\n\n    return state[pagePropName]\n  }\n\n  const syncStateOnSuccess = (side: Side) => {\n    const scrollProp = getScrollPropFromCurrentPage()\n    const paginationProp = getScrollPropKeyForSide(side)\n\n    state.lastLoadedPage = scrollProp.currentPage\n    state[paginationProp] = scrollProp[paginationProp]\n\n    state.requestCount += 1\n\n    // We save the state in the browser history so it can be restored\n    // if the user navigates away and then back to the page...\n    router.remember(\n      {\n        previousPage: state.previousPage,\n        nextPage: state.nextPage,\n        lastLoadedPage: state.lastLoadedPage,\n        requestCount: state.requestCount,\n      } as InfiniteScrollState,\n      getRememberKey(),\n    )\n  }\n\n  const getPageName = () => getScrollPropFromCurrentPage().pageName\n  const getRequestCount = () => state.requestCount\n\n  const fetchPage = (side: Side, reloadOptions: ReloadOptions = {}): void => {\n    const page = findPageToLoad(side)\n\n    if (state.loading || page === null) {\n      return\n    }\n\n    state.loading = true\n\n    router.reload({\n      ...reloadOptions,\n      data: { [getPageName()]: page },\n      only: [options.getPropName()],\n      preserveUrl: true, // we handle URL updates manually via useInfiniteScrollQueryString()\n      headers: {\n        [MERGE_INTENT_HEADER]: side === 'previous' ? 'prepend' : 'append',\n        ...reloadOptions.headers,\n      },\n      onBefore: (visit: PendingVisit) => {\n        side === 'next' ? options.onBeforeNextRequest() : options.onBeforePreviousRequest()\n        reloadOptions.onBefore?.(visit)\n      },\n      onBeforeUpdate: (page: Page) => {\n        options.onBeforeUpdate()\n        reloadOptions.onBeforeUpdate?.(page)\n      },\n      onSuccess: (page: Page) => {\n        syncStateOnSuccess(side)\n        reloadOptions.onSuccess?.(page)\n      },\n      onFinish: (visit: any) => {\n        state.loading = false\n        side === 'next'\n          ? options.onCompleteNextRequest(state.lastLoadedPage)\n          : options.onCompletePreviousRequest(state.lastLoadedPage)\n        reloadOptions.onFinish?.(visit)\n      },\n    })\n  }\n\n  const getLastLoadedPage = () => state.lastLoadedPage\n  const hasPrevious = () => !!state.previousPage\n  const hasNext = () => !!state.nextPage\n  const fetchPrevious = (reloadOptions?: ReloadOptions): void => fetchPage('previous', reloadOptions)\n  const fetchNext = (reloadOptions?: ReloadOptions): void => fetchPage('next', reloadOptions)\n\n  return {\n    getLastLoadedPage,\n    getPageName,\n    getRequestCount,\n    hasPrevious,\n    hasNext,\n    fetchNext,\n    fetchPrevious,\n    removeEventListener,\n  }\n}\n"
  },
  {
    "path": "packages/core/src/infiniteScroll/elements.ts",
    "content": "import { router } from '..'\nimport debounce from '../debounce'\nimport { useIntersectionObservers } from '../intersectionObservers'\nimport { UseInfiniteScrollElementManager } from '../types'\n\nconst INFINITE_SCROLL_PAGE_KEY = 'infiniteScrollPage'\nconst INFINITE_SCROLL_IGNORE_KEY = 'infiniteScrollIgnore'\n\ntype ElementRange = {\n  from: number\n  to: number\n}\n\nexport const getPageFromElement = (element: HTMLElement): string | undefined =>\n  element.dataset[INFINITE_SCROLL_PAGE_KEY]\n\nexport const useInfiniteScrollElementManager = (options: {\n  shouldFetchNext: () => boolean\n  shouldFetchPrevious: () => boolean\n  getTriggerMargin: () => number\n  getStartElement: () => HTMLElement\n  getEndElement: () => HTMLElement\n  getItemsElement: () => HTMLElement\n  getScrollableParent: () => HTMLElement | null\n  onPreviousTriggered: () => void\n  onNextTriggered: () => void\n  onItemIntersected: (element: HTMLElement) => void\n  getPropName: () => string\n}): UseInfiniteScrollElementManager => {\n  const intersectionObservers = useIntersectionObservers()\n\n  let itemsObserver: IntersectionObserver\n  let startElementObserver: IntersectionObserver\n  let endElementObserver: IntersectionObserver\n  let itemsMutationObserver: MutationObserver\n  let triggersEnabled = false\n\n  const setupObservers = () => {\n    // Watch for manually added DOM elements (not from server responses)\n    // This mutation observer tracks when new elements are added to the slot,\n    // so we can distinguish between user-added content and server-loaded pages\n    itemsMutationObserver = new MutationObserver((mutations) => {\n      mutations.forEach((mutation) => {\n        mutation.addedNodes.forEach((node) => {\n          if (node.nodeType !== Node.ELEMENT_NODE) {\n            return\n          }\n\n          addedElements.add(node as HTMLElement)\n        })\n      })\n\n      rememberElementsDebounced()\n    })\n\n    itemsMutationObserver.observe(options.getItemsElement(), { childList: true })\n\n    // Track individual items entering/leaving viewport for URL synchronization\n    // When items become visible, we update the URL to reflect the current page\n    itemsObserver = intersectionObservers.new((entry: IntersectionObserverEntry) =>\n      options.onItemIntersected(entry.target as HTMLElement),\n    )\n\n    // Set up trigger zones at start/end that load more content when intersected. The rootMargin\n    // creates a buffer zone so loading starts before user reaches the edge. We should always\n    // have a root margin of at least 1px as our default elements have no height\n    const observerOptions: IntersectionObserverInit = {\n      root: options.getScrollableParent(),\n      rootMargin: `${Math.max(1, options.getTriggerMargin())}px`,\n    }\n\n    startElementObserver = intersectionObservers.new(options.onPreviousTriggered, observerOptions)\n    endElementObserver = intersectionObservers.new(options.onNextTriggered, observerOptions)\n  }\n\n  const enableTriggers = () => {\n    if (triggersEnabled) {\n      // Make sure we don't register multiple watchers\n      disableTriggers()\n    }\n\n    const startElement = options.getStartElement()\n    const endElement = options.getEndElement()\n\n    if (startElement && options.shouldFetchPrevious()) {\n      startElementObserver.observe(startElement)\n    }\n\n    if (endElement && options.shouldFetchNext()) {\n      endElementObserver.observe(endElement)\n    }\n\n    triggersEnabled = true\n  }\n\n  const disableTriggers = () => {\n    if (!triggersEnabled) {\n      return\n    }\n\n    startElementObserver.disconnect()\n    endElementObserver.disconnect()\n    triggersEnabled = false\n  }\n\n  const refreshTriggers = () => {\n    if (triggersEnabled) {\n      enableTriggers()\n    }\n  }\n\n  const flushAll = () => {\n    disableTriggers()\n    intersectionObservers.flushAll()\n    itemsMutationObserver?.disconnect()\n  }\n\n  const addedElements = new Set<HTMLElement>()\n\n  const elementIsUntagged = (element: HTMLElement): boolean =>\n    !(INFINITE_SCROLL_PAGE_KEY in element.dataset) && !(INFINITE_SCROLL_IGNORE_KEY in element.dataset)\n\n  const processManuallyAddedElements = () => {\n    // Tag manually added elements so they don't interfere with URL management\n    // These elements get marked as \"ignore\" since they weren't loaded from the server\n    Array.from(addedElements).forEach((element) => {\n      if (elementIsUntagged(element)) {\n        element.dataset[INFINITE_SCROLL_IGNORE_KEY] = 'true'\n      }\n\n      itemsObserver.observe(element)\n    })\n\n    addedElements.clear()\n  }\n\n  const findUntaggedElements = (containerElement: HTMLElement): HTMLElement[] => {\n    return Array.from(\n      containerElement.querySelectorAll(\n        `:scope > *:not([data-infinite-scroll-page]):not([data-infinite-scroll-ignore])`,\n      ),\n    )\n  }\n\n  let hasRestoredElements = false\n\n  const processServerLoadedElements = (loadedPage: string | number | null) => {\n    // On first run, try to restore the elements tags from browser history\n    if (!hasRestoredElements) {\n      hasRestoredElements = true\n\n      if (restoreElements()) {\n        return\n      }\n    }\n\n    // Tag new server-loaded elements with their page number for URL management\n    // This allows us to update the URL based on which page's content is most visible\n    findUntaggedElements(options.getItemsElement()).forEach((element) => {\n      if (elementIsUntagged(element)) {\n        element.dataset[INFINITE_SCROLL_PAGE_KEY] = loadedPage?.toString() || '1'\n      }\n\n      itemsObserver.observe(element)\n    })\n\n    rememberElements()\n  }\n\n  const getElementsRememberKey = () => `inertia:infinite-scroll-elements:${options.getPropName()}`\n\n  // Remember in browser history which elements belong to which page, so we can restore\n  // them on back/forward navigation and keep URL synchronization working correctly\n  const rememberElements = () => {\n    const pageElementRange: Record<string, ElementRange> = {}\n    const childNodes = options.getItemsElement().childNodes\n\n    for (let index = 0; index < childNodes.length; index++) {\n      const node = childNodes[index]\n\n      if (node.nodeType !== Node.ELEMENT_NODE) {\n        continue\n      }\n\n      const page = getPageFromElement(node as HTMLElement)\n\n      if (typeof page === 'undefined') {\n        continue\n      }\n\n      if (!(page in pageElementRange)) {\n        pageElementRange[page] = { from: index, to: index }\n      } else {\n        pageElementRange[page].to = index\n      }\n    }\n\n    router.remember(pageElementRange, getElementsRememberKey())\n  }\n\n  const rememberElementsDebounced = debounce(rememberElements, 250)\n\n  const restoreElements = (): boolean => {\n    const pageElementRange = router.restore(getElementsRememberKey()) as Record<string, ElementRange> | undefined\n\n    if (!pageElementRange || typeof pageElementRange !== 'object') {\n      return false\n    }\n\n    const childNodes = options.getItemsElement().childNodes\n\n    // Use for loop instead of forEach for better performance\n    for (let index = 0; index < childNodes.length; index++) {\n      const node = childNodes[index]\n\n      if (node.nodeType !== Node.ELEMENT_NODE) {\n        continue\n      }\n\n      const element = node as HTMLElement\n\n      // Find which page this element belongs to based on ranges\n      let elementPage: string | undefined\n\n      for (const [page, range] of Object.entries(pageElementRange)) {\n        if (index >= range.from && index <= range.to) {\n          elementPage = page\n          break\n        }\n      }\n\n      if (elementPage) {\n        element.dataset[INFINITE_SCROLL_PAGE_KEY] = elementPage\n      } else if (!elementIsUntagged(element)) {\n        continue\n      } else {\n        element.dataset[INFINITE_SCROLL_IGNORE_KEY] = 'true'\n      }\n\n      itemsObserver.observe(element)\n    }\n\n    return true\n  }\n\n  return {\n    setupObservers,\n    enableTriggers,\n    disableTriggers,\n    refreshTriggers,\n    flushAll,\n    processManuallyAddedElements,\n    processServerLoadedElements,\n  }\n}\n"
  },
  {
    "path": "packages/core/src/infiniteScroll/queryString.ts",
    "content": "import { hrefToUrl, router, urlHasProtocol, urlToString } from '..'\nimport debounce from '../debounce'\nimport { getElementsInViewportFromCollection } from '../domUtils'\nimport { page as currentPage } from './../page'\nimport Queue from './../queue'\nimport { getPageFromElement } from './elements'\n\n// Shared queue among all instances to ensure URL updates are processed sequentially\nconst queue = new Queue<Promise<void>>()\n\nlet initialUrl: URL | null\nlet payloadUrl: URL | null\nlet initialUrlWasAbsolute: boolean | null = null\n\n/**\n * As users scroll through infinite content, this system updates the URL to reflect\n * which page they're currently viewing. It uses a \"most visible page\" calculation\n * so that the URL reflects whichever page has the most visible items.\n */\nexport const useInfiniteScrollQueryString = (options: {\n  getPageName: () => string\n  getItemsElement: () => HTMLElement\n  shouldPreserveUrl: () => boolean\n}) => {\n  let enabled = true\n\n  const queuePageUpdate = (page: string) => {\n    queue\n      .add(() => {\n        return new Promise((resolve) => {\n          if (!enabled) {\n            initialUrl = payloadUrl = null\n            return resolve()\n          }\n\n          if (!initialUrl || !payloadUrl) {\n            const currentPageUrl = currentPage.get().url\n            initialUrl = hrefToUrl(currentPageUrl)\n            payloadUrl = hrefToUrl(currentPageUrl)\n            initialUrlWasAbsolute = urlHasProtocol(currentPageUrl)\n          }\n\n          const pageName = options.getPageName()\n          const searchParams = payloadUrl.searchParams\n\n          // Clean URLs: don't show ?page=1 in the URL, just remove the parameter entirely\n          if (page === '1') {\n            searchParams.delete(pageName)\n          } else {\n            searchParams.set(pageName, page)\n          }\n\n          setTimeout(() => resolve())\n        })\n      })\n      .finally(() => {\n        if (\n          enabled &&\n          initialUrl &&\n          payloadUrl &&\n          initialUrl.href !== payloadUrl.href &&\n          initialUrlWasAbsolute !== null\n        ) {\n          // Update URL without triggering a page reload or affecting scroll position\n          router.replace({\n            url: urlToString(payloadUrl, initialUrlWasAbsolute),\n            preserveScroll: true,\n            preserveState: true,\n          })\n        }\n\n        initialUrl = payloadUrl = initialUrlWasAbsolute = null\n      })\n  }\n\n  // Debounced to avoid excessive URL updates during fast scrolling\n  const onItemIntersected = debounce((itemElement: HTMLElement) => {\n    const itemsElement = options.getItemsElement()\n\n    if (!enabled || options.shouldPreserveUrl() || !itemElement || !itemsElement) {\n      return\n    }\n\n    // Count how many items from each page are currently visible in the viewport\n    const pageMap = new Map<string, number>()\n    const elements = [...itemsElement.children] as HTMLElement[]\n\n    getElementsInViewportFromCollection(elements, itemElement).forEach((element) => {\n      const page = getPageFromElement(element) ?? '1'\n\n      if (pageMap.has(page)) {\n        pageMap.set(page, pageMap.get(page)! + 1)\n      } else {\n        pageMap.set(page, 1)\n      }\n    })\n\n    // Find the page with the most visible items - this becomes the \"current\" page\n    const sortedPages = Array.from(pageMap.entries()).sort((a, b) => b[1] - a[1])\n    const mostVisiblePage = sortedPages[0]?.[0]\n\n    if (mostVisiblePage !== undefined) {\n      queuePageUpdate(mostVisiblePage)\n    }\n  }, 250)\n\n  return {\n    onItemIntersected,\n    cancel: () => (enabled = false),\n  }\n}\n"
  },
  {
    "path": "packages/core/src/infiniteScroll/scrollPreservation.ts",
    "content": "import { getElementsInViewportFromCollection } from '../domUtils'\n\n/**\n * When loading content \"before\" the current viewport (e.g. loading page 1 when viewing page 2),\n * new content is prepended to the DOM, which naturally pushes existing content down and\n * disrupts the user's scroll position. This system maintains visual stability by:\n *\n * 1. Capturing a reference element and its position before the update\n * 2. After new content is added, calculating how far that reference element moved\n * 3. Adjusting scroll position to keep the reference element in the same visual location\n */\nexport const useInfiniteScrollPreservation = (options: {\n  getScrollableParent: () => HTMLElement | null\n  getItemsElement: () => HTMLElement\n}) => {\n  const createCallbacks = () => {\n    let currentScrollTop: number\n    let referenceElement: Element | null = null\n    let referenceElementTop: number = 0\n\n    const captureScrollPosition = () => {\n      const scrollableContainer = options.getScrollableParent()\n      const itemsElement = options.getItemsElement()\n\n      // Capture current scroll position\n      currentScrollTop = scrollableContainer?.scrollTop || window.scrollY\n\n      // Find the first visible element to use as a reference point\n      // This element will help us calculate how much the content shifted after the update\n      const visibleElements = getElementsInViewportFromCollection([...itemsElement.children] as HTMLElement[])\n\n      if (visibleElements.length > 0) {\n        referenceElement = visibleElements[0]\n        const containerRect = scrollableContainer?.getBoundingClientRect() || { top: 0 }\n        const containerTop = scrollableContainer ? containerRect.top : 0\n        const rect = referenceElement.getBoundingClientRect()\n        // Store the reference element's position relative to its container\n        referenceElementTop = rect.top - containerTop\n      }\n    }\n\n    const restoreScrollPosition = () => {\n      if (!referenceElement) {\n        return\n      }\n\n      let attempts = 0\n      let restored = false\n\n      const restore = () => {\n        attempts++\n\n        if (restored || attempts > 10) {\n          return false\n        }\n\n        // Calculate where our reference element ended up after new content was prepended\n        const scrollableContainer = options.getScrollableParent()\n        const containerRect = scrollableContainer?.getBoundingClientRect() || { top: 0 }\n        const containerTop = scrollableContainer ? containerRect.top : 0\n        const newRect = referenceElement!.getBoundingClientRect()\n        const newElementTop = newRect.top - containerTop\n\n        // Calculate how much the reference element moved due to content being prepended\n        const adjustment = newElementTop - referenceElementTop\n\n        if (adjustment === 0) {\n          // Try again on the next frame, as DOM may still be updating\n          window.requestAnimationFrame(restore)\n          return\n        }\n\n        // Adjust scroll position to compensate for the movement, keeping the reference element\n        // in the same visual position as before the update\n        if (scrollableContainer) {\n          scrollableContainer.scrollTo({ top: currentScrollTop + adjustment })\n        } else {\n          window.scrollTo(0, window.scrollY + adjustment)\n        }\n\n        restored = true\n      }\n\n      window.requestAnimationFrame(restore)\n    }\n\n    return {\n      captureScrollPosition,\n      restoreScrollPosition,\n    }\n  }\n\n  return {\n    createCallbacks,\n  }\n}\n"
  },
  {
    "path": "packages/core/src/infiniteScroll.ts",
    "content": "import { requestAnimationFrame } from './domUtils'\nimport { router } from './index'\nimport { useInfiniteScrollData } from './infiniteScroll/data'\nimport { useInfiniteScrollElementManager } from './infiniteScroll/elements'\nimport { useInfiniteScrollQueryString } from './infiniteScroll/queryString'\nimport { useInfiniteScrollPreservation } from './infiniteScroll/scrollPreservation'\nimport { Page, ReloadOptions, UseInfiniteScrollOptions, UseInfiniteScrollProps } from './types'\n\n/**\n * Core infinite scroll composable that orchestrates data fetching, DOM management,\n * scroll preservation, and URL synchronization.\n *\n * This is the main entry point that coordinates four sub-systems:\n * - Data management: Handles pagination state and server requests\n * - Element management: DOM observation and intersection detection\n * - Query string sync: Updates URL as user scrolls through pages\n * - Scroll preservation: Maintains scroll position during content updates\n */\nexport default function useInfiniteScroll(options: UseInfiniteScrollOptions): UseInfiniteScrollProps {\n  const queryStringManager = useInfiniteScrollQueryString({ ...options, getPageName: () => dataManager.getPageName() })\n\n  // Create scroll preservation callbacks that capture and restore scroll position\n  // and restore it after new content is prepended to maintain visual stability\n  const scrollPreservation = useInfiniteScrollPreservation(options)\n\n  const elementManager = useInfiniteScrollElementManager({\n    ...options,\n    // As items enter viewport, update URL to reflect the most visible page\n    onItemIntersected: queryStringManager.onItemIntersected,\n    onPreviousTriggered: () => dataManager.fetchPrevious(),\n    onNextTriggered: () => dataManager.fetchNext(),\n  })\n\n  const dataManager = useInfiniteScrollData({\n    ...options,\n    // Before updating page data, tag any manually added DOM elements\n    // so they don't get confused with server-loaded content\n    onBeforeUpdate: elementManager.processManuallyAddedElements,\n    // After successful request, tag new server content\n    onCompletePreviousRequest: (loadedPage) => {\n      options.onCompletePreviousRequest()\n      requestAnimationFrame(() => elementManager.processServerLoadedElements(loadedPage), 2)\n    },\n    onCompleteNextRequest: (loadedPage) => {\n      options.onCompleteNextRequest()\n      requestAnimationFrame(() => elementManager.processServerLoadedElements(loadedPage), 2)\n    },\n    onReset: options.onDataReset,\n  })\n\n  const addScrollPreservationCallbacks = (reloadOptions: ReloadOptions): ReloadOptions => {\n    const { captureScrollPosition, restoreScrollPosition } = scrollPreservation.createCallbacks()\n\n    const originalOnBeforeUpdate = reloadOptions.onBeforeUpdate || (() => {})\n    const originalOnSuccess = reloadOptions.onSuccess || (() => {})\n\n    reloadOptions.onBeforeUpdate = (page: Page) => {\n      originalOnBeforeUpdate(page)\n      captureScrollPosition()\n    }\n\n    reloadOptions.onSuccess = (page: Page) => {\n      originalOnSuccess(page)\n      restoreScrollPosition()\n    }\n\n    return reloadOptions\n  }\n\n  const originalFetchNext = dataManager.fetchNext\n  dataManager.fetchNext = (reloadOptions: ReloadOptions = {}) => {\n    if (options.inReverseMode()) {\n      reloadOptions = addScrollPreservationCallbacks(reloadOptions)\n    }\n\n    originalFetchNext(reloadOptions)\n  }\n\n  const originalFetchPrevious = dataManager.fetchPrevious\n  dataManager.fetchPrevious = (reloadOptions: ReloadOptions = {}) => {\n    if (!options.inReverseMode()) {\n      reloadOptions = addScrollPreservationCallbacks(reloadOptions)\n    }\n\n    originalFetchPrevious(reloadOptions)\n  }\n\n  const removeEventListener = router.on('success', () => requestAnimationFrame(elementManager.refreshTriggers, 2))\n\n  return {\n    dataManager,\n    elementManager,\n    flush: () => {\n      removeEventListener()\n      dataManager.removeEventListener()\n      elementManager.flushAll()\n      queryStringManager.cancel()\n    },\n  }\n}\n"
  },
  {
    "path": "packages/core/src/initialVisit.ts",
    "content": "import { eventHandler } from './eventHandler'\nimport { fireFlashEvent, fireNavigateEvent } from './events'\nimport { history } from './history'\nimport { navigationType } from './navigationType'\nimport { page as currentPage } from './page'\nimport { Scroll } from './scroll'\nimport { SessionStorage } from './sessionStorage'\nimport { LocationVisit, Page } from './types'\n\nexport class InitialVisit {\n  public static handle(): void {\n    this.clearRememberedStateOnReload()\n\n    const scenarios = [this.handleBackForward, this.handleLocation, this.handleDefault]\n\n    scenarios.find((handler) => handler.bind(this)())\n  }\n\n  protected static clearRememberedStateOnReload(): void {\n    if (navigationType.isReload()) {\n      history.deleteState(history.rememberedState)\n      history.clearInitialState(history.rememberedState)\n    }\n  }\n\n  protected static handleBackForward(): boolean {\n    if (!navigationType.isBackForward() || !history.browserHasHistoryEntry()) {\n      return false\n    }\n\n    const scrollRegions = history.getScrollRegions()\n\n    history\n      .decrypt()\n      .then((data) => {\n        currentPage.set(data, { preserveScroll: true, preserveState: true }).then(() => {\n          Scroll.restore(scrollRegions)\n          fireNavigateEvent(currentPage.get())\n        })\n      })\n      .catch(() => {\n        eventHandler.onMissingHistoryItem()\n      })\n\n    return true\n  }\n\n  /**\n   * @link https://inertiajs.com/redirects#external-redirects\n   */\n  protected static handleLocation(): boolean {\n    if (!SessionStorage.exists(SessionStorage.locationVisitKey)) {\n      return false\n    }\n\n    const locationVisit: LocationVisit = SessionStorage.get(SessionStorage.locationVisitKey) || {}\n\n    SessionStorage.remove(SessionStorage.locationVisitKey)\n\n    if (typeof window !== 'undefined') {\n      currentPage.setUrlHash(window.location.hash)\n    }\n\n    history\n      .decrypt(currentPage.get())\n      .then(() => {\n        const rememberedState = history.getState<Page['rememberedState']>(history.rememberedState, {})\n        const scrollRegions = history.getScrollRegions()\n        currentPage.remember(rememberedState)\n\n        currentPage\n          .set(currentPage.get(), {\n            preserveScroll: locationVisit.preserveScroll,\n            preserveState: true,\n          })\n          .then(() => {\n            if (locationVisit.preserveScroll) {\n              Scroll.restore(scrollRegions)\n            }\n\n            fireNavigateEvent(currentPage.get())\n          })\n      })\n      .catch(() => {\n        eventHandler.onMissingHistoryItem()\n      })\n\n    return true\n  }\n\n  protected static handleDefault(): void {\n    if (typeof window !== 'undefined') {\n      currentPage.setUrlHash(window.location.hash)\n    }\n\n    currentPage.set(currentPage.get(), { preserveScroll: true, preserveState: true }).then(() => {\n      if (navigationType.isReload()) {\n        Scroll.restore(history.getScrollRegions())\n      } else {\n        Scroll.scrollToAnchor()\n      }\n\n      const page = currentPage.get()\n\n      fireNavigateEvent(page)\n\n      const flash = page.flash\n\n      if (Object.keys(flash).length > 0) {\n        queueMicrotask(() => fireFlashEvent(flash))\n      }\n    })\n  }\n}\n"
  },
  {
    "path": "packages/core/src/intersectionObservers.ts",
    "content": "type IntersectionObserverCallback = (entry: IntersectionObserverEntry) => void\n\ninterface IntersectionObserverManager {\n  new: (callback: IntersectionObserverCallback, options?: IntersectionObserverInit) => IntersectionObserver\n  flushAll: () => void\n}\n\nexport const useIntersectionObservers = (): IntersectionObserverManager => {\n  const intersectionObservers: IntersectionObserver[] = []\n\n  const newIntersectionObserver = (\n    callback: IntersectionObserverCallback,\n    options: IntersectionObserverInit = {},\n  ): IntersectionObserver => {\n    const observer = new IntersectionObserver((entries) => {\n      for (const entry of entries) {\n        if (entry.isIntersecting) {\n          callback(entry)\n        }\n      }\n    }, options)\n\n    intersectionObservers.push(observer)\n\n    return observer\n  }\n\n  const flushAll = () => {\n    intersectionObservers.forEach((observer) => observer.disconnect())\n    intersectionObservers.length = 0\n  }\n\n  return {\n    new: newIntersectionObserver,\n    flushAll,\n  }\n}\n"
  },
  {
    "path": "packages/core/src/modal.ts",
    "content": "export default {\n  modal: null,\n  listener: null,\n\n  createIframeAndPage(html: Record<string, unknown> | string): { iframe: HTMLIFrameElement; page: HTMLElement } {\n    if (typeof html === 'object') {\n      html = `All Inertia requests must receive a valid Inertia response, however a plain JSON response was received.<hr>${JSON.stringify(\n        html,\n      )}`\n    }\n\n    const page = document.createElement('html')\n    page.innerHTML = html\n    page.querySelectorAll('a').forEach((a) => a.setAttribute('target', '_top'))\n\n    const iframe = document.createElement('iframe')\n    iframe.style.backgroundColor = 'white'\n    iframe.style.borderRadius = '5px'\n    iframe.style.width = '100%'\n    iframe.style.height = '100%'\n\n    return { iframe, page }\n  },\n\n  show(html: Record<string, unknown> | string): void {\n    const { iframe, page } = this.createIframeAndPage(html)\n\n    this.modal = document.createElement('div')\n    this.modal.style.position = 'fixed'\n    this.modal.style.width = '100vw'\n    this.modal.style.height = '100vh'\n    this.modal.style.padding = '50px'\n    this.modal.style.boxSizing = 'border-box'\n    this.modal.style.backgroundColor = 'rgba(0, 0, 0, .6)'\n    this.modal.style.zIndex = 200000\n    this.modal.addEventListener('click', () => this.hide())\n    this.modal.appendChild(iframe)\n\n    document.body.prepend(this.modal)\n    document.body.style.overflow = 'hidden'\n    if (!iframe.contentWindow) {\n      throw new Error('iframe not yet ready.')\n    }\n    iframe.contentWindow.document.open()\n    iframe.contentWindow.document.write(page.outerHTML)\n    iframe.contentWindow.document.close()\n\n    this.listener = this.hideOnEscape.bind(this)\n    document.addEventListener('keydown', this.listener)\n  },\n\n  hide(): void {\n    this.modal.outerHTML = ''\n    this.modal = null\n    document.body.style.overflow = 'visible'\n    document.removeEventListener('keydown', this.listener)\n  },\n\n  hideOnEscape(event: KeyboardEvent): void {\n    if (event.keyCode === 27) {\n      this.hide()\n    }\n  },\n}\n"
  },
  {
    "path": "packages/core/src/navigationEvents.ts",
    "content": "type MouseNavigationEvent = Pick<\n  MouseEvent,\n  'altKey' | 'ctrlKey' | 'shiftKey' | 'metaKey' | 'button' | 'currentTarget' | 'defaultPrevented' | 'target'\n>\n\ntype KeyboardNavigationEvent = Pick<KeyboardEvent, 'currentTarget' | 'defaultPrevented' | 'key' | 'target'>\n\nfunction isContentEditableOrPrevented(event: KeyboardNavigationEvent | MouseNavigationEvent): boolean {\n  return (event.target instanceof HTMLElement && event.target.isContentEditable) || event.defaultPrevented\n}\n\n/**\n * Determine if this mouse event should be intercepted for navigation purposes.\n * Links with modifier keys or non-left clicks should not be intercepted.\n * Content editable elements and prevented events are ignored.\n */\nexport function shouldIntercept(event: MouseNavigationEvent): boolean {\n  const isLink = (event.currentTarget as HTMLElement).tagName.toLowerCase() === 'a'\n\n  return !(\n    isContentEditableOrPrevented(event) ||\n    (isLink && event.altKey) ||\n    (isLink && event.ctrlKey) ||\n    (isLink && event.metaKey) ||\n    (isLink && event.shiftKey) ||\n    (isLink && 'button' in event && event.button !== 0)\n  )\n}\n\n/**\n * Determine if this keyboard event should trigger a navigation request.\n * Enter triggers navigation for both links and buttons currently.\n * Space only triggers navigation for buttons specifically.\n */\nexport function shouldNavigate(event: KeyboardNavigationEvent): boolean {\n  const isButton = (event.currentTarget as HTMLElement).tagName.toLowerCase() === 'button'\n\n  return !isContentEditableOrPrevented(event) && (event.key === 'Enter' || (isButton && event.key === ' '))\n}\n"
  },
  {
    "path": "packages/core/src/navigationType.ts",
    "content": "class NavigationType {\n  protected type: NavigationTimingType\n\n  public constructor() {\n    this.type = this.resolveType()\n  }\n\n  protected resolveType(): NavigationTimingType {\n    if (typeof window === 'undefined') {\n      return 'navigate'\n    }\n\n    if (\n      window.performance &&\n      window.performance.getEntriesByType &&\n      window.performance.getEntriesByType('navigation').length > 0\n    ) {\n      return (window.performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming).type\n    }\n\n    return 'navigate'\n  }\n\n  public get(): NavigationTimingType {\n    return this.type\n  }\n\n  public isBackForward(): boolean {\n    return this.type === 'back_forward'\n  }\n\n  public isReload(): boolean {\n    return this.type === 'reload'\n  }\n}\n\nexport const navigationType = new NavigationType()\n"
  },
  {
    "path": "packages/core/src/objectUtils.ts",
    "content": "export const objectsAreEqual = <T extends Record<string, any>>(\n  obj1: T,\n  obj2: T,\n  excludeKeys: {\n    [K in keyof T]: K\n  }[keyof T][],\n): boolean => {\n  if (obj1 === obj2) {\n    return true\n  }\n\n  // Check keys in obj1\n  for (const key in obj1) {\n    if (excludeKeys.includes(key)) {\n      continue\n    }\n\n    if (obj1[key] === obj2[key]) {\n      continue\n    }\n\n    if (!compareValues(obj1[key], obj2[key])) {\n      return false\n    }\n  }\n\n  // Check keys that exist in obj2 but not in obj1\n  for (const key in obj2) {\n    if (excludeKeys.includes(key)) {\n      continue\n    }\n\n    if (!(key in obj1)) {\n      return false\n    }\n  }\n\n  return true\n}\n\nconst compareValues = (value1: any, value2: any): boolean => {\n  switch (typeof value1) {\n    case 'object':\n      return objectsAreEqual(value1, value2, [])\n    case 'function':\n      return value1.toString() === value2.toString()\n    default:\n      return value1 === value2\n  }\n}\n"
  },
  {
    "path": "packages/core/src/page.ts",
    "content": "import { eventHandler } from './eventHandler'\nimport { fireNavigateEvent } from './events'\nimport { history } from './history'\nimport { prefetchedRequests } from './prefetched'\nimport { Scroll } from './scroll'\nimport { Component, FlashData, Page, PageEvent, PageHandler, PageResolver, RouterInitParams, Visit } from './types'\nimport { hrefToUrl, isSameUrlWithoutHash } from './url'\n\nclass CurrentPage {\n  protected page!: Page\n  protected swapComponent!: PageHandler<any>\n  protected resolveComponent!: PageResolver\n  protected onFlashCallback?: (flash: Page['flash']) => void\n  protected componentId = {}\n  protected listeners: {\n    event: PageEvent\n    callback: VoidFunction\n  }[] = []\n  protected isFirstPageLoad = true\n  protected cleared = false\n  protected pendingDeferredProps: Pick<Page, 'deferredProps' | 'url' | 'component'> | null = null\n  protected historyQuotaExceeded = false\n\n  public init<ComponentType = Component>({\n    initialPage,\n    swapComponent,\n    resolveComponent,\n    onFlash,\n  }: RouterInitParams<ComponentType>) {\n    this.page = { ...initialPage, flash: initialPage.flash ?? {} }\n    this.swapComponent = swapComponent\n    this.resolveComponent = resolveComponent\n    this.onFlashCallback = onFlash\n\n    eventHandler.on('historyQuotaExceeded', () => {\n      this.historyQuotaExceeded = true\n    })\n\n    return this\n  }\n\n  public set(\n    page: Page,\n    {\n      replace = false,\n      preserveScroll = false,\n      preserveState = false,\n      viewTransition = false,\n    }: {\n      replace?: boolean\n      preserveScroll?: boolean\n      preserveState?: boolean\n      viewTransition?: Visit['viewTransition']\n    } = {},\n  ): Promise<void> {\n    if (Object.keys(page.deferredProps || {}).length) {\n      this.pendingDeferredProps = {\n        deferredProps: page.deferredProps,\n        component: page.component,\n        url: page.url,\n      }\n\n      // Preserve original deferred props for back button handling\n      if (page.initialDeferredProps === undefined) {\n        page.initialDeferredProps = page.deferredProps\n      }\n    }\n\n    this.componentId = {}\n\n    const componentId = this.componentId\n\n    if (page.clearHistory) {\n      history.clear()\n    }\n\n    return this.resolve(page.component).then((component) => {\n      if (componentId !== this.componentId) {\n        // Component has changed since we started resolving this component, bail\n        return\n      }\n\n      page.rememberedState ??= {}\n\n      const isServer = typeof window === 'undefined'\n      const location = !isServer ? window.location : new URL(page.url)\n      const scrollRegions = !isServer && preserveScroll ? Scroll.getScrollRegions() : []\n      replace = replace || isSameUrlWithoutHash(hrefToUrl(page.url), location)\n\n      // Clear flash data from the page object, we don't want it when navigating back/forward...\n      const pageForHistory = { ...page, flash: {} }\n\n      return new Promise<void>((resolve) =>\n        replace ? history.replaceState(pageForHistory, resolve) : history.pushState(pageForHistory, resolve),\n      ).then(() => {\n        const isNewComponent = !this.isTheSame(page)\n\n        if (!isNewComponent && Object.keys(page.props.errors || {}).length > 0) {\n          // Don't use view transition if the page stays the same and there are (new) errors...\n          viewTransition = false\n        }\n\n        this.page = page\n        this.cleared = false\n\n        if (this.hasOnceProps()) {\n          prefetchedRequests.updateCachedOncePropsFromCurrentPage()\n        }\n\n        if (isNewComponent) {\n          this.fireEventsFor('newComponent')\n        }\n\n        if (this.isFirstPageLoad) {\n          this.fireEventsFor('firstLoad')\n        }\n\n        this.isFirstPageLoad = false\n\n        if (this.historyQuotaExceeded) {\n          // If we exceeded the history quota, don't attempt to swap the\n          // component as we're performing a full page reload instead.\n          this.historyQuotaExceeded = false\n          return\n        }\n\n        return this.swap({\n          component,\n          page,\n          preserveState,\n          viewTransition,\n        }).then(() => {\n          if (preserveScroll) {\n            // Scroll regions must be explicitly restored since the DOM elements are destroyed\n            // and recreated during the component 'swap'. Document scroll is naturally\n            // preserved as the document element itself persists across navigations.\n            window.requestAnimationFrame(() => Scroll.restoreScrollRegions(scrollRegions))\n          } else {\n            Scroll.reset()\n          }\n\n          if (\n            this.pendingDeferredProps &&\n            this.pendingDeferredProps.component === page.component &&\n            this.pendingDeferredProps.url === page.url\n          ) {\n            eventHandler.fireInternalEvent('loadDeferredProps', this.pendingDeferredProps.deferredProps)\n          }\n\n          this.pendingDeferredProps = null\n\n          if (!replace) {\n            fireNavigateEvent(page)\n          }\n        })\n      })\n    })\n  }\n\n  public setQuietly(\n    page: Page,\n    {\n      preserveState = false,\n    }: {\n      preserveState?: boolean\n    } = {},\n  ) {\n    return this.resolve(page.component).then((component) => {\n      this.page = page\n      this.cleared = false\n      history.setCurrent(page)\n      return this.swap({ component, page, preserveState, viewTransition: false })\n    })\n  }\n\n  public clear(): void {\n    this.cleared = true\n  }\n\n  public isCleared(): boolean {\n    return this.cleared\n  }\n\n  public get(): Page {\n    return this.page\n  }\n\n  public getWithoutFlashData(): Page {\n    return { ...this.page, flash: {} }\n  }\n\n  public hasOnceProps(): boolean {\n    return Object.keys(this.page.onceProps ?? {}).length > 0\n  }\n\n  public merge(data: Partial<Page>): void {\n    this.page = { ...this.page, ...data }\n  }\n\n  public setFlash(flash: FlashData): void {\n    this.page = { ...this.page, flash }\n    this.onFlashCallback?.(flash)\n  }\n\n  public setUrlHash(hash: string): void {\n    if (!this.page.url.includes(hash)) {\n      this.page.url += hash\n    }\n  }\n\n  public remember(data: Page['rememberedState']): void {\n    this.page.rememberedState = data\n  }\n\n  public swap({\n    component,\n    page,\n    preserveState,\n    viewTransition,\n  }: {\n    component: Component\n    page: Page\n    preserveState: boolean\n    viewTransition: Visit['viewTransition']\n  }): Promise<unknown> {\n    const doSwap = () => this.swapComponent({ component, page, preserveState })\n\n    if (!viewTransition || !document?.startViewTransition || document.visibilityState === 'hidden') {\n      return doSwap()\n    }\n\n    const viewTransitionCallback = typeof viewTransition === 'boolean' ? () => null : viewTransition\n\n    return new Promise((resolve) => {\n      const transitionResult = document.startViewTransition(() => doSwap().then(resolve))\n\n      viewTransitionCallback(transitionResult)\n    })\n  }\n\n  public resolve(component: string): Promise<Component> {\n    return Promise.resolve(this.resolveComponent(component))\n  }\n\n  public isTheSame(page: Page): boolean {\n    return this.page.component === page.component\n  }\n\n  public on(event: PageEvent, callback: VoidFunction): VoidFunction {\n    this.listeners.push({ event, callback })\n\n    return () => {\n      this.listeners = this.listeners.filter((listener) => listener.event !== event && listener.callback !== callback)\n    }\n  }\n\n  public fireEventsFor(event: PageEvent): void {\n    this.listeners.filter((listener) => listener.event === event).forEach((listener) => listener.callback())\n  }\n\n  public mergeOncePropsIntoResponse(response: Page, { force = false }: { force?: boolean } = {}): void {\n    Object.entries(response.onceProps ?? {}).forEach(([key, onceProp]) => {\n      const existingOnceProp = this.page.onceProps?.[key]\n\n      if (existingOnceProp === undefined) {\n        return\n      }\n\n      if (force || response.props[onceProp.prop] === undefined) {\n        response.props[onceProp.prop] = this.page.props[existingOnceProp.prop]\n        response.onceProps![key].expiresAt = existingOnceProp.expiresAt\n      }\n    })\n  }\n}\n\nexport const page = new CurrentPage()\n"
  },
  {
    "path": "packages/core/src/poll.ts",
    "content": "import { PollOptions } from './types'\n\nexport class Poll {\n  protected id: number | null = null\n  protected throttle = false\n  protected keepAlive = false\n  protected cb: VoidFunction\n  protected interval: number\n  protected cbCount = 0\n\n  constructor(interval: number, cb: VoidFunction, options: PollOptions) {\n    this.keepAlive = options.keepAlive ?? false\n\n    this.cb = cb\n    this.interval = interval\n\n    if (options.autoStart ?? true) {\n      this.start()\n    }\n  }\n\n  public stop() {\n    // console.log('stopping...', this.id)\n    if (this.id) {\n      //   console.log('clearing interval...')\n      clearInterval(this.id)\n    }\n  }\n\n  public start() {\n    if (typeof window === 'undefined') {\n      return\n    }\n\n    this.stop()\n\n    this.id = window.setInterval(() => {\n      if (!this.throttle || this.cbCount % 10 === 0) {\n        this.cb()\n      }\n\n      if (this.throttle) {\n        this.cbCount++\n      }\n    }, this.interval)\n  }\n\n  public isInBackground(hidden: boolean) {\n    this.throttle = this.keepAlive ? false : hidden\n\n    if (this.throttle) {\n      this.cbCount = 0\n    }\n  }\n}\n"
  },
  {
    "path": "packages/core/src/polls.ts",
    "content": "import { Poll } from './poll'\nimport { PollOptions } from './types'\n\nclass Polls {\n  protected polls: Poll[] = []\n\n  constructor() {\n    this.setupVisibilityListener()\n  }\n\n  public add(\n    interval: number,\n    cb: VoidFunction,\n    options: PollOptions,\n  ): {\n    stop: VoidFunction\n    start: VoidFunction\n  } {\n    const poll = new Poll(interval, cb, options)\n\n    this.polls.push(poll)\n\n    return {\n      stop: () => poll.stop(),\n      start: () => poll.start(),\n    }\n  }\n\n  public clear() {\n    this.polls.forEach((poll) => poll.stop())\n\n    this.polls = []\n  }\n\n  protected setupVisibilityListener() {\n    if (typeof document === 'undefined') {\n      return\n    }\n\n    document.addEventListener(\n      'visibilitychange',\n      () => {\n        this.polls.forEach((poll) => poll.isInBackground(document.hidden))\n      },\n      false,\n    )\n  }\n}\n\nexport const polls = new Polls()\n"
  },
  {
    "path": "packages/core/src/prefetched.ts",
    "content": "import { cloneDeep } from 'lodash-es'\nimport { objectsAreEqual } from './objectUtils'\nimport { page as currentPage } from './page'\nimport { Response } from './response'\nimport { timeToMs } from './time'\nimport {\n  ActiveVisit,\n  CacheForOption,\n  InFlightPrefetch,\n  InternalActiveVisit,\n  Page,\n  PrefetchedResponse,\n  PrefetchOptions,\n  PrefetchRemovalTimer,\n} from './types'\n\nclass PrefetchedRequests {\n  protected cached: PrefetchedResponse[] = []\n  protected inFlightRequests: InFlightPrefetch[] = []\n  protected removalTimers: PrefetchRemovalTimer[] = []\n  protected currentUseId: string | null = null\n\n  public add(\n    params: ActiveVisit,\n    sendFunc: (params: InternalActiveVisit) => void,\n    { cacheFor, cacheTags }: PrefetchOptions,\n  ) {\n    const inFlight = this.findInFlight(params)\n\n    if (inFlight) {\n      return Promise.resolve()\n    }\n\n    const existing = this.findCached(params)\n\n    if (!params.fresh && existing && existing.staleTimestamp > Date.now()) {\n      return Promise.resolve()\n    }\n\n    const [stale, prefetchExpiresIn] = this.extractStaleValues(cacheFor)\n\n    const promise = new Promise<Response>((resolve, reject) => {\n      sendFunc({\n        ...params,\n        onCancel: () => {\n          this.remove(params)\n          params.onCancel()\n          reject()\n        },\n        onError: (error) => {\n          this.remove(params)\n          params.onError(error)\n          reject()\n        },\n        onPrefetching(visitParams) {\n          params.onPrefetching(visitParams)\n        },\n        onPrefetched(response, visit) {\n          params.onPrefetched(response, visit)\n        },\n        onPrefetchResponse(response) {\n          resolve(response)\n        },\n        onPrefetchError(error) {\n          prefetchedRequests.removeFromInFlight(params)\n          reject(error)\n        },\n      })\n    }).then((response) => {\n      this.remove(params)\n\n      const pageResponse = response.getPageResponse()\n\n      currentPage.mergeOncePropsIntoResponse(pageResponse)\n\n      this.cached.push({\n        params: { ...params },\n        staleTimestamp: Date.now() + stale,\n        expiresAt: Date.now() + prefetchExpiresIn,\n        response: promise,\n        singleUse: prefetchExpiresIn === 0,\n        timestamp: Date.now(),\n        inFlight: false,\n        tags: Array.isArray(cacheTags) ? cacheTags : [cacheTags],\n      })\n\n      const oncePropExpiresIn = this.getShortestOncePropTtl(pageResponse)\n      this.scheduleForRemoval(\n        params,\n        oncePropExpiresIn ? Math.min(prefetchExpiresIn, oncePropExpiresIn) : prefetchExpiresIn,\n      )\n      this.removeFromInFlight(params)\n\n      response.handlePrefetch()\n\n      return response\n    })\n\n    this.inFlightRequests.push({\n      params: { ...params },\n      response: promise,\n      staleTimestamp: null,\n      inFlight: true,\n    })\n\n    return promise\n  }\n\n  public removeAll(): void {\n    this.cached = []\n    this.removalTimers.forEach((removalTimer) => {\n      clearTimeout(removalTimer.timer)\n    })\n    this.removalTimers = []\n  }\n\n  public removeByTags(tags: string[]): void {\n    this.cached = this.cached.filter((prefetched) => {\n      return !prefetched.tags.some((tag) => tags.includes(tag))\n    })\n  }\n\n  public remove(params: ActiveVisit): void {\n    this.cached = this.cached.filter((prefetched) => {\n      return !this.paramsAreEqual(prefetched.params, params)\n    })\n\n    this.clearTimer(params)\n  }\n\n  protected removeFromInFlight(params: ActiveVisit): void {\n    this.inFlightRequests = this.inFlightRequests.filter((prefetching) => {\n      return !this.paramsAreEqual(prefetching.params, params)\n    })\n  }\n\n  protected extractStaleValues(cacheFor: PrefetchOptions['cacheFor']): [number, number] {\n    const [stale, expires] = this.cacheForToStaleAndExpires(cacheFor)\n\n    return [timeToMs(stale), timeToMs(expires)]\n  }\n\n  protected cacheForToStaleAndExpires(cacheFor: PrefetchOptions['cacheFor']): [CacheForOption, CacheForOption] {\n    if (!Array.isArray(cacheFor)) {\n      return [cacheFor, cacheFor]\n    }\n\n    switch (cacheFor.length) {\n      case 0:\n        return [0, 0]\n      case 1:\n        return [cacheFor[0], cacheFor[0]]\n      default:\n        return [cacheFor[0], cacheFor[1]]\n    }\n  }\n\n  protected clearTimer(params: ActiveVisit) {\n    const timer = this.removalTimers.find((removalTimer) => {\n      return this.paramsAreEqual(removalTimer.params, params)\n    })\n\n    if (timer) {\n      clearTimeout(timer.timer)\n      this.removalTimers = this.removalTimers.filter((removalTimer) => removalTimer !== timer)\n    }\n  }\n\n  protected scheduleForRemoval(params: ActiveVisit, expiresIn: number) {\n    if (typeof window === 'undefined') {\n      return\n    }\n\n    this.clearTimer(params)\n\n    if (expiresIn > 0) {\n      const timer = window.setTimeout(() => this.remove(params), expiresIn)\n\n      this.removalTimers.push({\n        params,\n        timer,\n      })\n    }\n  }\n\n  public get(params: ActiveVisit): InFlightPrefetch | PrefetchedResponse | null {\n    return this.findCached(params) || this.findInFlight(params)\n  }\n\n  public use(prefetched: PrefetchedResponse | InFlightPrefetch, params: ActiveVisit) {\n    const id = `${params.url.pathname}-${Date.now()}-${Math.random().toString(36).substring(7)}`\n\n    this.currentUseId = id\n\n    return prefetched.response.then((response) => {\n      if (this.currentUseId !== id) {\n        // They've since gone on to `use` a different request,\n        // so we should ignore this one\n        return\n      }\n\n      response.mergeParams({ ...params, onPrefetched: () => {} })\n\n      // If this was a one-time cache, remove it\n      // (generally a prefetch=\"click\" request with no specified cache value)\n      this.removeSingleUseItems(params)\n\n      return response.handle()\n    })\n  }\n\n  protected removeSingleUseItems(params: ActiveVisit) {\n    this.cached = this.cached.filter((prefetched) => {\n      if (!this.paramsAreEqual(prefetched.params, params)) {\n        return true\n      }\n\n      return !prefetched.singleUse\n    })\n  }\n\n  public findCached(params: ActiveVisit): PrefetchedResponse | null {\n    return (\n      this.cached.find((prefetched) => {\n        return this.paramsAreEqual(prefetched.params, params)\n      }) || null\n    )\n  }\n\n  public findInFlight(params: ActiveVisit): InFlightPrefetch | null {\n    return (\n      this.inFlightRequests.find((prefetched) => {\n        return this.paramsAreEqual(prefetched.params, params)\n      }) || null\n    )\n  }\n\n  protected withoutPurposePrefetchHeader(params: ActiveVisit): ActiveVisit {\n    const newParams = cloneDeep(params)\n    if (newParams.headers['Purpose'] === 'prefetch') {\n      delete newParams.headers['Purpose']\n    }\n    return newParams\n  }\n\n  protected paramsAreEqual(params1: ActiveVisit, params2: ActiveVisit): boolean {\n    return objectsAreEqual<ActiveVisit>(\n      this.withoutPurposePrefetchHeader(params1),\n      this.withoutPurposePrefetchHeader(params2),\n      [\n        'showProgress',\n        'replace',\n        'prefetch',\n        'preserveScroll',\n        'preserveState',\n        'onBefore',\n        'onBeforeUpdate',\n        'onStart',\n        'onProgress',\n        'onFinish',\n        'onCancel',\n        'onSuccess',\n        'onError',\n        'onFlash',\n        'onPrefetched',\n        'onCancelToken',\n        'onPrefetching',\n        'async',\n        'viewTransition',\n      ],\n    )\n  }\n\n  public updateCachedOncePropsFromCurrentPage(): void {\n    this.cached.forEach((prefetched) => {\n      prefetched.response.then((response) => {\n        const pageResponse = response.getPageResponse()\n\n        currentPage.mergeOncePropsIntoResponse(pageResponse, { force: true })\n\n        for (const [group, deferredProps] of Object.entries(pageResponse.deferredProps ?? {})) {\n          const remaining = deferredProps.filter((prop) => pageResponse.props[prop] === undefined)\n\n          if (remaining.length > 0) {\n            pageResponse.deferredProps![group] = remaining\n          } else {\n            delete pageResponse.deferredProps![group]\n          }\n        }\n\n        const oncePropExpiresIn = this.getShortestOncePropTtl(pageResponse)\n\n        if (oncePropExpiresIn === null) {\n          return\n        }\n\n        const prefetchExpiresIn = prefetched.expiresAt - Date.now()\n        const expiresIn = Math.min(prefetchExpiresIn, oncePropExpiresIn)\n\n        if (expiresIn > 0) {\n          this.scheduleForRemoval(prefetched.params, expiresIn)\n        } else {\n          this.remove(prefetched.params)\n        }\n      })\n    })\n  }\n\n  protected getShortestOncePropTtl(page: Page): number | null {\n    const expiryTimestamps = Object.values(page.onceProps ?? {})\n      .map((onceProp) => onceProp.expiresAt)\n      .filter((expiresAt): expiresAt is number => !!expiresAt)\n\n    if (expiryTimestamps.length === 0) {\n      return null\n    }\n\n    return Math.min(...expiryTimestamps) - Date.now()\n  }\n}\n\nexport const prefetchedRequests = new PrefetchedRequests()\n"
  },
  {
    "path": "packages/core/src/progress-component.ts",
    "content": "/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress\n * @license MIT */\n\nimport { ProgressSettings } from './types'\n\nconst baseComponentSelector = 'nprogress'\n\nlet progress: HTMLDivElement\n\nconst settings: ProgressSettings = {\n  minimum: 0.08,\n  easing: 'linear',\n  positionUsing: 'translate3d',\n  speed: 200,\n  trickle: true,\n  trickleSpeed: 200,\n  showSpinner: true,\n  barSelector: '[role=\"bar\"]',\n  spinnerSelector: '[role=\"spinner\"]',\n  parent: 'body',\n  color: '#29d',\n  includeCSS: true,\n  template: [\n    '<div class=\"bar\" role=\"bar\">',\n    '<div class=\"peg\"></div>',\n    '</div>',\n    '<div class=\"spinner\" role=\"spinner\">',\n    '<div class=\"spinner-icon\"></div>',\n    '</div>',\n  ].join(''),\n}\n\nlet status: number | null = null\n\nconst configure = (options: Partial<ProgressSettings>) => {\n  Object.assign(settings, options)\n\n  if (settings.includeCSS) {\n    injectCSS(settings.color)\n  }\n\n  progress = document.createElement('div')\n  progress.id = baseComponentSelector\n  progress.innerHTML = settings.template\n}\n\n/**\n * Sets the progress bar status, where `n` is a number from `0.0` to `1.0`.\n */\nconst set = (n: number) => {\n  const started = isStarted()\n\n  n = clamp(n, settings.minimum, 1)\n  status = n === 1 ? null : n\n\n  const progress = render(!started)\n  const bar = progress.querySelector(settings.barSelector)! as HTMLElement\n  const speed = settings.speed\n  const ease = settings.easing\n\n  progress.offsetWidth /* Repaint */\n\n  queue((next) => {\n    const barStyles = ((): Partial<CSSStyleDeclaration> => {\n      if (settings.positionUsing === 'translate3d') {\n        return {\n          transition: `all ${speed}ms ${ease}`,\n          transform: `translate3d(${toBarPercentage(n)}%,0,0)`,\n        }\n      }\n\n      if (settings.positionUsing === 'translate') {\n        return {\n          transition: `all ${speed}ms ${ease}`,\n          transform: `translate(${toBarPercentage(n)}%,0)`,\n        }\n      }\n\n      return { marginLeft: `${toBarPercentage(n)}%` }\n    })()\n\n    for (const key in barStyles) {\n      bar.style[key] = barStyles[key]!\n    }\n\n    if (n !== 1) {\n      return setTimeout(next, speed)\n    }\n\n    // Fade out\n    progress.style.transition = 'none'\n    progress.style.opacity = '1'\n    progress.offsetWidth /* Repaint */\n\n    setTimeout(() => {\n      progress.style.transition = `all ${speed}ms linear`\n      progress.style.opacity = '0'\n\n      setTimeout(() => {\n        remove()\n        progress.style.transition = ''\n        progress.style.opacity = ''\n        next()\n      }, speed)\n    }, speed)\n  })\n}\n\nconst isStarted = () => typeof status === 'number'\n\n/**\n * Shows the progress bar.\n * This is the same as setting the status to 0%, except that it doesn't go backwards.\n */\nconst start = () => {\n  if (!status) {\n    set(0)\n  }\n\n  const work = function () {\n    setTimeout(function () {\n      if (!status) {\n        return\n      }\n\n      increaseByRandom()\n      work()\n    }, settings.trickleSpeed)\n  }\n\n  if (settings.trickle) {\n    work()\n  }\n}\n\n/**\n * Hides the progress bar.\n * This is the *sort of* the same as setting the status to 100%, with the\n * difference being `done()` makes some placebo effect of some realistic motion.\n *\n * If `true` is passed, it will show the progress bar even if it's hidden.\n */\nconst done = (force?: boolean) => {\n  if (!force && !status) {\n    return\n  }\n\n  increaseByRandom(0.3 + 0.5 * Math.random())\n  set(1)\n}\n\nconst increaseByRandom = (amount?: number) => {\n  const n = status\n\n  if (n === null) {\n    return start()\n  }\n\n  if (n > 1) {\n    return\n  }\n\n  amount =\n    typeof amount === 'number'\n      ? amount\n      : (() => {\n          const ranges: Record<number, [number, number]> = {\n            0.1: [0, 0.2],\n            0.04: [0.2, 0.5],\n            0.02: [0.5, 0.8],\n            0.005: [0.8, 0.99],\n          }\n\n          for (const r in ranges) {\n            if (n >= ranges[r][0] && n < ranges[r][1]) {\n              return parseFloat(r)\n            }\n          }\n\n          return 0\n        })()\n\n  return set(clamp(n + amount, 0, 0.994))\n}\n\n/**\n * (Internal) renders the progress bar markup based on the `template` setting.\n */\nconst render = (fromStart: boolean) => {\n  if (isRendered()) {\n    return document.getElementById(baseComponentSelector)!\n  }\n\n  document.documentElement.classList.add(`${baseComponentSelector}-busy`)\n\n  const bar = progress.querySelector(settings.barSelector)! as HTMLElement\n  const perc = fromStart ? '-100' : toBarPercentage(status || 0)\n  const parent = getParent()\n\n  bar.style.transition = 'all 0 linear'\n  bar.style.transform = `translate3d(${perc}%,0,0)`\n\n  if (!settings.showSpinner) {\n    progress.querySelector(settings.spinnerSelector)?.remove()\n  }\n\n  if (parent !== document.body) {\n    parent.classList.add(`${baseComponentSelector}-custom-parent`)\n  }\n\n  parent.appendChild(progress)\n\n  return progress\n}\n\nconst getParent = (): HTMLElement => {\n  return (isDOM(settings.parent) ? settings.parent : document.querySelector(settings.parent)) as HTMLElement\n}\n\nconst remove = () => {\n  document.documentElement.classList.remove(`${baseComponentSelector}-busy`)\n  getParent().classList.remove(`${baseComponentSelector}-custom-parent`)\n  progress?.remove()\n}\n\nconst isRendered = () => {\n  return document.getElementById(baseComponentSelector) !== null\n}\n\nconst isDOM = (obj: any) => {\n  if (typeof HTMLElement === 'object') {\n    return obj instanceof HTMLElement\n  }\n\n  return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string'\n}\n\nfunction clamp(n: number, min: number, max: number): number {\n  if (n < min) {\n    return min\n  }\n\n  if (n > max) {\n    return max\n  }\n\n  return n\n}\n\n// Converts a percentage (`0..1`) to a bar translateX percentage (`-100%..0%`).\nconst toBarPercentage = (n: number) => (-1 + n) * 100\n\n// Queues a function to be executed.\nconst queue = (() => {\n  const pending: ((...args: any[]) => any)[] = []\n\n  const next = () => {\n    const fn = pending.shift()\n\n    if (fn) {\n      fn(next)\n    }\n  }\n\n  return (fn: (...args: any[]) => any) => {\n    pending.push(fn)\n\n    if (pending.length === 1) {\n      next()\n    }\n  }\n})()\n\nconst injectCSS = (color: string): void => {\n  const element = document.createElement('style')\n\n  element.textContent = `\n    #${baseComponentSelector} {\n      pointer-events: none;\n    }\n\n    #${baseComponentSelector} .bar {\n      background: ${color};\n\n      position: fixed;\n      z-index: 1031;\n      top: 0;\n      left: 0;\n\n      width: 100%;\n      height: 2px;\n    }\n\n    #${baseComponentSelector} .peg {\n      display: block;\n      position: absolute;\n      right: 0px;\n      width: 100px;\n      height: 100%;\n      box-shadow: 0 0 10px ${color}, 0 0 5px ${color};\n      opacity: 1.0;\n\n      transform: rotate(3deg) translate(0px, -4px);\n    }\n\n    #${baseComponentSelector} .spinner {\n      display: block;\n      position: fixed;\n      z-index: 1031;\n      top: 15px;\n      right: 15px;\n    }\n\n    #${baseComponentSelector} .spinner-icon {\n      width: 18px;\n      height: 18px;\n      box-sizing: border-box;\n\n      border: solid 2px transparent;\n      border-top-color: ${color};\n      border-left-color: ${color};\n      border-radius: 50%;\n\n      animation: ${baseComponentSelector}-spinner 400ms linear infinite;\n    }\n\n    .${baseComponentSelector}-custom-parent {\n      overflow: hidden;\n      position: relative;\n    }\n\n    .${baseComponentSelector}-custom-parent #${baseComponentSelector} .spinner,\n    .${baseComponentSelector}-custom-parent #${baseComponentSelector} .bar {\n      position: absolute;\n    }\n\n    @keyframes ${baseComponentSelector}-spinner {\n      0%   { transform: rotate(0deg); }\n      100% { transform: rotate(360deg); }\n    }\n  `\n  document.head.appendChild(element)\n}\n\nconst show = () => {\n  if (progress) {\n    progress.style.display = ''\n  }\n}\n\nconst hide = () => {\n  if (progress) {\n    progress.style.display = 'none'\n  }\n}\n\nexport default {\n  configure,\n  isStarted,\n  done,\n  set,\n  remove,\n  start,\n  status,\n  show,\n  hide,\n}\n"
  },
  {
    "path": "packages/core/src/progress.ts",
    "content": "import ProgressComponent from './progress-component'\nimport { GlobalEvent } from './types'\n\nclass Progress {\n  public hideCount = 0\n\n  public start(): void {\n    ProgressComponent.start()\n  }\n\n  public reveal(force: boolean = false): void {\n    this.hideCount = Math.max(0, this.hideCount - 1)\n\n    if (force || this.hideCount === 0) {\n      ProgressComponent.show()\n    }\n  }\n\n  public hide(): void {\n    this.hideCount++\n\n    ProgressComponent.hide()\n  }\n\n  public set(status: number): void {\n    ProgressComponent.set(Math.max(0, Math.min(1, status)))\n  }\n\n  public finish(): void {\n    ProgressComponent.done()\n  }\n\n  public reset(): void {\n    ProgressComponent.set(0)\n  }\n\n  public remove(): void {\n    ProgressComponent.done()\n    ProgressComponent.remove()\n  }\n\n  public isStarted(): boolean {\n    return ProgressComponent.isStarted()\n  }\n\n  public getStatus(): number | null {\n    return ProgressComponent.status\n  }\n}\n\nexport const progress = new Progress()\nexport const reveal = progress.reveal\nexport const hide = progress.hide\n\nfunction addEventListeners(delay: number): void {\n  document.addEventListener('inertia:start', (e) => handleStartEvent(e, delay))\n  document.addEventListener('inertia:progress', handleProgressEvent)\n}\n\nfunction handleStartEvent(event: GlobalEvent<'start'>, delay: number): void {\n  if (!event.detail.visit.showProgress) {\n    progress.hide()\n  }\n\n  const timeout = setTimeout(() => progress.start(), delay)\n  document.addEventListener('inertia:finish', (e) => finish(e, timeout), { once: true })\n}\n\nfunction handleProgressEvent(event: GlobalEvent<'progress'>): void {\n  if (progress.isStarted() && event.detail.progress?.percentage) {\n    progress.set(Math.max(progress.getStatus()!, (event.detail.progress.percentage / 100) * 0.9))\n  }\n}\n\nfunction finish(event: GlobalEvent<'finish'>, timeout: NodeJS.Timeout): void {\n  clearTimeout(timeout!)\n\n  if (!progress.isStarted()) {\n    return\n  }\n\n  if (event.detail.visit.completed) {\n    progress.finish()\n  } else if (event.detail.visit.interrupted) {\n    progress.reset()\n  } else if (event.detail.visit.cancelled) {\n    progress.remove()\n  }\n}\n\nexport default function setupProgress({\n  delay = 250,\n  color = '#29d',\n  includeCSS = true,\n  showSpinner = false,\n} = {}): void {\n  addEventListeners(delay)\n  ProgressComponent.configure({ showSpinner, includeCSS, color })\n}\n"
  },
  {
    "path": "packages/core/src/queue.ts",
    "content": "export default class Queue<T> {\n  protected items: (() => T)[] = []\n  protected processingPromise: Promise<void> | null = null\n\n  public add(item: () => T) {\n    this.items.push(item)\n    return this.process()\n  }\n\n  public process() {\n    this.processingPromise ??= this.processNext().finally(() => {\n      this.processingPromise = null\n    })\n\n    return this.processingPromise\n  }\n\n  protected processNext(): Promise<void> {\n    const next = this.items.shift()\n\n    if (next) {\n      return Promise.resolve(next()).then(() => this.processNext())\n    }\n\n    return Promise.resolve()\n  }\n}\n"
  },
  {
    "path": "packages/core/src/request.ts",
    "content": "import { type AxiosProgressEvent, type AxiosRequestConfig, default as axios } from 'axios'\nimport { fireExceptionEvent, fireFinishEvent, firePrefetchingEvent, fireProgressEvent, fireStartEvent } from './events'\nimport { page as currentPage } from './page'\nimport { RequestParams } from './requestParams'\nimport { Response } from './response'\nimport type { ActiveVisit, Page } from './types'\nimport { urlWithoutHash } from './url'\n\nexport class Request {\n  protected response!: Response\n  protected cancelToken!: AbortController\n  protected requestParams: RequestParams\n  protected requestHasFinished = false\n\n  constructor(\n    params: ActiveVisit,\n    protected page: Page,\n  ) {\n    this.requestParams = RequestParams.create(params)\n    this.cancelToken = new AbortController()\n  }\n\n  public static create(params: ActiveVisit, page: Page): Request {\n    return new Request(params, page)\n  }\n\n  public isPrefetch(): boolean {\n    return this.requestParams.isPrefetch()\n  }\n\n  public async send() {\n    this.requestParams.onCancelToken(() => this.cancel({ cancelled: true }))\n\n    fireStartEvent(this.requestParams.all())\n    this.requestParams.onStart()\n\n    if (this.requestParams.all().prefetch) {\n      this.requestParams.onPrefetching()\n      firePrefetchingEvent(this.requestParams.all())\n    }\n\n    // We capture this up here because the response\n    // will clear the prefetch flag so it can use it\n    // as a regular response once the prefetch is done\n    const originallyPrefetch = this.requestParams.all().prefetch\n\n    return axios({\n      method: this.requestParams.all().method,\n      url: urlWithoutHash(this.requestParams.all().url).href,\n      data: this.requestParams.data(),\n      params: this.requestParams.queryParams(),\n      signal: this.cancelToken.signal,\n      headers: this.getHeaders(),\n      onUploadProgress: this.onProgress.bind(this),\n      // Why text? This allows us to delay JSON.parse until we're ready to use the response,\n      // helps with performance particularly on large responses + history encryption\n      responseType: 'text',\n    })\n      .then((response) => {\n        this.response = Response.create(this.requestParams, response, this.page)\n\n        return this.response.handle()\n      })\n      .catch((error) => {\n        if (error?.response) {\n          this.response = Response.create(this.requestParams, error.response, this.page)\n\n          return this.response.handle()\n        }\n\n        return Promise.reject(error)\n      })\n      .catch((error) => {\n        if (axios.isCancel(error)) {\n          return\n        }\n\n        if (fireExceptionEvent(error)) {\n          if (originallyPrefetch) {\n            this.requestParams.onPrefetchError(error)\n          }\n\n          return Promise.reject(error)\n        }\n      })\n      .finally(() => {\n        this.finish()\n\n        if (originallyPrefetch && this.response) {\n          this.requestParams.onPrefetchResponse(this.response)\n        }\n      })\n  }\n\n  protected finish(): void {\n    if (this.requestParams.wasCancelledAtAll()) {\n      return\n    }\n\n    this.requestParams.markAsFinished()\n    this.fireFinishEvents()\n  }\n\n  protected fireFinishEvents(): void {\n    if (this.requestHasFinished) {\n      // This could be called from multiple places, don't let it re-fire\n      return\n    }\n\n    this.requestHasFinished = true\n\n    fireFinishEvent(this.requestParams.all())\n    this.requestParams.onFinish()\n  }\n\n  public cancel({ cancelled = false, interrupted = false }: { cancelled?: boolean; interrupted?: boolean }): void {\n    if (this.requestHasFinished) {\n      // If the request has already finished, there's no need to cancel it\n      return\n    }\n\n    this.cancelToken.abort()\n\n    this.requestParams.markAsCancelled({ cancelled, interrupted })\n\n    this.fireFinishEvents()\n  }\n\n  protected onProgress(progress: AxiosProgressEvent): void {\n    if (this.requestParams.data() instanceof FormData) {\n      progress.percentage = progress.progress ? Math.round(progress.progress * 100) : 0\n      fireProgressEvent(progress)\n      this.requestParams.all().onProgress(progress)\n    }\n  }\n\n  protected getHeaders(): AxiosRequestConfig['headers'] {\n    const headers: AxiosRequestConfig['headers'] = {\n      ...this.requestParams.headers(),\n      Accept: 'text/html, application/xhtml+xml',\n      'X-Requested-With': 'XMLHttpRequest',\n      'X-Inertia': true,\n    }\n\n    const page = currentPage.get()\n\n    if (page.version) {\n      headers['X-Inertia-Version'] = page.version\n    }\n\n    const onceProps = Object.entries(page.onceProps || {})\n      .filter(([, onceProp]) => {\n        if (page.props[onceProp.prop] === undefined) {\n          // The prop could deferred and not be loaded yet\n          return false\n        }\n\n        return !onceProp.expiresAt || onceProp.expiresAt > Date.now()\n      })\n      .map(([key]) => key)\n\n    if (onceProps.length > 0) {\n      headers['X-Inertia-Except-Once-Props'] = onceProps.join(',')\n    }\n\n    return headers\n  }\n}\n"
  },
  {
    "path": "packages/core/src/requestParams.ts",
    "content": "import { AxiosRequestConfig } from 'axios'\nimport { page as currentPage } from './page'\nimport { Response } from './response'\nimport { ActiveVisit, InternalActiveVisit, Page, PreserveStateOption, VisitCallbacks } from './types'\n\nexport class RequestParams {\n  protected callbacks: {\n    name: keyof VisitCallbacks\n    args: any[]\n  }[] = []\n\n  protected params: InternalActiveVisit\n\n  constructor(params: InternalActiveVisit) {\n    if (!params.prefetch) {\n      this.params = params\n    } else {\n      const wrappedCallbacks: Record<keyof VisitCallbacks, () => any> = {\n        onBefore: this.wrapCallback(params, 'onBefore'),\n        onBeforeUpdate: this.wrapCallback(params, 'onBeforeUpdate'),\n        onStart: this.wrapCallback(params, 'onStart'),\n        onProgress: this.wrapCallback(params, 'onProgress'),\n        onFinish: this.wrapCallback(params, 'onFinish'),\n        onCancel: this.wrapCallback(params, 'onCancel'),\n        onSuccess: this.wrapCallback(params, 'onSuccess'),\n        onError: this.wrapCallback(params, 'onError'),\n        onFlash: this.wrapCallback(params, 'onFlash'),\n        onCancelToken: this.wrapCallback(params, 'onCancelToken'),\n        onPrefetched: this.wrapCallback(params, 'onPrefetched'),\n        onPrefetching: this.wrapCallback(params, 'onPrefetching'),\n      }\n\n      this.params = {\n        ...params,\n        ...wrappedCallbacks,\n        onPrefetchResponse: params.onPrefetchResponse || (() => {}),\n        onPrefetchError: params.onPrefetchError || (() => {}),\n      }\n    }\n    //\n  }\n\n  public static create(params: ActiveVisit): RequestParams {\n    return new RequestParams(params)\n  }\n\n  public data() {\n    return this.params.method === 'get' ? null : this.params.data\n  }\n\n  public queryParams() {\n    return this.params.method === 'get' ? this.params.data : {}\n  }\n\n  public isPartial() {\n    return this.params.only.length > 0 || this.params.except.length > 0 || this.params.reset.length > 0\n  }\n\n  public isPrefetch(): boolean {\n    return this.params.prefetch === true\n  }\n\n  public isDeferredPropsRequest() {\n    return this.params.deferredProps === true\n  }\n\n  public onCancelToken(cb: VoidFunction) {\n    this.params.onCancelToken({\n      cancel: cb,\n    })\n  }\n\n  public markAsFinished() {\n    this.params.completed = true\n    this.params.cancelled = false\n    this.params.interrupted = false\n  }\n\n  public markAsCancelled({ cancelled = true, interrupted = false }) {\n    this.params.onCancel()\n\n    this.params.completed = false\n    this.params.cancelled = cancelled\n    this.params.interrupted = interrupted\n  }\n\n  public wasCancelledAtAll() {\n    return this.params.cancelled || this.params.interrupted\n  }\n\n  public onFinish() {\n    this.params.onFinish(this.params)\n  }\n\n  public onStart() {\n    this.params.onStart(this.params)\n  }\n\n  public onPrefetching() {\n    this.params.onPrefetching(this.params)\n  }\n\n  public onPrefetchResponse(response: Response) {\n    if (this.params.onPrefetchResponse) {\n      this.params.onPrefetchResponse(response)\n    }\n  }\n\n  public onPrefetchError(error: Error) {\n    if (this.params.onPrefetchError) {\n      this.params.onPrefetchError(error)\n    }\n  }\n\n  public all() {\n    return this.params\n  }\n\n  public headers(): AxiosRequestConfig['headers'] {\n    const headers: AxiosRequestConfig['headers'] = {\n      ...this.params.headers,\n    }\n\n    if (this.isPartial()) {\n      headers['X-Inertia-Partial-Component'] = currentPage.get().component\n    }\n\n    const only = this.params.only.concat(this.params.reset)\n\n    if (only.length > 0) {\n      headers['X-Inertia-Partial-Data'] = only.join(',')\n    }\n\n    if (this.params.except.length > 0) {\n      headers['X-Inertia-Partial-Except'] = this.params.except.join(',')\n    }\n\n    if (this.params.reset.length > 0) {\n      headers['X-Inertia-Reset'] = this.params.reset.join(',')\n    }\n\n    if (this.params.errorBag && this.params.errorBag.length > 0) {\n      headers['X-Inertia-Error-Bag'] = this.params.errorBag\n    }\n\n    return headers\n  }\n\n  public setPreserveOptions(page: Page) {\n    this.params.preserveScroll = RequestParams.resolvePreserveOption(this.params.preserveScroll, page)\n    this.params.preserveState = RequestParams.resolvePreserveOption(this.params.preserveState, page)\n  }\n\n  public runCallbacks() {\n    this.callbacks.forEach(({ name, args }) => {\n      // @ts-ignore\n      this.params[name](...args)\n    })\n  }\n\n  public merge(toMerge: Partial<ActiveVisit>) {\n    this.params = {\n      ...this.params,\n      ...toMerge,\n    }\n  }\n\n  protected wrapCallback(params: ActiveVisit, name: keyof VisitCallbacks) {\n    // @ts-ignore\n    return (...args) => {\n      this.recordCallback(name, args)\n      // @ts-ignore\n      params[name](...args)\n    }\n  }\n\n  protected recordCallback(name: keyof VisitCallbacks, args: any[]) {\n    this.callbacks.push({ name, args })\n  }\n\n  public static resolvePreserveOption(value: PreserveStateOption, page: Page): boolean {\n    if (typeof value === 'function') {\n      return value(page)\n    }\n\n    if (value === 'errors') {\n      return Object.keys(page.props.errors || {}).length > 0\n    }\n\n    return value\n  }\n}\n"
  },
  {
    "path": "packages/core/src/requestStream.ts",
    "content": "import { Request } from './request'\n\nexport class RequestStream {\n  protected requests: Request[] = []\n\n  protected maxConcurrent: number\n\n  protected interruptible: boolean\n\n  constructor({ maxConcurrent, interruptible }: { maxConcurrent: number; interruptible: boolean }) {\n    this.maxConcurrent = maxConcurrent\n    this.interruptible = interruptible\n  }\n\n  public send(request: Request) {\n    this.requests.push(request)\n\n    request.send().finally(() => {\n      this.requests = this.requests.filter((r) => r !== request)\n    })\n  }\n\n  public interruptInFlight(): void {\n    this.cancel({ interrupted: true }, false)\n  }\n\n  public cancelInFlight({ prefetch = true } = {}): void {\n    this.requests\n      .filter((request) => prefetch || !request.isPrefetch())\n      .forEach((request) => request.cancel({ cancelled: true }))\n  }\n\n  protected cancel({ cancelled = false, interrupted = false } = {}, force: boolean = false): void {\n    if (!force && !this.shouldCancel()) {\n      return\n    }\n\n    const request = this.requests.shift()!\n\n    request?.cancel({ cancelled, interrupted })\n  }\n\n  protected shouldCancel(): boolean {\n    return this.interruptible && this.requests.length >= this.maxConcurrent\n  }\n}\n"
  },
  {
    "path": "packages/core/src/resetFormFields.ts",
    "content": "export const FormComponentResetSymbol = Symbol('FormComponentReset')\n\ntype FormElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement\n\nfunction isFormElement(element: Element): element is FormElement {\n  return (\n    element instanceof HTMLInputElement ||\n    element instanceof HTMLSelectElement ||\n    element instanceof HTMLTextAreaElement\n  )\n}\n\nfunction resetInputElement(input: HTMLInputElement, defaultValues: FormDataEntryValue[]): boolean {\n  const oldValue = input.value\n  const oldChecked = input.checked\n\n  switch (input.type.toLowerCase()) {\n    case 'checkbox':\n      // For checkboxes, check if the input's value is in the array of default values\n      input.checked = defaultValues.includes(input.value)\n      break\n    case 'radio':\n      // For radios, only use the first default value to avoid multiple radios being checked\n      input.checked = defaultValues[0] === input.value\n      break\n    case 'file':\n      input.value = ''\n      break\n    case 'button':\n    case 'submit':\n    case 'reset':\n    case 'image':\n      // These input types don't carry form state\n      break\n    default:\n      // text, email, number, date, etc. - use first default value\n      input.value = defaultValues[0] !== null && defaultValues[0] !== undefined ? String(defaultValues[0]) : ''\n  }\n\n  // Return true if the value actually changed\n  return input.value !== oldValue || input.checked !== oldChecked\n}\n\nfunction resetSelectElement(select: HTMLSelectElement, defaultValues: FormDataEntryValue[]): boolean {\n  const oldValue = select.value\n  const oldSelectedOptions = Array.from(select.selectedOptions).map((opt) => opt.value)\n\n  if (select.multiple) {\n    // For multi-select, select all options that match any of the default values\n    const defaultStrings = defaultValues.map((value) => String(value))\n\n    Array.from(select.options).forEach((option) => {\n      option.selected = defaultStrings.includes(option.value)\n    })\n  } else {\n    // For single select, use the first default value (or empty string)\n    select.value = defaultValues[0] !== undefined ? String(defaultValues[0]) : ''\n  }\n\n  // Check if selection actually changed\n  const newSelectedOptions = Array.from(select.selectedOptions).map((opt) => opt.value)\n  const hasChanged = select.multiple\n    ? JSON.stringify(oldSelectedOptions.sort()) !== JSON.stringify(newSelectedOptions.sort())\n    : select.value !== oldValue\n\n  return hasChanged\n}\n\nfunction resetFormElement(element: FormElement, defaultValues: FormDataEntryValue[]): boolean {\n  if (element.disabled) {\n    // For disabled elements, use their DOM defaultValue since they're not in FormData\n    if (element instanceof HTMLInputElement) {\n      const oldValue = element.value\n      const oldChecked = element.checked\n\n      switch (element.type.toLowerCase()) {\n        case 'checkbox':\n        case 'radio':\n          element.checked = element.defaultChecked\n          return element.checked !== oldChecked\n        case 'file':\n          element.value = ''\n          return oldValue !== ''\n        case 'button':\n        case 'submit':\n        case 'reset':\n        case 'image':\n          // These input types don't carry form state\n          return false\n        default:\n          element.value = element.defaultValue\n          return element.value !== oldValue\n      }\n    } else if (element instanceof HTMLSelectElement) {\n      // Reset select to default selected options\n      const oldSelectedOptions = Array.from(element.selectedOptions).map((opt) => opt.value)\n\n      Array.from(element.options).forEach((option) => {\n        option.selected = option.defaultSelected\n      })\n\n      const newSelectedOptions = Array.from(element.selectedOptions).map((opt) => opt.value)\n      return JSON.stringify(oldSelectedOptions.sort()) !== JSON.stringify(newSelectedOptions.sort())\n    } else if (element instanceof HTMLTextAreaElement) {\n      const oldValue = element.value\n      element.value = element.defaultValue\n      return element.value !== oldValue\n    }\n\n    return false\n  }\n\n  if (element instanceof HTMLInputElement) {\n    // Pass all default values to handle checkboxes and radios correctly\n    return resetInputElement(element, defaultValues)\n  } else if (element instanceof HTMLSelectElement) {\n    return resetSelectElement(element, defaultValues)\n  } else if (element instanceof HTMLTextAreaElement) {\n    const oldValue = element.value\n    element.value = defaultValues[0] !== undefined ? String(defaultValues[0]) : ''\n    return element.value !== oldValue\n  }\n\n  return false\n}\n\nfunction resetFieldElements(\n  elements: Element | RadioNodeList | HTMLCollection,\n  defaultValues: FormDataEntryValue[],\n): boolean {\n  let hasChanged = false\n\n  if (elements instanceof RadioNodeList || elements instanceof HTMLCollection) {\n    // Handle multiple elements with the same name (e.g., radio buttons, checkboxes, array fields)\n    Array.from(elements).forEach((node, index) => {\n      if (node instanceof Element && isFormElement(node)) {\n        if (node instanceof HTMLInputElement && ['checkbox', 'radio'].includes(node.type.toLowerCase())) {\n          // For checkboxes and radios, pass all default values for value-based matching\n          if (resetFormElement(node, defaultValues)) {\n            hasChanged = true\n          }\n        } else {\n          // For other array elements (like text inputs), use index-based matching\n          const indexedDefaultValues =\n            defaultValues[index] !== undefined ? [defaultValues[index]] : [defaultValues[0] ?? null].filter(Boolean)\n\n          if (resetFormElement(node, indexedDefaultValues)) {\n            hasChanged = true\n          }\n        }\n      }\n    })\n  } else if (isFormElement(elements)) {\n    // Handle single element - pass all default values (important for multi-selects)\n    hasChanged = resetFormElement(elements, defaultValues)\n  }\n\n  return hasChanged\n}\n\nexport function resetFormFields(formElement: HTMLFormElement, defaults: FormData, fieldNames?: string[]): void {\n  if (!formElement) {\n    return\n  }\n\n  const resetEntireForm = !fieldNames || fieldNames.length === 0\n\n  // If no specific fields provided, reset the entire form\n  if (resetEntireForm) {\n    // Get all field names from both defaults and form elements (including disabled ones)\n    const formData = new FormData(formElement)\n    const formElementNames = Array.from(formElement.elements)\n      .map((el) => (isFormElement(el) ? el.name : ''))\n      .filter(Boolean)\n    fieldNames = [...new Set([...defaults.keys(), ...formData.keys(), ...formElementNames])]\n  }\n\n  let hasChanged = false\n\n  fieldNames!.forEach((fieldName) => {\n    const elements = formElement.elements.namedItem(fieldName)\n\n    if (elements) {\n      if (resetFieldElements(elements, defaults.getAll(fieldName))) {\n        hasChanged = true\n      }\n    }\n  })\n\n  // Dispatch reset event to notify listeners that the form was reset programmatically\n  if (hasChanged && resetEntireForm) {\n    // Use Symbol in detail so adapters can preventDefault() to avoid Firefox's native reset behavior\n    formElement.dispatchEvent(\n      new CustomEvent('reset', { bubbles: true, cancelable: true, detail: { [FormComponentResetSymbol]: true } }),\n    )\n  }\n}\n"
  },
  {
    "path": "packages/core/src/response.ts",
    "content": "import { AxiosResponse } from 'axios'\nimport { get, isEqual, set } from 'lodash-es'\nimport { config, router } from '.'\nimport dialog from './dialog'\nimport {\n  fireBeforeUpdateEvent,\n  fireErrorEvent,\n  fireFlashEvent,\n  fireInvalidEvent,\n  firePrefetchedEvent,\n  fireSuccessEvent,\n} from './events'\nimport { history } from './history'\nimport modal from './modal'\nimport { page as currentPage } from './page'\nimport Queue from './queue'\nimport { RequestParams } from './requestParams'\nimport { SessionStorage } from './sessionStorage'\nimport { ActiveVisit, ErrorBag, Errors, Page } from './types'\nimport { hrefToUrl, isSameUrlWithoutHash, setHashIfSameUrl } from './url'\n\nconst queue = new Queue<Promise<boolean | void>>()\n\nexport class Response {\n  protected wasPrefetched = false\n\n  constructor(\n    protected requestParams: RequestParams,\n    protected response: AxiosResponse,\n    protected originatingPage: Page,\n  ) {}\n\n  public static create(params: RequestParams, response: AxiosResponse, originatingPage: Page): Response {\n    return new Response(params, response, originatingPage)\n  }\n\n  public async handlePrefetch() {\n    if (isSameUrlWithoutHash(this.requestParams.all().url, window.location)) {\n      this.handle()\n    }\n  }\n\n  public async handle() {\n    return queue.add(() => this.process())\n  }\n\n  public async process() {\n    if (this.requestParams.all().prefetch) {\n      this.wasPrefetched = true\n      this.requestParams.all().prefetch = false\n\n      this.requestParams.all().onPrefetched(this.response, this.requestParams.all())\n      firePrefetchedEvent(this.response, this.requestParams.all())\n\n      return Promise.resolve()\n    }\n\n    this.requestParams.runCallbacks()\n\n    if (!this.isInertiaResponse()) {\n      return this.handleNonInertiaResponse()\n    }\n\n    await history.processQueue()\n\n    history.preserveUrl = this.requestParams.all().preserveUrl\n\n    await this.setPage()\n\n    const errors = currentPage.get().props.errors || {}\n\n    if (Object.keys(errors).length > 0) {\n      const scopedErrors = this.getScopedErrors(errors)\n\n      fireErrorEvent(scopedErrors)\n\n      return this.requestParams.all().onError(scopedErrors)\n    }\n\n    router.flushByCacheTags(this.requestParams.all().invalidateCacheTags || [])\n\n    if (!this.wasPrefetched) {\n      // We end up here other than from the prefetch cache, so we assume this response is\n      // never than the cached one and therefore flush the cache.\n      router.flush(currentPage.get().url)\n    }\n\n    const { flash } = currentPage.get()\n\n    if (Object.keys(flash).length > 0 && !this.requestParams.isDeferredPropsRequest()) {\n      fireFlashEvent(flash)\n      this.requestParams.all().onFlash(flash)\n    }\n\n    fireSuccessEvent(currentPage.get())\n\n    await this.requestParams.all().onSuccess(currentPage.get())\n\n    history.preserveUrl = false\n  }\n\n  public mergeParams(params: ActiveVisit) {\n    this.requestParams.merge(params)\n  }\n\n  public getPageResponse(): Page {\n    const data = this.getDataFromResponse(this.response.data)\n\n    // Only spread if data is an object (not a string like HTML error pages)\n    if (typeof data === 'object') {\n      return (this.response.data = { ...data, flash: data.flash ?? {} })\n    }\n\n    return (this.response.data = data)\n  }\n\n  protected async handleNonInertiaResponse() {\n    if (this.isLocationVisit()) {\n      const locationUrl = hrefToUrl(this.getHeader('x-inertia-location'))\n\n      setHashIfSameUrl(this.requestParams.all().url, locationUrl)\n\n      return this.locationVisit(locationUrl)\n    }\n\n    const response = {\n      ...this.response,\n      data: this.getDataFromResponse(this.response.data),\n    }\n\n    if (fireInvalidEvent(response)) {\n      return config.get('future.useDialogForErrorModal') ? dialog.show(response.data) : modal.show(response.data)\n    }\n  }\n\n  protected isInertiaResponse(): boolean {\n    return this.hasHeader('x-inertia')\n  }\n\n  protected hasStatus(status: number): boolean {\n    return this.response.status === status\n  }\n\n  protected getHeader(header: string): string {\n    return this.response.headers[header]\n  }\n\n  protected hasHeader(header: string): boolean {\n    return this.getHeader(header) !== undefined\n  }\n\n  protected isLocationVisit(): boolean {\n    return this.hasStatus(409) && this.hasHeader('x-inertia-location')\n  }\n\n  /**\n   * @link https://inertiajs.com/redirects#external-redirects\n   */\n  protected locationVisit(url: URL): boolean | void {\n    try {\n      SessionStorage.set(SessionStorage.locationVisitKey, {\n        preserveScroll: this.requestParams.all().preserveScroll === true,\n      })\n\n      if (typeof window === 'undefined') {\n        return\n      }\n\n      if (isSameUrlWithoutHash(window.location, url)) {\n        window.location.reload()\n      } else {\n        window.location.href = url.href\n      }\n    } catch (error) {\n      return false\n    }\n  }\n\n  protected async setPage(): Promise<void> {\n    const pageResponse = this.getPageResponse()\n\n    if (!this.shouldSetPage(pageResponse)) {\n      return Promise.resolve()\n    }\n\n    this.mergeProps(pageResponse)\n    currentPage.mergeOncePropsIntoResponse(pageResponse)\n    this.preserveEqualProps(pageResponse)\n\n    await this.setRememberedState(pageResponse)\n\n    this.requestParams.setPreserveOptions(pageResponse)\n\n    pageResponse.url = history.preserveUrl ? currentPage.get().url : this.pageUrl(pageResponse)\n\n    this.requestParams.all().onBeforeUpdate(pageResponse)\n    fireBeforeUpdateEvent(pageResponse)\n\n    return currentPage.set(pageResponse, {\n      replace: this.requestParams.all().replace,\n      preserveScroll: this.requestParams.all().preserveScroll as boolean,\n      preserveState: this.requestParams.all().preserveState as boolean,\n      viewTransition: this.requestParams.all().viewTransition,\n    })\n  }\n\n  protected getDataFromResponse(response: any): any {\n    if (typeof response !== 'string') {\n      return response\n    }\n\n    try {\n      return JSON.parse(response)\n    } catch (error) {\n      return response\n    }\n  }\n\n  protected shouldSetPage(pageResponse: Page): boolean {\n    if (!this.requestParams.all().async) {\n      // If the request is sync, we should always set the page\n      return true\n    }\n\n    if (this.originatingPage.component !== pageResponse.component) {\n      // We originated from a component but the response re-directed us,\n      // we should respect the redirection and set the page\n      return true\n    }\n\n    // At this point, if the originating request component is different than the current component,\n    // the user has since navigated and we should discard the response\n    if (this.originatingPage.component !== currentPage.get().component) {\n      return false\n    }\n\n    const originatingUrl = hrefToUrl(this.originatingPage.url)\n    const currentPageUrl = hrefToUrl(currentPage.get().url)\n\n    // We have the same component, let's double-check the URL\n    // If we're no longer on the same path name (e.g. /users/1 -> /users/2), we should not set the page\n    return originatingUrl.origin === currentPageUrl.origin && originatingUrl.pathname === currentPageUrl.pathname\n  }\n\n  protected pageUrl(pageResponse: Page) {\n    const responseUrl = hrefToUrl(pageResponse.url)\n\n    setHashIfSameUrl(this.requestParams.all().url, responseUrl)\n\n    return responseUrl.pathname + responseUrl.search + responseUrl.hash\n  }\n\n  protected preserveEqualProps(pageResponse: Page): void {\n    if (pageResponse.component !== currentPage.get().component || config.get('future.preserveEqualProps') !== true) {\n      return\n    }\n\n    const currentPageProps = currentPage.get().props\n\n    Object.entries(pageResponse.props).forEach(([key, value]) => {\n      if (isEqual(value, currentPageProps[key])) {\n        pageResponse.props[key] = currentPageProps[key]\n      }\n    })\n  }\n\n  protected mergeProps(pageResponse: Page): void {\n    if (!this.requestParams.isPartial() || pageResponse.component !== currentPage.get().component) {\n      return\n    }\n\n    const propsToAppend = pageResponse.mergeProps || []\n    const propsToPrepend = pageResponse.prependProps || []\n    const propsToDeepMerge = pageResponse.deepMergeProps || []\n    const matchPropsOn = pageResponse.matchPropsOn || []\n\n    const mergeProp = (prop: string, shouldAppend: boolean) => {\n      const currentProp = get(currentPage.get().props, prop)\n      const incomingProp = get(pageResponse.props, prop)\n\n      if (Array.isArray(incomingProp)) {\n        const newArray = this.mergeOrMatchItems(\n          (currentProp || []) as any[],\n          incomingProp,\n          prop,\n          matchPropsOn,\n          shouldAppend,\n        )\n\n        set(pageResponse.props, prop, newArray)\n      } else if (typeof incomingProp === 'object' && incomingProp !== null) {\n        const newObject = {\n          ...(currentProp || {}),\n          ...incomingProp,\n        }\n\n        set(pageResponse.props, prop, newObject)\n      }\n    }\n\n    propsToAppend.forEach((prop) => mergeProp(prop, true))\n    propsToPrepend.forEach((prop) => mergeProp(prop, false))\n\n    propsToDeepMerge.forEach((prop) => {\n      const currentProp = currentPage.get().props[prop]\n      const incomingProp = pageResponse.props[prop]\n\n      // Function to recursively merge objects and arrays\n      const deepMerge = (target: any, source: any, matchProp: string) => {\n        if (Array.isArray(source)) {\n          return this.mergeOrMatchItems(target, source, matchProp, matchPropsOn)\n        }\n\n        if (typeof source === 'object' && source !== null) {\n          // Merge objects by iterating over keys\n          return Object.keys(source).reduce(\n            (acc, key) => {\n              acc[key] = deepMerge(target ? target[key] : undefined, source[key], `${matchProp}.${key}`)\n              return acc\n            },\n            { ...target },\n          )\n        }\n\n        // If the source is neither an array nor an object, simply return the it\n        return source\n      }\n\n      // Apply the deep merge and update the page response\n      pageResponse.props[prop] = deepMerge(currentProp, incomingProp, prop)\n    })\n\n    pageResponse.props = { ...currentPage.get().props, ...pageResponse.props }\n\n    if (this.requestParams.isDeferredPropsRequest()) {\n      const currentErrors = currentPage.get().props.errors\n\n      if (currentErrors && Object.keys(currentErrors).length > 0) {\n        // Preserve existing errors during deferred props requests\n        pageResponse.props.errors = currentErrors\n      }\n    }\n\n    // Preserve the existing scrollProps\n    if (currentPage.get().scrollProps) {\n      pageResponse.scrollProps = {\n        ...(currentPage.get().scrollProps || {}),\n        ...(pageResponse.scrollProps || {}),\n      }\n    }\n\n    // Preserve the existing onceProps\n    if (currentPage.hasOnceProps()) {\n      pageResponse.onceProps = {\n        ...(currentPage.get().onceProps || {}),\n        ...(pageResponse.onceProps || {}),\n      }\n    }\n\n    // Preserve flash data and merge with new flash data on non-deferred requests\n    pageResponse.flash = {\n      ...currentPage.get().flash,\n      ...(this.requestParams.isDeferredPropsRequest() ? {} : pageResponse.flash),\n    }\n\n    const currentOriginalDeferred = currentPage.get().initialDeferredProps\n    if (currentOriginalDeferred && Object.keys(currentOriginalDeferred).length > 0) {\n      pageResponse.initialDeferredProps = currentOriginalDeferred\n    }\n  }\n\n  protected mergeOrMatchItems(\n    existingItems: any[],\n    newItems: any[],\n    matchProp: string,\n    matchPropsOn: string[],\n    shouldAppend = true,\n  ) {\n    const items = Array.isArray(existingItems) ? existingItems : []\n\n    // Find the matching key for this specific property path\n    const matchingKey = matchPropsOn.find((key) => {\n      const keyPath = key.split('.').slice(0, -1).join('.')\n\n      return keyPath === matchProp\n    })\n\n    // If no matching key is configured, simply concatenate the arrays\n    if (!matchingKey) {\n      return shouldAppend ? [...items, ...newItems] : [...newItems, ...items]\n    }\n\n    // Extract the property name we'll use to match items (e.g., 'id' from 'users.data.id')\n    const uniqueProperty = matchingKey.split('.').pop() || ''\n\n    // Create a map of new items by their unique property lookups\n    const newItemsMap = new Map()\n\n    newItems.forEach((item) => {\n      if (this.hasUniqueProperty(item, uniqueProperty)) {\n        newItemsMap.set(item[uniqueProperty], item)\n      }\n    })\n\n    return shouldAppend\n      ? this.appendWithMatching(items, newItems, newItemsMap, uniqueProperty)\n      : this.prependWithMatching(items, newItems, newItemsMap, uniqueProperty)\n  }\n\n  protected appendWithMatching(\n    existingItems: any[],\n    newItems: any[],\n    newItemsMap: Map<any, any>,\n    uniqueProperty: string,\n  ): any[] {\n    // Update existing items with new values, keep non-matching items\n    const updatedExisting = existingItems.map((item) => {\n      if (this.hasUniqueProperty(item, uniqueProperty) && newItemsMap.has(item[uniqueProperty])) {\n        return newItemsMap.get(item[uniqueProperty])\n      }\n\n      return item\n    })\n\n    // Filter new items to only include those not already in existing items\n    const newItemsToAdd = newItems.filter((item) => {\n      if (!this.hasUniqueProperty(item, uniqueProperty)) {\n        return true // Always add items without unique property\n      }\n\n      return !existingItems.some(\n        (existing) =>\n          this.hasUniqueProperty(existing, uniqueProperty) && existing[uniqueProperty] === item[uniqueProperty],\n      )\n    })\n\n    return [...updatedExisting, ...newItemsToAdd]\n  }\n\n  protected prependWithMatching(\n    existingItems: any[],\n    newItems: any[],\n    newItemsMap: Map<any, any>,\n    uniqueProperty: string,\n  ): any[] {\n    // Filter existing items, keeping only those not being updated\n    const untouchedExisting = existingItems.filter((item) => {\n      if (this.hasUniqueProperty(item, uniqueProperty)) {\n        return !newItemsMap.has(item[uniqueProperty])\n      }\n\n      return true\n    })\n\n    return [...newItems, ...untouchedExisting]\n  }\n\n  protected hasUniqueProperty(item: any, property: string): boolean {\n    return item && typeof item === 'object' && property in item\n  }\n\n  protected async setRememberedState(pageResponse: Page): Promise<void> {\n    const rememberedState = await history.getState<Page['rememberedState']>(history.rememberedState, {})\n\n    if (\n      this.requestParams.all().preserveState &&\n      rememberedState &&\n      pageResponse.component === currentPage.get().component\n    ) {\n      pageResponse.rememberedState = rememberedState\n    }\n  }\n\n  protected getScopedErrors(errors: Errors & ErrorBag): Errors {\n    if (!this.requestParams.all().errorBag) {\n      return errors\n    }\n\n    return errors[this.requestParams.all().errorBag || ''] || {}\n  }\n}\n"
  },
  {
    "path": "packages/core/src/router.ts",
    "content": "import { cloneDeep, get, set } from 'lodash-es'\nimport { progress } from '.'\nimport { config } from './config'\nimport { eventHandler } from './eventHandler'\nimport { fireBeforeEvent, fireFlashEvent } from './events'\nimport { history } from './history'\nimport { InitialVisit } from './initialVisit'\nimport { page as currentPage } from './page'\nimport { polls } from './polls'\nimport { prefetchedRequests } from './prefetched'\nimport Queue from './queue'\nimport { Request } from './request'\nimport { RequestParams } from './requestParams'\nimport { RequestStream } from './requestStream'\nimport { Scroll } from './scroll'\nimport {\n  ActiveVisit,\n  ClientSideVisitOptions,\n  Component,\n  FlashData,\n  GlobalEvent,\n  GlobalEventNames,\n  GlobalEventResult,\n  InFlightPrefetch,\n  Method,\n  Page,\n  PageFlashData,\n  PendingVisit,\n  PendingVisitOptions,\n  PollOptions,\n  PrefetchedResponse,\n  PrefetchOptions,\n  ReloadOptions,\n  RequestPayload,\n  RouterInitParams,\n  UrlMethodPair,\n  Visit,\n  VisitCallbacks,\n  VisitHelperOptions,\n  VisitOptions,\n} from './types'\nimport {\n  hrefToUrl,\n  isSameUrlWithoutHash,\n  isSameUrlWithoutQueryOrHash,\n  isUrlMethodPair,\n  transformUrlAndData,\n} from './url'\n\nexport class Router {\n  protected syncRequestStream = new RequestStream({\n    maxConcurrent: 1,\n    interruptible: true,\n  })\n\n  protected asyncRequestStream = new RequestStream({\n    maxConcurrent: Infinity,\n    interruptible: false,\n  })\n\n  protected clientVisitQueue = new Queue<Promise<void>>()\n\n  public init<ComponentType = Component>({\n    initialPage,\n    resolveComponent,\n    swapComponent,\n    onFlash,\n  }: RouterInitParams<ComponentType>): void {\n    currentPage.init({\n      initialPage,\n      resolveComponent,\n      swapComponent,\n      onFlash,\n    })\n\n    InitialVisit.handle()\n\n    eventHandler.init()\n\n    eventHandler.on('missingHistoryItem', () => {\n      if (typeof window !== 'undefined') {\n        this.visit(window.location.href, { preserveState: true, preserveScroll: true, replace: true })\n      }\n    })\n\n    eventHandler.on('loadDeferredProps', (deferredProps: Page['deferredProps']) => {\n      this.loadDeferredProps(deferredProps)\n    })\n\n    eventHandler.on('historyQuotaExceeded', (url) => {\n      window.location.href = url\n    })\n  }\n\n  public get<T extends RequestPayload = RequestPayload>(\n    url: URL | string | UrlMethodPair,\n    data: T = {} as T,\n    options: VisitHelperOptions<T> = {},\n  ): void {\n    return this.visit(url, { ...options, method: 'get', data })\n  }\n\n  public post<T extends RequestPayload = RequestPayload>(\n    url: URL | string | UrlMethodPair,\n    data: T = {} as T,\n    options: VisitHelperOptions<T> = {},\n  ): void {\n    return this.visit(url, { preserveState: true, ...options, method: 'post', data })\n  }\n\n  public put<T extends RequestPayload = RequestPayload>(\n    url: URL | string | UrlMethodPair,\n    data: T = {} as T,\n    options: VisitHelperOptions<T> = {},\n  ): void {\n    return this.visit(url, { preserveState: true, ...options, method: 'put', data })\n  }\n\n  public patch<T extends RequestPayload = RequestPayload>(\n    url: URL | string | UrlMethodPair,\n    data: T = {} as T,\n    options: VisitHelperOptions<T> = {},\n  ): void {\n    return this.visit(url, { preserveState: true, ...options, method: 'patch', data })\n  }\n\n  public delete<T extends RequestPayload = RequestPayload>(\n    url: URL | string | UrlMethodPair,\n    options: Omit<VisitOptions<T>, 'method'> = {},\n  ): void {\n    return this.visit(url, { preserveState: true, ...options, method: 'delete' })\n  }\n\n  public reload<T extends RequestPayload = RequestPayload>(options: ReloadOptions<T> = {}): void {\n    return this.doReload(options)\n  }\n\n  protected doReload<T extends RequestPayload = RequestPayload>(\n    options: ReloadOptions<T> & {\n      deferredProps?: boolean\n    } = {},\n  ): void {\n    if (typeof window === 'undefined') {\n      return\n    }\n\n    return this.visit(window.location.href, {\n      ...options,\n      preserveScroll: true,\n      preserveState: true,\n      async: true,\n      headers: {\n        ...(options.headers || {}),\n        'Cache-Control': 'no-cache',\n      },\n    })\n  }\n\n  public remember(data: unknown, key = 'default'): void {\n    history.remember(data, key)\n  }\n\n  public restore<T = unknown>(key = 'default'): T | undefined {\n    return history.restore(key) as T | undefined\n  }\n\n  public on<TEventName extends GlobalEventNames>(\n    type: TEventName,\n    callback: (event: GlobalEvent<TEventName>) => GlobalEventResult<TEventName>,\n  ): VoidFunction {\n    if (typeof window === 'undefined') {\n      return () => {}\n    }\n\n    return eventHandler.onGlobalEvent(type, callback)\n  }\n\n  /**\n   * @deprecated Use cancelAll() instead.\n   */\n  public cancel(): void {\n    this.syncRequestStream.cancelInFlight()\n  }\n\n  public cancelAll({ async = true, prefetch = true, sync = true } = {}): void {\n    if (async) {\n      this.asyncRequestStream.cancelInFlight({ prefetch })\n    }\n\n    if (sync) {\n      this.syncRequestStream.cancelInFlight()\n    }\n  }\n\n  public poll(interval: number, requestOptions: ReloadOptions = {}, options: PollOptions = {}) {\n    return polls.add(interval, () => this.reload(requestOptions), {\n      autoStart: options.autoStart ?? true,\n      keepAlive: options.keepAlive ?? false,\n    })\n  }\n\n  public visit<T extends RequestPayload = RequestPayload>(\n    href: string | URL | UrlMethodPair,\n    options: VisitOptions<T> = {},\n  ): void {\n    const visit: PendingVisit = this.getPendingVisit(href, {\n      ...options,\n      showProgress: options.showProgress ?? !options.async,\n    } as VisitOptions)\n\n    const events = this.getVisitEvents(options as VisitOptions)\n\n    // If either of these return false, we don't want to continue\n    if (events.onBefore(visit) === false || !fireBeforeEvent(visit)) {\n      return\n    }\n\n    const currentPageUrl = hrefToUrl(currentPage.get().url)\n    const isPartialReload = visit.only.length > 0 || visit.except.length > 0 || visit.reset.length > 0\n\n    // For partial reloads, only compare the base URL (origin + pathname) to allow\n    // concurrent requests with different query params to the same page\n    const isSamePage = isPartialReload\n      ? isSameUrlWithoutQueryOrHash(visit.url, currentPageUrl)\n      : isSameUrlWithoutHash(visit.url, currentPageUrl)\n\n    if (!isSamePage) {\n      // Only cancel non-prefetch requests (deferred props + partial reloads)\n      this.asyncRequestStream.cancelInFlight({ prefetch: false })\n    }\n\n    if (!visit.async) {\n      this.syncRequestStream.interruptInFlight()\n    }\n\n    if (!currentPage.isCleared() && !visit.preserveUrl) {\n      // Save scroll regions for the current page\n      Scroll.save()\n    }\n\n    const requestParams: PendingVisit & VisitCallbacks = {\n      ...visit,\n      ...events,\n    }\n\n    const prefetched = prefetchedRequests.get(requestParams)\n\n    if (prefetched) {\n      progress.reveal(prefetched.inFlight)\n      prefetchedRequests.use(prefetched, requestParams)\n    } else {\n      progress.reveal(true)\n      const requestStream = visit.async ? this.asyncRequestStream : this.syncRequestStream\n      requestStream.send(Request.create(requestParams, currentPage.get()))\n    }\n  }\n\n  public getCached(\n    href: string | URL | UrlMethodPair,\n    options: VisitOptions = {},\n  ): InFlightPrefetch | PrefetchedResponse | null {\n    return prefetchedRequests.findCached(this.getPrefetchParams(href, options))\n  }\n\n  public flush(href: string | URL | UrlMethodPair, options: VisitOptions = {}): void {\n    prefetchedRequests.remove(this.getPrefetchParams(href, options))\n  }\n\n  public flushAll(): void {\n    prefetchedRequests.removeAll()\n  }\n\n  public flushByCacheTags(tags: string | string[]): void {\n    prefetchedRequests.removeByTags(Array.isArray(tags) ? tags : [tags])\n  }\n\n  public getPrefetching(\n    href: string | URL | UrlMethodPair,\n    options: VisitOptions = {},\n  ): InFlightPrefetch | PrefetchedResponse | null {\n    return prefetchedRequests.findInFlight(this.getPrefetchParams(href, options))\n  }\n\n  public prefetch(\n    href: string | URL | UrlMethodPair,\n    options: VisitOptions = {},\n    prefetchOptions: Partial<PrefetchOptions> = {},\n  ) {\n    const method: Method = options.method ?? (isUrlMethodPair(href) ? href.method : 'get')\n\n    if (method !== 'get') {\n      throw new Error('Prefetch requests must use the GET method')\n    }\n\n    const visit: PendingVisit = this.getPendingVisit(href, {\n      ...options,\n      async: true,\n      showProgress: false,\n      prefetch: true,\n      viewTransition: false,\n    })\n\n    const visitUrl = visit.url.origin + visit.url.pathname + visit.url.search\n    const currentUrl = window.location.origin + window.location.pathname + window.location.search\n\n    if (visitUrl === currentUrl) {\n      // Don't prefetch the current page, you're already on it\n      return\n    }\n\n    const events = this.getVisitEvents(options)\n\n    // If either of these return false, we don't want to continue\n    if (events.onBefore(visit) === false || !fireBeforeEvent(visit)) {\n      return\n    }\n\n    progress.hide()\n\n    this.asyncRequestStream.interruptInFlight()\n\n    const requestParams: PendingVisit & VisitCallbacks = {\n      ...visit,\n      ...events,\n    }\n\n    const ensureCurrentPageIsSet = (): Promise<void> => {\n      return new Promise((resolve) => {\n        const checkIfPageIsDefined = () => {\n          if (currentPage.get()) {\n            resolve()\n          } else {\n            setTimeout(checkIfPageIsDefined, 50)\n          }\n        }\n\n        checkIfPageIsDefined()\n      })\n    }\n\n    ensureCurrentPageIsSet().then(() => {\n      prefetchedRequests.add(\n        requestParams,\n        (params) => {\n          this.asyncRequestStream.send(Request.create(params, currentPage.get()))\n        },\n        {\n          cacheFor: config.get('prefetch.cacheFor'),\n          cacheTags: [],\n          ...prefetchOptions,\n        },\n      )\n    })\n  }\n\n  public clearHistory(): void {\n    history.clear()\n  }\n\n  public decryptHistory(): Promise<Page> {\n    return history.decrypt()\n  }\n\n  public resolveComponent(component: string): Promise<Component> {\n    return currentPage.resolve(component)\n  }\n\n  public replace<TProps = Page['props']>(params: ClientSideVisitOptions<TProps>): void {\n    this.clientVisit(params, { replace: true })\n  }\n\n  public replaceProp<TProps = Page['props']>(\n    name: string,\n    value: unknown | ((oldValue: unknown, props: TProps) => unknown),\n    options?: Pick<ClientSideVisitOptions, 'onError' | 'onFinish' | 'onSuccess'>,\n  ): void {\n    this.replace({\n      preserveScroll: true,\n      preserveState: true,\n      props(currentProps) {\n        const newValue = typeof value === 'function' ? value(get(currentProps, name), currentProps) : value\n\n        return set(cloneDeep(currentProps), name, newValue)\n      },\n      ...(options || {}),\n    })\n  }\n\n  public appendToProp<TProps = Page['props']>(\n    name: string,\n    value: unknown | unknown[] | ((oldValue: unknown, props: TProps) => unknown | unknown[]),\n    options?: Pick<ClientSideVisitOptions, 'onError' | 'onFinish' | 'onSuccess'>,\n  ): void {\n    this.replaceProp(\n      name,\n      (currentValue: unknown, currentProps: TProps) => {\n        const newValue = typeof value === 'function' ? value(currentValue, currentProps) : value\n\n        if (!Array.isArray(currentValue)) {\n          currentValue = currentValue !== undefined ? [currentValue] : []\n        }\n\n        return [...(currentValue as unknown[]), newValue]\n      },\n      options,\n    )\n  }\n\n  public prependToProp<TProps = Page['props']>(\n    name: string,\n    value: unknown | unknown[] | ((oldValue: unknown, props: TProps) => unknown | unknown[]),\n    options?: Pick<ClientSideVisitOptions, 'onError' | 'onFinish' | 'onSuccess'>,\n  ): void {\n    this.replaceProp(\n      name,\n      (currentValue: unknown, currentProps: TProps) => {\n        const newValue = typeof value === 'function' ? value(currentValue, currentProps) : value\n\n        if (!Array.isArray(currentValue)) {\n          currentValue = currentValue !== undefined ? [currentValue] : []\n        }\n\n        return [newValue, ...(currentValue as unknown[])]\n      },\n      options,\n    )\n  }\n\n  public push<TProps = Page['props']>(params: ClientSideVisitOptions<TProps>): void {\n    this.clientVisit(params)\n  }\n\n  public flash<TFlash extends PageFlashData = PageFlashData>(\n    keyOrData: string | ((flash: FlashData) => TFlash) | TFlash,\n    value?: unknown,\n  ): void {\n    const current = currentPage.get().flash\n    let flash: PageFlashData\n\n    if (typeof keyOrData === 'function') {\n      flash = keyOrData(current)\n    } else if (typeof keyOrData === 'string') {\n      flash = { ...current, [keyOrData]: value }\n    } else if (keyOrData && Object.keys(keyOrData).length) {\n      flash = { ...current, ...keyOrData }\n    } else {\n      return\n    }\n\n    currentPage.setFlash(flash)\n\n    if (Object.keys(flash).length) {\n      fireFlashEvent(flash)\n    }\n  }\n\n  protected clientVisit<TProps = Page['props']>(\n    params: ClientSideVisitOptions<TProps>,\n    { replace = false }: { replace?: boolean } = {},\n  ): void {\n    this.clientVisitQueue.add(() => this.performClientVisit(params, { replace }))\n  }\n\n  protected performClientVisit<TProps = Page['props']>(\n    params: ClientSideVisitOptions<TProps>,\n    { replace = false }: { replace?: boolean } = {},\n  ): Promise<void> {\n    const current = currentPage.get()\n\n    const onceProps =\n      typeof params.props === 'function'\n        ? Object.fromEntries(\n            Object.values(current.onceProps ?? {}).map((onceProp) => [onceProp.prop, current.props[onceProp.prop]]),\n          )\n        : {}\n\n    const props =\n      typeof params.props === 'function'\n        ? params.props(current.props as TProps, onceProps as Partial<TProps>)\n        : (params.props ?? current.props)\n\n    const flash = typeof params.flash === 'function' ? params.flash(current.flash) : params.flash\n\n    const { viewTransition, onError, onFinish, onFlash, onSuccess, ...pageParams } = params\n\n    const page = {\n      ...current,\n      ...pageParams,\n      flash: flash ?? {},\n      props: props as Page['props'],\n    }\n\n    const preserveScroll = RequestParams.resolvePreserveOption(params.preserveScroll ?? false, page)\n    const preserveState = RequestParams.resolvePreserveOption(params.preserveState ?? false, page)\n\n    return currentPage\n      .set(page, {\n        replace,\n        preserveScroll,\n        preserveState,\n        viewTransition,\n      })\n      .then(() => {\n        const currentFlash = currentPage.get().flash\n\n        if (Object.keys(currentFlash).length > 0) {\n          fireFlashEvent(currentFlash)\n          onFlash?.(currentFlash)\n        }\n\n        const errors = currentPage.get().props.errors || {}\n\n        if (Object.keys(errors).length === 0) {\n          onSuccess?.(currentPage.get())\n          return\n        }\n\n        const scopedErrors = params.errorBag ? errors[params.errorBag || ''] || {} : errors\n\n        onError?.(scopedErrors)\n      })\n      .finally(() => onFinish?.(params))\n  }\n\n  protected getPrefetchParams(href: string | URL | UrlMethodPair, options: VisitOptions): ActiveVisit {\n    return {\n      ...this.getPendingVisit(href, {\n        ...options,\n        async: true,\n        showProgress: false,\n        prefetch: true,\n        viewTransition: false,\n      }),\n      ...this.getVisitEvents(options),\n    }\n  }\n\n  protected getPendingVisit(\n    href: string | URL | UrlMethodPair,\n    options: VisitOptions,\n    pendingVisitOptions: Partial<PendingVisitOptions> = {},\n  ): PendingVisit {\n    if (isUrlMethodPair(href)) {\n      const urlMethodPair = href\n      href = urlMethodPair.url\n      options.method = options.method ?? urlMethodPair.method\n    }\n\n    const defaultVisitOptionsCallback = config.get('visitOptions')\n\n    const configuredOptions = defaultVisitOptionsCallback\n      ? defaultVisitOptionsCallback(href.toString(), cloneDeep(options)) || {}\n      : {}\n\n    const mergedOptions: Visit = {\n      method: 'get',\n      data: {},\n      replace: false,\n      preserveScroll: false,\n      preserveState: false,\n      only: [],\n      except: [],\n      headers: {},\n      errorBag: '',\n      forceFormData: false,\n      queryStringArrayFormat: 'brackets',\n      async: false,\n      showProgress: true,\n      fresh: false,\n      reset: [],\n      preserveUrl: false,\n      prefetch: false,\n      invalidateCacheTags: [],\n      viewTransition: false,\n      ...options,\n      ...configuredOptions,\n    }\n\n    const [url, _data] = transformUrlAndData(\n      href,\n      mergedOptions.data,\n      mergedOptions.method,\n      mergedOptions.forceFormData,\n      mergedOptions.queryStringArrayFormat,\n    )\n\n    const visit = {\n      cancelled: false,\n      completed: false,\n      interrupted: false,\n      ...mergedOptions,\n      ...pendingVisitOptions,\n      url,\n      data: _data,\n    }\n\n    if (visit.prefetch) {\n      visit.headers['Purpose'] = 'prefetch'\n    }\n\n    return visit\n  }\n\n  protected getVisitEvents(options: VisitOptions): VisitCallbacks {\n    return {\n      onCancelToken: options.onCancelToken || (() => {}),\n      onBefore: options.onBefore || (() => {}),\n      onBeforeUpdate: options.onBeforeUpdate || (() => {}),\n      onStart: options.onStart || (() => {}),\n      onProgress: options.onProgress || (() => {}),\n      onFinish: options.onFinish || (() => {}),\n      onCancel: options.onCancel || (() => {}),\n      onSuccess: options.onSuccess || (() => {}),\n      onError: options.onError || (() => {}),\n      onFlash: options.onFlash || (() => {}),\n      onPrefetched: options.onPrefetched || (() => {}),\n      onPrefetching: options.onPrefetching || (() => {}),\n    }\n  }\n\n  protected loadDeferredProps(deferred: Page['deferredProps']): void {\n    if (deferred) {\n      Object.entries(deferred).forEach(([_, group]) => {\n        this.doReload({ only: group, deferredProps: true })\n      })\n    }\n  }\n}\n"
  },
  {
    "path": "packages/core/src/scroll.ts",
    "content": "import { requestAnimationFrame } from './domUtils'\nimport { history } from './history'\nimport { ScrollRegion } from './types'\n\nconst isServer = typeof window === 'undefined'\nconst isFirefox = !isServer && /Firefox/i.test(window.navigator.userAgent)\n\nexport class Scroll {\n  public static save(): void {\n    history.saveScrollPositions(this.getScrollRegions())\n  }\n\n  public static getScrollRegions(): ScrollRegion[] {\n    return Array.from(this.regions()).map((region) => ({\n      top: region.scrollTop,\n      left: region.scrollLeft,\n    }))\n  }\n\n  protected static regions(): NodeListOf<Element> {\n    return document.querySelectorAll('[scroll-region]')\n  }\n\n  public static scrollToTop(): void {\n    if (isFirefox && getComputedStyle(document.documentElement).scrollBehavior === 'smooth') {\n      // Firefox has a bug with smooth scrolling to (0, 0) when navigating to pages that are shorter than the previous page.\n      return requestAnimationFrame(() => window.scrollTo(0, 0), 2)\n    }\n\n    window.scrollTo(0, 0)\n  }\n\n  public static reset(): void {\n    const anchorHash = isServer ? null : window.location.hash\n\n    if (!anchorHash) {\n      // Reset the document scroll position if there is no hash.\n      this.scrollToTop()\n    }\n\n    this.regions().forEach((region) => {\n      if (typeof region.scrollTo === 'function') {\n        region.scrollTo(0, 0)\n      } else {\n        region.scrollTop = 0\n        region.scrollLeft = 0\n      }\n    })\n\n    this.save()\n    this.scrollToAnchor()\n  }\n\n  public static scrollToAnchor(): void {\n    const anchorHash = isServer ? null : window.location.hash\n\n    if (anchorHash) {\n      // We're using a setTimeout() here as a workaround for a bug in the React adapter where the\n      // rendering isn't completing fast enough, causing the anchor link to not be scrolled to.\n      setTimeout(() => {\n        const anchorElement = document.getElementById(anchorHash.slice(1))\n        anchorElement ? anchorElement.scrollIntoView() : this.scrollToTop()\n      })\n    }\n  }\n\n  public static restore(scrollRegions: ScrollRegion[]): void {\n    if (isServer) {\n      return\n    }\n\n    window.requestAnimationFrame(() => {\n      this.restoreDocument()\n      this.restoreScrollRegions(scrollRegions)\n    })\n  }\n\n  public static restoreScrollRegions(scrollRegions: ScrollRegion[]): void {\n    if (isServer) {\n      return\n    }\n\n    this.regions().forEach((region: Element, index: number) => {\n      const scrollPosition = scrollRegions[index]\n\n      if (!scrollPosition) {\n        return\n      }\n\n      if (typeof region.scrollTo === 'function') {\n        region.scrollTo(scrollPosition.left, scrollPosition.top)\n      } else {\n        region.scrollTop = scrollPosition.top\n        region.scrollLeft = scrollPosition.left\n      }\n    })\n  }\n\n  public static restoreDocument(): void {\n    const scrollPosition = history.getDocumentScrollPosition()\n    window.scrollTo(scrollPosition.left, scrollPosition.top)\n  }\n\n  public static onScroll(event: Event): void {\n    const target = event.target as Element\n\n    if (typeof target.hasAttribute === 'function' && target.hasAttribute('scroll-region')) {\n      this.save()\n    }\n  }\n\n  public static onWindowScroll(): void {\n    history.saveDocumentScrollPosition({\n      top: window.scrollY,\n      left: window.scrollX,\n    })\n  }\n}\n"
  },
  {
    "path": "packages/core/src/server.ts",
    "content": "import { createServer, IncomingMessage } from 'http'\nimport cluster from 'node:cluster'\nimport { availableParallelism } from 'node:os'\nimport * as process from 'process'\nimport { InertiaAppResponse, Page } from './types'\n\ntype AppCallback = (page: Page) => InertiaAppResponse\ntype RouteHandler = (request: IncomingMessage) => Promise<unknown>\ntype ServerOptions = {\n  port?: number\n  cluster?: boolean\n}\ntype Port = number\n\nconst readableToString: (readable: IncomingMessage) => Promise<string> = (readable) =>\n  new Promise((resolve, reject) => {\n    let data = ''\n    readable.on('data', (chunk) => (data += chunk))\n    readable.on('end', () => resolve(data))\n    readable.on('error', (err) => reject(err))\n  })\n\nexport default (render: AppCallback, options?: Port | ServerOptions): void => {\n  const _port = typeof options === 'number' ? options : (options?.port ?? 13714)\n  const _useCluster = typeof options === 'object' && options?.cluster !== undefined ? options.cluster : false\n\n  const log = (message: string) => {\n    console.log(\n      _useCluster && !cluster.isPrimary\n        ? `[${cluster.worker?.id ?? 'N/A'} / ${cluster.worker?.process?.pid ?? 'N/A'}] ${message}`\n        : message,\n    )\n  }\n\n  if (_useCluster && cluster.isPrimary) {\n    log('Primary Inertia SSR server process started...')\n\n    for (let i = 0; i < availableParallelism(); i++) {\n      cluster.fork()\n    }\n\n    cluster.on('message', (_worker, message) => {\n      if (message === 'shutdown') {\n        for (const id in cluster.workers) {\n          cluster.workers[id]?.kill()\n        }\n\n        process.exit()\n      }\n    })\n\n    return\n  }\n\n  const routes: Record<string, RouteHandler> = {\n    '/health': async () => ({ status: 'OK', timestamp: Date.now() }),\n    '/shutdown': async () => {\n      if (cluster.isWorker) {\n        process.send?.('shutdown')\n      }\n\n      process.exit()\n    },\n    '/render': async (request) => render(JSON.parse(await readableToString(request))),\n    '/404': async () => ({ status: 'NOT_FOUND', timestamp: Date.now() }),\n  }\n\n  createServer(async (request, response) => {\n    const dispatchRoute = routes[<string>request.url] || routes['/404']\n\n    try {\n      response.writeHead(200, { 'Content-Type': 'application/json', Server: 'Inertia.js SSR' })\n      response.write(JSON.stringify(await dispatchRoute(request)))\n    } catch (e) {\n      console.error(e)\n    }\n\n    response.end()\n  }).listen(_port, () => log('Inertia SSR server started.'))\n\n  log(`Starting SSR server on port ${_port}...`)\n}\n"
  },
  {
    "path": "packages/core/src/sessionStorage.ts",
    "content": "export class SessionStorage {\n  public static locationVisitKey = 'inertiaLocationVisit'\n\n  public static set(key: string, value: any): void {\n    if (typeof window !== 'undefined') {\n      window.sessionStorage.setItem(key, JSON.stringify(value))\n    }\n  }\n\n  public static get(key: string): any {\n    if (typeof window !== 'undefined') {\n      return JSON.parse(window.sessionStorage.getItem(key) || 'null')\n    }\n  }\n\n  public static merge(key: string, value: any): void {\n    const existing = this.get(key)\n\n    if (existing === null) {\n      this.set(key, value)\n    } else {\n      this.set(key, { ...existing, ...value })\n    }\n  }\n\n  public static remove(key: string): void {\n    if (typeof window !== 'undefined') {\n      window.sessionStorage.removeItem(key)\n    }\n  }\n\n  public static removeNested(key: string, nestedKey: string): void {\n    const existing = this.get(key)\n\n    if (existing !== null) {\n      delete existing[nestedKey]\n\n      this.set(key, existing)\n    }\n  }\n\n  public static exists(key: string): boolean {\n    try {\n      return this.get(key) !== null\n    } catch (error) {\n      return false\n    }\n  }\n\n  public static clear(): void {\n    if (typeof window !== 'undefined') {\n      window.sessionStorage.clear()\n    }\n  }\n}\n"
  },
  {
    "path": "packages/core/src/time.ts",
    "content": "import { CacheForOption, TimeUnit } from './types'\n\nconst conversionMap: Record<TimeUnit, number> = {\n  ms: 1,\n  s: 1000,\n  m: 1000 * 60,\n  h: 1000 * 60 * 60,\n  d: 1000 * 60 * 60 * 24,\n}\n\nexport const timeToMs = (time: CacheForOption): number => {\n  if (typeof time === 'number') {\n    return time\n  }\n\n  for (const [unit, conversion] of Object.entries(conversionMap)) {\n    if (time.endsWith(unit)) {\n      return parseFloat(time) * conversion\n    }\n  }\n\n  return parseInt(time)\n}\n"
  },
  {
    "path": "packages/core/src/types.ts",
    "content": "import { AxiosProgressEvent, AxiosResponse } from 'axios'\nimport { NamedInputEvent, ValidationConfig, Validator } from 'laravel-precognition'\nimport { Response } from './response'\n\ndeclare module 'axios' {\n  export interface AxiosProgressEvent {\n    percentage: number | undefined\n  }\n}\n\nexport interface PageFlashData {\n  [key: string]: unknown\n}\n\nexport type DefaultInertiaConfig = {\n  errorValueType: string\n  flashDataType: PageFlashData\n  sharedPageProps: PageProps\n}\n/**\n * Designed to allow overriding of some core types using TypeScript\n * interface declaration merging.\n *\n * @see {@link DefaultInertiaConfig} for keys to override\n * @example\n * ```ts\n * // global.d.ts\n * import '@inertiajs/core'\n *\n * declare module '@inertiajs/core' {\n *   export interface InertiaConfig {\n *     errorValueType: string[]\n *     flashDataType: {\n *       toast?: { type: 'success' | 'error', message: string }\n *     }\n *     sharedPageProps: {\n *       auth: { user: User | null }\n *     }\n *   }\n * }\n * ```\n */\nexport interface InertiaConfig {}\nexport type InertiaConfigFor<Key extends keyof DefaultInertiaConfig> = Key extends keyof InertiaConfig\n  ? InertiaConfig[Key]\n  : DefaultInertiaConfig[Key]\nexport type ErrorValue = InertiaConfigFor<'errorValueType'>\nexport type FlashData = InertiaConfigFor<'flashDataType'>\nexport type SharedPageProps = InertiaConfigFor<'sharedPageProps'>\n\nexport type Errors = Record<string, ErrorValue>\nexport type ErrorBag = Record<string, Errors>\n\nexport type FormDataConvertibleValue = Blob | FormDataEntryValue | Date | boolean | number | null | undefined\nexport type FormDataConvertible =\n  | Array<FormDataConvertible>\n  | { [key: string]: FormDataConvertible }\n  | FormDataConvertibleValue\n\nexport type FormDataType<T extends object> = {\n  [K in keyof T]: T[K] extends infer U\n    ? U extends FormDataConvertibleValue\n      ? U\n      : U extends (...args: unknown[]) => unknown\n        ? never\n        : U extends object | Array<unknown>\n          ? FormDataType<U>\n          : never\n    : never\n}\n\n/**\n * Uses `0 extends 1 & T` to detect `any` type and prevent infinite recursion.\n */\nexport type FormDataKeys<T> = T extends Function | FormDataConvertibleValue\n  ? never\n  : T extends unknown[]\n    ? ArrayFormDataKeys<T>\n    : T extends object\n      ? ObjectFormDataKeys<T>\n      : never\n\n/**\n * Helper type for array form data keys\n */\ntype ArrayFormDataKeys<T extends unknown[]> = number extends T['length']\n  ? // Dynamic array\n      | `${number}`\n      | (0 extends 1 & T[number]\n          ? never\n          : T[number] extends FormDataConvertibleValue\n            ? never\n            : `${number}.${FormDataKeys<T[number]>}`)\n  : // Tuple with known length\n      | Extract<keyof T, `${number}`>\n      | {\n          [Key in Extract<keyof T, `${number}`>]: 0 extends 1 & T[Key]\n            ? never\n            : T[Key] extends FormDataConvertibleValue\n              ? never\n              : `${Key & string}.${FormDataKeys<T[Key & string] & string>}`\n        }[Extract<keyof T, `${number}`>]\n\n/**\n * Helper type for object form data keys\n */\ntype ObjectFormDataKeys<T extends object> = string extends keyof T\n  ? string\n  :\n      | Extract<keyof T, string>\n      | {\n          [Key in Extract<keyof T, string>]: 0 extends 1 & T[Key]\n            ? never\n            : T[Key] extends FormDataConvertibleValue\n              ? never\n              : T[Key] extends any[]\n                ? `${Key}.${FormDataKeys<T[Key]> & string}`\n                : T[Key] extends Record<string, any>\n                  ? `${Key}.${FormDataKeys<T[Key]> & string}`\n                  : Exclude<T[Key], null | undefined> extends any[]\n                    ? never\n                    : Exclude<T[Key], null | undefined> extends Record<string, any>\n                      ? `${Key}.${FormDataKeys<Exclude<T[Key], null | undefined>> & string}`\n                      : never\n        }[Extract<keyof T, string>]\n\ntype PartialFormDataErrors<T> = {\n  [K in string extends keyof T ? string : Extract<keyof FormDataError<T>, string>]?: ErrorValue\n}\n\nexport type FormDataErrors<T> = PartialFormDataErrors<T> & {\n  [K in keyof PartialFormDataErrors<T>]: NonNullable<PartialFormDataErrors<T>[K]>\n}\n\nexport type FormDataValues<T, K extends FormDataKeys<T>> = K extends `${infer P}.${infer Rest}`\n  ? T extends unknown[]\n    ? P extends `${infer I extends number}`\n      ? Rest extends FormDataKeys<T[I]>\n        ? FormDataValues<T[I], Rest>\n        : never\n      : never\n    : P extends keyof T\n      ? Rest extends FormDataKeys<T[P]>\n        ? FormDataValues<T[P], Rest>\n        : never\n      : never\n  : K extends keyof T\n    ? T[K]\n    : T extends unknown[]\n      ? T[K & number]\n      : never\n\nexport type FormDataError<T> = Partial<Record<FormDataKeys<T>, ErrorValue>>\n\nexport type Method = 'get' | 'post' | 'put' | 'patch' | 'delete'\n\nexport type RequestPayload = Record<string, FormDataConvertible> | FormData\n\nexport interface PageProps {\n  [key: string]: unknown\n}\n\nexport type ScrollProp = {\n  pageName: string\n  previousPage: number | string | null\n  nextPage: number | string | null\n  currentPage: number | string | null\n  reset: boolean\n}\n\nexport interface Page<SharedProps extends PageProps = PageProps> {\n  component: string\n  props: PageProps &\n    SharedProps & {\n      errors: Errors & ErrorBag\n      deferred?: Record<string, VisitOptions['only']>\n    }\n  url: string\n  version: string | null\n  clearHistory: boolean\n  encryptHistory: boolean\n  deferredProps?: Record<string, NonNullable<VisitOptions['only']>>\n  initialDeferredProps?: Record<string, NonNullable<VisitOptions['only']>>\n  mergeProps?: string[]\n  prependProps?: string[]\n  deepMergeProps?: string[]\n  matchPropsOn?: string[]\n  scrollProps?: Record<keyof PageProps, ScrollProp>\n  flash: FlashData\n  onceProps?: Record<\n    string,\n    {\n      prop: keyof PageProps\n      expiresAt?: number | null\n    }\n  >\n\n  /** @internal */\n  rememberedState: Record<string, unknown>\n}\n\nexport type ScrollRegion = {\n  top: number\n  left: number\n}\n\nexport interface ClientSideVisitOptions<TProps = Page['props']> {\n  component?: Page['component']\n  url?: Page['url']\n  props?: ((props: TProps, onceProps: Partial<TProps>) => PageProps) | PageProps\n  flash?: ((flash: FlashData) => PageFlashData) | PageFlashData\n  clearHistory?: Page['clearHistory']\n  encryptHistory?: Page['encryptHistory']\n  preserveScroll?: VisitOptions['preserveScroll']\n  preserveState?: VisitOptions['preserveState']\n  errorBag?: string | null\n  viewTransition?: VisitOptions['viewTransition']\n  onError?: (errors: Errors) => void\n  onFinish?: (visit: ClientSideVisitOptions<TProps>) => void\n  onFlash?: (flash: FlashData) => void\n  onSuccess?: (page: Page<SharedPageProps>) => void\n}\n\nexport type PageResolver = (name: string) => Component\n\nexport type PageHandler<ComponentType = Component> = ({\n  component,\n  page,\n  preserveState,\n}: {\n  component: ComponentType\n  page: Page\n  preserveState: boolean\n}) => Promise<unknown>\n\nexport type PreserveStateOption = boolean | 'errors' | ((page: Page) => boolean)\n\nexport type QueryStringArrayFormatOption = 'indices' | 'brackets'\n\nexport type Progress = AxiosProgressEvent\n\nexport type LocationVisit = {\n  preserveScroll: boolean\n}\n\nexport type CancelToken = {\n  cancel: VoidFunction\n}\n\nexport type CancelTokenCallback = (cancelToken: CancelToken) => void\n\nexport type Visit<T extends RequestPayload = RequestPayload> = {\n  method: Method\n  data: T\n  replace: boolean\n  preserveScroll: PreserveStateOption\n  preserveState: PreserveStateOption\n  only: Array<string>\n  except: Array<string>\n  headers: Record<string, string>\n  errorBag: string | null\n  forceFormData: boolean\n  queryStringArrayFormat: QueryStringArrayFormatOption\n  async: boolean\n  showProgress: boolean\n  prefetch: boolean\n  fresh: boolean\n  reset: string[]\n  preserveUrl: boolean\n  invalidateCacheTags: string | string[]\n  viewTransition: boolean | ((viewTransition: ViewTransition) => void)\n}\n\nexport type GlobalEventsMap<T extends RequestPayload = RequestPayload> = {\n  before: {\n    parameters: [PendingVisit<T>]\n    details: {\n      visit: PendingVisit<T>\n    }\n    result: boolean | void\n  }\n  start: {\n    parameters: [PendingVisit<T>]\n    details: {\n      visit: PendingVisit<T>\n    }\n    result: void\n  }\n  progress: {\n    parameters: [Progress | undefined]\n    details: {\n      progress: Progress | undefined\n    }\n    result: void\n  }\n  finish: {\n    parameters: [ActiveVisit<T>]\n    details: {\n      visit: ActiveVisit<T>\n    }\n    result: void\n  }\n  cancel: {\n    parameters: []\n    details: {}\n    result: void\n  }\n  beforeUpdate: {\n    parameters: [Page<SharedPageProps>]\n    details: {\n      page: Page<SharedPageProps>\n    }\n    result: void\n  }\n  navigate: {\n    parameters: [Page<SharedPageProps>]\n    details: {\n      page: Page<SharedPageProps>\n    }\n    result: void\n  }\n  success: {\n    parameters: [Page<SharedPageProps>]\n    details: {\n      page: Page<SharedPageProps>\n    }\n    result: void\n  }\n  error: {\n    parameters: [Errors]\n    details: {\n      errors: Errors\n    }\n    result: void\n  }\n  invalid: {\n    parameters: [AxiosResponse]\n    details: {\n      response: AxiosResponse\n    }\n    result: boolean | void\n  }\n  exception: {\n    parameters: [Error]\n    details: {\n      exception: Error\n    }\n    result: boolean | void\n  }\n  prefetched: {\n    parameters: [AxiosResponse, ActiveVisit<T>]\n    details: {\n      response: AxiosResponse\n      fetchedAt: number\n      visit: ActiveVisit<T>\n    }\n    result: void\n  }\n  prefetching: {\n    parameters: [ActiveVisit<T>]\n    details: {\n      visit: ActiveVisit<T>\n    }\n    result: void\n  }\n  flash: {\n    parameters: [Page['flash']]\n    details: {\n      flash: Page['flash']\n    }\n    result: void\n  }\n}\n\nexport type PageEvent = 'newComponent' | 'firstLoad'\n\nexport type GlobalEventNames<T extends RequestPayload = RequestPayload> = keyof GlobalEventsMap<T>\n\nexport type GlobalEvent<\n  TEventName extends GlobalEventNames<T>,\n  T extends RequestPayload = RequestPayload,\n> = CustomEvent<GlobalEventDetails<TEventName, T>>\n\nexport type GlobalEventParameters<\n  TEventName extends GlobalEventNames<T>,\n  T extends RequestPayload = RequestPayload,\n> = GlobalEventsMap<T>[TEventName]['parameters']\n\nexport type GlobalEventResult<\n  TEventName extends GlobalEventNames<T>,\n  T extends RequestPayload = RequestPayload,\n> = GlobalEventsMap<T>[TEventName]['result']\n\nexport type GlobalEventDetails<\n  TEventName extends GlobalEventNames<T>,\n  T extends RequestPayload = RequestPayload,\n> = GlobalEventsMap<T>[TEventName]['details']\n\nexport type GlobalEventTrigger<TEventName extends GlobalEventNames<T>, T extends RequestPayload = RequestPayload> = (\n  ...params: GlobalEventParameters<TEventName, T>\n) => GlobalEventResult<TEventName, T>\n\nexport type GlobalEventCallback<TEventName extends GlobalEventNames<T>, T extends RequestPayload = RequestPayload> = (\n  ...params: GlobalEventParameters<TEventName, T>\n) => GlobalEventResult<TEventName, T>\n\nexport type InternalEvent = 'missingHistoryItem' | 'loadDeferredProps' | 'historyQuotaExceeded'\n\nexport type VisitCallbacks<T extends RequestPayload = RequestPayload> = {\n  onCancelToken: CancelTokenCallback\n  onBefore: GlobalEventCallback<'before', T>\n  onBeforeUpdate: GlobalEventCallback<'beforeUpdate', T>\n  onStart: GlobalEventCallback<'start', T>\n  onProgress: GlobalEventCallback<'progress', T>\n  onFinish: GlobalEventCallback<'finish', T>\n  onCancel: GlobalEventCallback<'cancel', T>\n  onSuccess: GlobalEventCallback<'success', T>\n  onError: GlobalEventCallback<'error', T>\n  onFlash: GlobalEventCallback<'flash', T>\n  onPrefetched: GlobalEventCallback<'prefetched', T>\n  onPrefetching: GlobalEventCallback<'prefetching', T>\n}\n\nexport type VisitOptions<T extends RequestPayload = RequestPayload> = Partial<Visit<T> & VisitCallbacks<T>>\n\nexport type ReloadOptions<T extends RequestPayload = RequestPayload> = Omit<\n  VisitOptions<T>,\n  'preserveScroll' | 'preserveState'\n>\n\nexport type PollOptions = {\n  keepAlive?: boolean\n  autoStart?: boolean\n}\n\nexport type VisitHelperOptions<T extends RequestPayload = RequestPayload> = Omit<VisitOptions<T>, 'method' | 'data'>\n\nexport type RouterInitParams<ComponentType = Component> = {\n  initialPage: Page\n  resolveComponent: PageResolver\n  swapComponent: PageHandler<ComponentType>\n  onFlash?: (flash: Page['flash']) => void\n}\n\nexport type PendingVisitOptions = {\n  url: URL\n  completed: boolean\n  cancelled: boolean\n  interrupted: boolean\n}\n\nexport type PendingVisit<T extends RequestPayload = RequestPayload> = Visit<T> & PendingVisitOptions\n\nexport type ActiveVisit<T extends RequestPayload = RequestPayload> = PendingVisit<T> & Required<VisitOptions<T>>\n\nexport type InternalActiveVisit = ActiveVisit & {\n  onPrefetchResponse?: (response: Response) => void\n  onPrefetchError?: (error: Error) => void\n  deferredProps?: boolean\n}\n\nexport type VisitId = unknown\nexport type Component = unknown\n\ntype FirstLevelOptional<T> = {\n  [K in keyof T]?: T[K] extends object ? { [P in keyof T[K]]?: T[K][P] } : T[K]\n}\n\ninterface CreateInertiaAppOptions<TComponentResolver, TSetupOptions, TSetupReturn, TAdditionalInertiaAppConfig> {\n  resolve: TComponentResolver\n  setup: (options: TSetupOptions) => TSetupReturn\n  title?: HeadManagerTitleCallback\n  defaults?: FirstLevelOptional<InertiaAppConfig & TAdditionalInertiaAppConfig>\n}\n\nexport interface CreateInertiaAppOptionsForCSR<\n  SharedProps extends PageProps,\n  TComponentResolver,\n  TSetupOptions,\n  TSetupReturn,\n  TAdditionalInertiaAppConfig,\n> extends CreateInertiaAppOptions<TComponentResolver, TSetupOptions, TSetupReturn, TAdditionalInertiaAppConfig> {\n  id?: string\n  page?: Page<SharedProps>\n  progress?:\n    | false\n    | {\n        delay?: number\n        color?: string\n        includeCSS?: boolean\n        showSpinner?: boolean\n      }\n  render?: undefined\n}\n\nexport interface CreateInertiaAppOptionsForSSR<\n  SharedProps extends PageProps,\n  TComponentResolver,\n  TSetupOptions,\n  TSetupReturn,\n  TAdditionalInertiaAppConfig,\n> extends CreateInertiaAppOptions<TComponentResolver, TSetupOptions, TSetupReturn, TAdditionalInertiaAppConfig> {\n  id?: undefined\n  page: Page<SharedProps>\n  progress?: undefined\n  render: unknown\n}\n\nexport type InertiaAppSSRResponse = { head: string[]; body: string }\nexport type InertiaAppResponse = Promise<InertiaAppSSRResponse | void>\n\nexport type HeadManagerTitleCallback = (title: string) => string\nexport type HeadManagerOnUpdateCallback = (elements: string[]) => void\nexport type HeadManager = {\n  forceUpdate: () => void\n  createProvider: () => {\n    preferredAttribute: () => 'data-inertia' | 'inertia'\n    reconnect: () => void\n    update: HeadManagerOnUpdateCallback\n    disconnect: () => void\n  }\n}\n\nexport type LinkPrefetchOption = 'mount' | 'hover' | 'click'\n\nexport type TimeUnit = 'ms' | 's' | 'm' | 'h' | 'd'\nexport type CacheForOption = number | `${number}${TimeUnit}` | string\n\nexport type PrefetchOptions = {\n  cacheFor: CacheForOption | CacheForOption[]\n  cacheTags: string | string[]\n}\n\nexport type InertiaAppConfig = {\n  form: {\n    recentlySuccessfulDuration: number\n    forceIndicesArrayFormatInFormData: boolean\n    withAllErrors: boolean\n  }\n  // experimental: {\n  //   /* not guaranteed */\n  // }\n  future: {\n    /* planned defaults */\n    preserveEqualProps: boolean\n    useDataInertiaHeadAttribute: boolean\n    useDialogForErrorModal: boolean\n    useScriptElementForInitialPage: boolean\n  }\n  prefetch: {\n    cacheFor: CacheForOption | CacheForOption[]\n    hoverDelay: number\n  }\n  visitOptions?: (href: string, options: VisitOptions) => VisitOptions\n}\n\nexport interface LinkComponentBaseProps extends Partial<\n  Pick<\n    Visit<RequestPayload>,\n    | 'data'\n    | 'method'\n    | 'replace'\n    | 'preserveScroll'\n    | 'preserveState'\n    | 'preserveUrl'\n    | 'only'\n    | 'except'\n    | 'headers'\n    | 'queryStringArrayFormat'\n    | 'async'\n    | 'viewTransition'\n  > &\n    VisitCallbacks & {\n      href: string | UrlMethodPair\n      prefetch: boolean | LinkPrefetchOption | LinkPrefetchOption[]\n      cacheFor: CacheForOption | CacheForOption[]\n      cacheTags: string | string[]\n    }\n> {}\n\ntype PrefetchObject = {\n  params: ActiveVisit\n  response: Promise<Response>\n}\n\nexport type InFlightPrefetch = PrefetchObject & {\n  staleTimestamp: null\n  inFlight: true\n}\n\nexport type PrefetchCancellationToken = {\n  isCancelled: boolean\n  cancel: () => void\n}\n\nexport type PrefetchedResponse = PrefetchObject & {\n  staleTimestamp: number\n  timestamp: number\n  expiresAt: number\n  singleUse: boolean\n  inFlight: false\n  tags: string[]\n}\n\nexport type PrefetchRemovalTimer = {\n  params: ActiveVisit\n  timer: number\n}\n\nexport type ProgressSettings = {\n  minimum: number\n  easing: string\n  positionUsing: 'translate3d' | 'translate' | 'margin'\n  speed: number\n  trickle: boolean\n  trickleSpeed: number\n  showSpinner: boolean\n  barSelector: string\n  spinnerSelector: string\n  parent: string\n  template: string\n  includeCSS: boolean\n  color: string\n}\n\nexport type UrlMethodPair = { url: string; method: Method }\n\nexport type UseFormTransformCallback<TForm> = (data: TForm) => object\nexport type UseFormWithPrecognitionArguments =\n  | [Method | (() => Method), string | (() => string)]\n  | [UrlMethodPair | (() => UrlMethodPair)]\n\ntype UseFormInertiaArguments<TForm> =\n  | []\n  | [data: TForm | (() => TForm)]\n  | [rememberKey: string, data: TForm | (() => TForm)]\ntype UseFormPrecognitionArguments<TForm> =\n  | [urlMethodPair: UrlMethodPair | (() => UrlMethodPair), data: TForm | (() => TForm)]\n  | [method: Method | (() => Method), url: string | (() => string), data: TForm | (() => TForm)]\nexport type UseFormArguments<TForm> = UseFormInertiaArguments<TForm> | UseFormPrecognitionArguments<TForm>\n\nexport type UseFormSubmitOptions = Omit<VisitOptions, 'data'>\nexport type UseFormSubmitArguments =\n  | [Method, string, UseFormSubmitOptions?]\n  | [UrlMethodPair, UseFormSubmitOptions?]\n  | [UseFormSubmitOptions?]\n\nexport type FormComponentOptions = Pick<\n  VisitOptions,\n  'preserveScroll' | 'preserveState' | 'preserveUrl' | 'replace' | 'only' | 'except' | 'reset' | 'viewTransition'\n>\n\nexport type FormComponentProps = Partial<\n  Pick<Visit, 'headers' | 'queryStringArrayFormat' | 'errorBag' | 'showProgress' | 'invalidateCacheTags'> &\n    Omit<VisitCallbacks, 'onPrefetched' | 'onPrefetching'>\n> & {\n  method?: Method | Uppercase<Method>\n  action?: string | UrlMethodPair\n  transform?: (data: Record<string, FormDataConvertible>) => Record<string, FormDataConvertible>\n  options?: FormComponentOptions\n  onSubmitComplete?: (props: FormComponentonSubmitCompleteArguments) => void\n  disableWhileProcessing?: boolean\n  resetOnSuccess?: boolean | string[]\n  resetOnError?: boolean | string[]\n  setDefaultsOnSuccess?: boolean\n  validateFiles?: boolean\n  validationTimeout?: number\n  withAllErrors?: boolean | null\n}\n\nexport type FormComponentMethods = {\n  clearErrors: (...fields: string[]) => void\n  resetAndClearErrors: (...fields: string[]) => void\n  setError: {\n    (field: string, value: ErrorValue): void\n    (errors: Record<string, ErrorValue>): void\n  }\n  reset: (...fields: string[]) => void\n  submit: () => void\n  defaults: () => void\n  getData: () => Record<string, FormDataConvertible>\n  getFormData: () => FormData\n  valid: (field: string) => boolean\n  invalid: (field: string) => boolean\n  validate: (field?: string | NamedInputEvent | ValidationConfig, config?: ValidationConfig) => void\n  touch: (...fields: string[]) => void\n  touched: (field?: string) => boolean\n  validator: () => Validator\n}\n\nexport type FormComponentonSubmitCompleteArguments = Pick<FormComponentMethods, 'reset' | 'defaults'>\n\nexport type FormComponentState = {\n  errors: Record<string, ErrorValue>\n  hasErrors: boolean\n  processing: boolean\n  progress: Progress | null\n  wasSuccessful: boolean\n  recentlySuccessful: boolean\n  isDirty: boolean\n  validating: boolean\n}\n\nexport type FormComponentSlotProps = FormComponentMethods & FormComponentState\n\nexport type FormComponentRef = FormComponentSlotProps\n\nexport interface UseInfiniteScrollOptions {\n  // Core data\n  getPropName: () => string\n  inReverseMode: () => boolean\n  shouldFetchNext: () => boolean\n  shouldFetchPrevious: () => boolean\n  shouldPreserveUrl: () => boolean\n\n  // Elements\n  getTriggerMargin: () => number\n  getStartElement: () => HTMLElement\n  getEndElement: () => HTMLElement\n  getItemsElement: () => HTMLElement\n  getScrollableParent: () => HTMLElement | null\n\n  // Callbacks\n  onBeforePreviousRequest: () => void\n  onBeforeNextRequest: () => void\n  onCompletePreviousRequest: () => void\n  onCompleteNextRequest: () => void\n  onDataReset?: () => void\n}\n\nexport interface UseInfiniteScrollDataManager {\n  getLastLoadedPage: () => number | string | null\n  getPageName: () => string\n  getRequestCount: () => number\n  hasPrevious: () => boolean\n  hasNext: () => boolean\n  fetchNext: (reloadOptions?: ReloadOptions) => void\n  fetchPrevious: (reloadOptions?: ReloadOptions) => void\n  removeEventListener: () => void\n}\n\nexport interface UseInfiniteScrollElementManager {\n  setupObservers: () => void\n  enableTriggers: () => void\n  disableTriggers: () => void\n  refreshTriggers: () => void\n  flushAll: () => void\n  processManuallyAddedElements: () => void\n  processServerLoadedElements: (loadedPage: string | number | null) => void\n}\n\nexport interface UseInfiniteScrollProps {\n  dataManager: UseInfiniteScrollDataManager\n  elementManager: UseInfiniteScrollElementManager\n  flush: () => void\n}\n\nexport interface InfiniteScrollSlotProps {\n  loading: boolean\n  loadingPrevious: boolean\n  loadingNext: boolean\n}\n\nexport interface InfiniteScrollActionSlotProps {\n  loading: boolean\n  loadingPrevious: boolean\n  loadingNext: boolean\n  fetch: () => void\n  autoMode: boolean\n  manualMode: boolean\n  hasMore: boolean\n  hasPrevious: boolean\n  hasNext: boolean\n}\n\nexport interface InfiniteScrollRef {\n  fetchNext: (reloadOptions?: ReloadOptions) => void\n  fetchPrevious: (reloadOptions?: ReloadOptions) => void\n  hasPrevious: () => boolean\n  hasNext: () => boolean\n}\n\nexport interface InfiniteScrollComponentBaseProps {\n  data: string\n  buffer?: number\n  as?: string\n  manual?: boolean\n  manualAfter?: number\n  preserveUrl?: boolean\n  reverse?: boolean\n  autoScroll?: boolean\n  onlyNext?: boolean\n  onlyPrevious?: boolean\n}\n\ndeclare global {\n  interface DocumentEventMap {\n    'inertia:before': GlobalEvent<'before'>\n    'inertia:start': GlobalEvent<'start'>\n    'inertia:progress': GlobalEvent<'progress'>\n    'inertia:success': GlobalEvent<'success'>\n    'inertia:error': GlobalEvent<'error'>\n    'inertia:invalid': GlobalEvent<'invalid'>\n    'inertia:exception': GlobalEvent<'exception'>\n    'inertia:finish': GlobalEvent<'finish'>\n    'inertia:beforeUpdate': GlobalEvent<'beforeUpdate'>\n    'inertia:navigate': GlobalEvent<'navigate'>\n    'inertia:flash': GlobalEvent<'flash'>\n  }\n}\n"
  },
  {
    "path": "packages/core/src/url.ts",
    "content": "import * as qs from 'qs'\nimport { config } from './config'\nimport { hasFiles } from './files'\nimport { isFormData, objectToFormData } from './formData'\nimport type {\n  FormDataConvertible,\n  Method,\n  QueryStringArrayFormatOption,\n  RequestPayload,\n  UrlMethodPair,\n  VisitOptions,\n} from './types'\n\nexport function hrefToUrl(href: string | URL): URL {\n  return new URL(href.toString(), typeof window === 'undefined' ? undefined : window.location.toString())\n}\n\nexport const transformUrlAndData = (\n  href: string | URL,\n  data: RequestPayload,\n  method: Method,\n  forceFormData: VisitOptions['forceFormData'],\n  queryStringArrayFormat: VisitOptions['queryStringArrayFormat'],\n): [URL, RequestPayload] => {\n  let url = typeof href === 'string' ? hrefToUrl(href) : href\n\n  if ((hasFiles(data) || forceFormData) && !isFormData(data)) {\n    if (config.get('form.forceIndicesArrayFormatInFormData')) {\n      queryStringArrayFormat = 'indices'\n    }\n\n    data = objectToFormData(data, new FormData(), null, queryStringArrayFormat)\n  }\n\n  if (isFormData(data)) {\n    return [url, data]\n  }\n\n  const [_href, _data] = mergeDataIntoQueryString(method, url, data, queryStringArrayFormat)\n\n  return [hrefToUrl(_href), _data]\n}\n\ntype MergeDataIntoQueryStringDataReturnType<T extends RequestPayload> =\n  T extends Record<string, FormDataConvertible> ? Record<string, FormDataConvertible> : RequestPayload\n\nexport function mergeDataIntoQueryString<T extends RequestPayload>(\n  method: Method,\n  href: URL | string,\n  data: T,\n  qsArrayFormat: QueryStringArrayFormatOption = 'brackets',\n): [string, MergeDataIntoQueryStringDataReturnType<T>] {\n  const hasDataForQueryString = method === 'get' && !isFormData(data) && Object.keys(data).length > 0\n  const hasHost = urlHasProtocol(href.toString())\n  const hasAbsolutePath = hasHost || href.toString().startsWith('/') || href.toString() === ''\n  const hasRelativePath = !hasAbsolutePath && !href.toString().startsWith('#') && !href.toString().startsWith('?')\n  const hasRelativePathWithDotPrefix = /^[.]{1,2}([/]|$)/.test(href.toString())\n  const hasSearch = href.toString().includes('?') || hasDataForQueryString\n  const hasHash = href.toString().includes('#')\n\n  const url = new URL(href.toString(), typeof window === 'undefined' ? 'http://localhost' : window.location.toString())\n\n  if (hasDataForQueryString) {\n    // If the original URL contains indices notation (e.g. [0], [1]), preserve it.\n    // Indices notation cannot be converted to brackets notation without data loss.\n    // We decode the URL search first because browsers may return URL-encoded brackets (%5B0%5D).\n    const hasIndices = /\\[\\d+\\]/.test(decodeURIComponent(url.search))\n    const parseOptions = { ignoreQueryPrefix: true, allowSparse: true }\n    url.search = qs.stringify(\n      { ...qs.parse(url.search, parseOptions), ...data },\n      {\n        encodeValuesOnly: true,\n        arrayFormat: hasIndices ? 'indices' : qsArrayFormat,\n      },\n    )\n  }\n\n  return [\n    [\n      hasHost ? `${url.protocol}//${url.host}` : '',\n      hasAbsolutePath ? url.pathname : '',\n      hasRelativePath ? url.pathname.substring(hasRelativePathWithDotPrefix ? 0 : 1) : '',\n      hasSearch ? url.search : '',\n      hasHash ? url.hash : '',\n    ].join(''),\n    (hasDataForQueryString ? {} : data) as MergeDataIntoQueryStringDataReturnType<T>,\n  ]\n}\n\nexport function urlWithoutHash(url: URL | Location): URL {\n  url = new URL(url.href)\n  url.hash = ''\n  return url\n}\n\nexport const setHashIfSameUrl = (originUrl: URL | Location, destinationUrl: URL | Location) => {\n  if (originUrl.hash && !destinationUrl.hash && urlWithoutHash(originUrl).href === destinationUrl.href) {\n    destinationUrl.hash = originUrl.hash\n  }\n}\n\nexport const isSameUrlWithoutHash = (url1: URL | Location, url2: URL | Location): boolean => {\n  return urlWithoutHash(url1).href === urlWithoutHash(url2).href\n}\n\nexport const isSameUrlWithoutQueryOrHash = (url1: URL | Location, url2: URL | Location): boolean => {\n  return url1.origin === url2.origin && url1.pathname === url2.pathname\n}\n\nexport function isUrlMethodPair(href: unknown): href is UrlMethodPair {\n  return href !== null && typeof href === 'object' && href !== undefined && 'url' in href && 'method' in href\n}\n\nexport function urlHasProtocol(url: string): boolean {\n  return /^([a-z][a-z0-9+.-]*:)?\\/\\/[^/]/i.test(url)\n}\n\nexport function urlToString(url: URL | string, absolute: boolean): string {\n  const urlObj = typeof url === 'string' ? hrefToUrl(url) : url\n\n  return absolute\n    ? `${urlObj.protocol}//${urlObj.host}${urlObj.pathname}${urlObj.search}${urlObj.hash}`\n    : `${urlObj.pathname}${urlObj.search}${urlObj.hash}`\n}\n"
  },
  {
    "path": "packages/core/src/useFormUtils.ts",
    "content": "import { NamedInputEvent, ValidationConfig } from 'laravel-precognition'\nimport {\n  FormDataType,\n  Method,\n  UrlMethodPair,\n  UseFormArguments,\n  UseFormSubmitArguments,\n  UseFormSubmitOptions,\n} from './types'\nimport { isUrlMethodPair } from './url'\n\nexport class UseFormUtils {\n  /**\n   * Creates a callback that returns a UrlMethodPair.\n   *\n   * createWayfinderCallback(urlMethodPair)\n   * createWayfinderCallback(method, url)\n   * createWayfinderCallback(() => urlMethodPair)\n   * createWayfinderCallback(() => method, () => url)\n   */\n  public static createWayfinderCallback(\n    ...args: [UrlMethodPair | (() => UrlMethodPair)] | [Method | (() => Method), string | (() => string)]\n  ): () => UrlMethodPair {\n    return () => {\n      if (args.length === 1) {\n        // Wayfinder object, return as-is or call function...\n        return isUrlMethodPair(args[0]) ? args[0] : args[0]()\n      }\n\n      // Separate method and url, reconstruct Wayfinder object...\n      return {\n        method: typeof args[0] === 'function' ? args[0]() : args[0],\n        url: typeof args[1] === 'function' ? args[1]() : args[1],\n      }\n    }\n  }\n\n  /**\n   * Parses all useForm() arguments into { rememberKey, data, precognitionEndpoint }.\n   *\n   * useForm()\n   * useForm(data)\n   * useForm(rememberKey, data)\n   * useForm(method, url, data)\n   * useForm(urlMethodPair, data)\n   *\n   */\n  public static parseUseFormArguments<TForm extends FormDataType<TForm>>(\n    ...args: UseFormArguments<TForm>\n  ): {\n    rememberKey: string | null\n    data: TForm | (() => TForm)\n    precognitionEndpoint: (() => UrlMethodPair) | null\n  } {\n    if (args.length === 0) {\n      // Empty form: useForm()\n      return {\n        rememberKey: null,\n        data: {} as TForm,\n        precognitionEndpoint: null,\n      }\n    }\n\n    if (args.length === 1) {\n      // Basic form: useForm(data)\n      return {\n        rememberKey: null,\n        data: args[0],\n        precognitionEndpoint: null,\n      }\n    }\n\n    if (args.length === 2) {\n      if (typeof args[0] === 'string') {\n        // Rememberable form: useForm(rememberKey, data)\n        return {\n          rememberKey: args[0],\n          data: args[1],\n          precognitionEndpoint: null,\n        }\n      }\n\n      // Form with Precognition + Wayfinder: useForm(wayfinder, data)\n      return {\n        rememberKey: null,\n        data: args[1],\n        precognitionEndpoint: this.createWayfinderCallback(args[0]),\n      }\n    }\n\n    // Form with Precognition: useForm(method, url, data)\n    return {\n      rememberKey: null,\n      data: args[2],\n      precognitionEndpoint: this.createWayfinderCallback(args[0], args[1]),\n    }\n  }\n\n  /**\n   * Parses all submission arguments into { method, url, options }.\n   * It uses the Precognition endpoint if no explicit method/url are provided.\n   *\n   * form.submit(method, url)\n   * form.submit(method, url, options)\n   * form.submit(urlMethodPair)\n   * form.submit(urlMethodPair, options)\n   * form.submit()\n   * form.submit(options)\n   */\n  public static parseSubmitArguments(\n    args: UseFormSubmitArguments,\n    precognitionEndpoint: (() => UrlMethodPair) | null,\n  ): { method: Method; url: string; options: UseFormSubmitOptions } {\n    if (args.length === 3 || (args.length === 2 && typeof args[0] === 'string')) {\n      // Explicit method and url provided...\n      return { method: args[0], url: args[1], options: args[2] ?? {} }\n    }\n\n    if (isUrlMethodPair(args[0])) {\n      // Wayfinder object provided...\n      return { ...args[0], options: (args[1] as UseFormSubmitOptions) ?? {} }\n    }\n\n    // Use Precognition endpoint with optional options...\n    return { ...precognitionEndpoint!(), options: (args[0] as UseFormSubmitOptions) ?? {} }\n  }\n\n  /**\n   * Merges headers into the Precognition validate() arguments.\n   */\n  public static mergeHeadersForValidation(\n    field?: string | NamedInputEvent | ValidationConfig,\n    config?: ValidationConfig,\n    headers?: Record<string, string>,\n  ): [string | NamedInputEvent | ValidationConfig | undefined, ValidationConfig | undefined] {\n    const merge = (config: ValidationConfig): ValidationConfig => {\n      config.headers = {\n        ...(headers ?? {}),\n        ...(config.headers ?? {}),\n      }\n\n      return config\n    }\n\n    if (field && typeof field === 'object' && !('target' in field)) {\n      field = merge(field)\n    } else if (config && typeof config === 'object') {\n      config = merge(config)\n    } else if (typeof field === 'string') {\n      config = merge(config ?? {})\n    } else {\n      field = merge(field ?? {})\n    }\n\n    return [field, config]\n  }\n}\n"
  },
  {
    "path": "packages/core/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"rootDir\": \"src\",\n    \"noEmitOnError\": true,\n\n    \"lib\": [\"DOM\", \"DOM.Iterable\", \"ES2020\"],\n    \"target\": \"ES2020\",\n    \"types\": [\"node\"],\n\n    \"declaration\": true,\n    \"declarationDir\": \"types\",\n    \"emitDeclarationOnly\": true,\n\n    \"module\": \"ES2020\",\n    \"moduleResolution\": \"Node\",\n    \"resolveJsonModule\": true,\n    \"allowSyntheticDefaultImports\": true,\n\n    \"noImplicitThis\": false,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"preserveConstEnums\": true,\n    \"removeComments\": false,\n    \"typeRoots\": [\"./node_modules/@types\"],\n    \"strict\": true,\n    \"skipLibCheck\": true\n  }\n}\n"
  },
  {
    "path": "packages/react/.gitignore",
    "content": "dist\ntypes\nnode_modules\npackage-lock.json\nyarn.lock\n"
  },
  {
    "path": "packages/react/LICENSE",
    "content": "MIT License\n\nCopyright (c) Jonathan Reinink <jonathan@reinink.ca>\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": "packages/react/build.js",
    "content": "#!/usr/bin/env node\nimport esbuild from 'esbuild'\nimport { nodeExternalsPlugin } from 'esbuild-node-externals'\nimport { readFileSync } from 'fs'\n\nconst watch = process.argv.slice(1).includes('--watch')\nconst withDeps = process.argv.slice(1).includes('--with-deps')\n\n// For regular builds, externalize all dependencies to keep the bundle size small (using nodeExternalsPlugin).\n// For builds with dependencies, only externalize peer dependencies and bundle everything\n// else so we can check ES2020 compatibility without checking framework code.\nlet externalDependencies = undefined\n\nif (withDeps) {\n  const pkg = JSON.parse(readFileSync('./package.json', 'utf8'))\n  externalDependencies = Object.keys(pkg.peerDependencies || {})\n}\n\nconst config = {\n  bundle: true,\n  minify: false,\n  sourcemap: withDeps ? false : true,\n  target: 'es2020',\n  external: externalDependencies,\n  plugins: [\n    ...(withDeps ? [] : [nodeExternalsPlugin()]),\n    {\n      name: 'inertia',\n      setup(build) {\n        let count = 0\n        build.onEnd((result) => {\n          if (count++ !== 0) {\n            console.log(`Rebuilding ${build.initialOptions.entryPoints} (${build.initialOptions.format})…`)\n          }\n        })\n      },\n    },\n  ],\n}\n\nconst builds = [\n  { entryPoints: ['src/index.ts'], format: 'esm', outfile: 'dist/index.esm.js', platform: 'browser' },\n  { entryPoints: ['src/index.ts'], format: 'cjs', outfile: 'dist/index.js', platform: 'browser' },\n  { entryPoints: ['src/server.ts'], format: 'esm', outfile: 'dist/server.esm.js', platform: 'node' },\n  { entryPoints: ['src/server.ts'], format: 'cjs', outfile: 'dist/server.js', platform: 'node' },\n]\n\nbuilds.forEach(async (build) => {\n  const context = await esbuild.context({ ...config, ...build })\n\n  if (watch) {\n    console.log(`Watching ${build.entryPoints} (${build.format})…`)\n    await context.watch()\n  } else {\n    await context.rebuild()\n    context.dispose()\n    console.log(`Built ${build.entryPoints} (${build.format}) ${withDeps ? '(with-deps)' : ''}…`)\n  }\n})\n"
  },
  {
    "path": "packages/react/package.json",
    "content": "{\n  \"name\": \"@inertiajs/react\",\n  \"version\": \"2.3.18\",\n  \"license\": \"MIT\",\n  \"description\": \"The React adapter for Inertia.js\",\n  \"contributors\": [\n    \"Jonathan Reinink <jonathan@reinink.ca>\",\n    \"Sebastian De Deyne <sebastiandedeyne@gmail.com>\"\n  ],\n  \"homepage\": \"https://inertiajs.com/\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/inertiajs/inertia.git\",\n    \"directory\": \"packages/react\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/inertiajs/inertia/issues\"\n  },\n  \"files\": [\n    \"dist\",\n    \"types\",\n    \"resources\"\n  ],\n  \"type\": \"module\",\n  \"main\": \"dist/index.js\",\n  \"types\": \"types/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./types/index.d.ts\",\n      \"import\": \"./dist/index.esm.js\",\n      \"require\": \"./dist/index.js\"\n    },\n    \"./server\": {\n      \"types\": \"./types/server.d.ts\",\n      \"import\": \"./dist/server.esm.js\",\n      \"require\": \"./dist/server.js\"\n    }\n  },\n  \"typesVersions\": {\n    \"*\": {\n      \"server\": [\n        \"types/server.d.ts\"\n      ]\n    }\n  },\n  \"scripts\": {\n    \"build\": \"pnpm clean && ./build.js && tsc\",\n    \"build:with-deps\": \"./build.js --with-deps\",\n    \"clean\": \"rm -rf types && rm -rf dist\",\n    \"dev\": \"pnpx concurrently -c \\\"#ffcf00,#3178c6\\\" \\\"pnpm dev:build\\\" \\\"pnpm dev:types\\\" --names build,types\",\n    \"dev:build\": \"./build.js --watch\",\n    \"dev:types\": \"tsc --watch --preserveWatchOutput\",\n    \"es2020-check\": \"pnpm build:with-deps && es-check es2020 \\\"dist/index.esm.js\\\" --checkFeatures --module --noCache --verbose\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"^19.2.14\",\n    \"@types/react-dom\": \"^19.2.3\",\n    \"axios\": \"^1.13.5\",\n    \"es-check\": \"^9.6.1\",\n    \"esbuild\": \"^0.27.3\",\n    \"esbuild-node-externals\": \"^1.20.1\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.9.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.9.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\"\n  },\n  \"dependencies\": {\n    \"@inertiajs/core\": \"workspace:*\",\n    \"@types/lodash-es\": \"^4.17.12\",\n    \"laravel-precognition\": \"^1.0.2\",\n    \"lodash-es\": \"^4.17.23\"\n  }\n}\n"
  },
  {
    "path": "packages/react/readme.md",
    "content": "# Inertia.js React Adapter\n\nVisit [inertiajs.com](https://inertiajs.com/) to learn more.\n"
  },
  {
    "path": "packages/react/resources/boost/guidelines/core.blade.php",
    "content": "# Inertia + React\n\n- IMPORTANT: Activate `inertia-react-development` when working with Inertia React client-side patterns.\n"
  },
  {
    "path": "packages/react/resources/boost/skills/inertia-react-development/SKILL.blade.php",
    "content": "---\nname: inertia-react-development\ndescription: \"Develops Inertia.js v2 React client-side applications. Activates when creating React pages, forms, or navigation; using <Link>, <Form>, useForm, or router; working with deferred props, prefetching, or polling; or when user mentions React with Inertia, React pages, React forms, or React navigation.\"\nlicense: MIT\nmetadata:\n  author: laravel\n---\n@php\n/** @var \\Laravel\\Boost\\Install\\GuidelineAssist $assist */\n@endphp\n# Inertia React Development\n\n## When to Apply\n\nActivate this skill when:\n\n- Creating or modifying React page components for Inertia\n- Working with forms in React (using `<Form>` or `useForm`)\n- Implementing client-side navigation with `<Link>` or `router`\n- Using v2 features: deferred props, prefetching, WhenVisible, InfiniteScroll, once props, flash data, or polling\n- Building React-specific features with the Inertia protocol\n\n## Documentation\n\nUse `search-docs` for detailed Inertia v2 React patterns and documentation.\n\n## Basic Usage\n\n### Page Components Location\n\nReact page components should be placed in the `{{ $assist->inertia()->pagesDirectory() }}` directory.\n\n### Page Component Structure\n\n@boostsnippet(\"Basic React Page Component\", \"react\")\nexport default function UsersIndex({ users }) {\n    return (\n        <div>\n            <h1>Users</h1>\n            <ul>\n                {users.map(user => <li key={user.id}>{user.name}</li>)}\n            </ul>\n        </div>\n    )\n}\n@endboostsnippet\n\n## Client-Side Navigation\n\n### Basic Link Component\n\nUse `<Link>` for client-side navigation instead of traditional `<a>` tags:\n\n@boostsnippet(\"Inertia React Navigation\", \"react\")\nimport { Link, router } from '@inertiajs/react'\n\n<Link href=\"/\">Home</Link>\n<Link href=\"/users\">Users</Link>\n<Link href={`/users/${user.id}`}>View User</Link>\n@endboostsnippet\n\n### Link with Method\n\n@boostsnippet(\"Link with POST Method\", \"react\")\nimport { Link } from '@inertiajs/react'\n\n<Link href=\"/logout\" method=\"post\" as=\"button\">\n    Logout\n</Link>\n@endboostsnippet\n\n### Prefetching\n\nPrefetch pages to improve perceived performance:\n\n@boostsnippet(\"Prefetch on Hover\", \"react\")\nimport { Link } from '@inertiajs/react'\n\n<Link href=\"/users\" prefetch>\n    Users\n</Link>\n@endboostsnippet\n\n### Programmatic Navigation\n\n@boostsnippet(\"Router Visit\", \"react\")\nimport { router } from '@inertiajs/react'\n\nfunction handleClick() {\n    router.visit('/users')\n}\n\n// Or with options\nrouter.visit('/users', {\n    method: 'post',\n    data: { name: 'John' },\n    onSuccess: () => console.log('Success!'),\n})\n@endboostsnippet\n\n## Form Handling\n\n@if($assist->inertia()->hasFormComponent())\n### Form Component (Recommended)\n\nThe recommended way to build forms is with the `<Form>` component:\n\n@boostsnippet(\"Form Component Example\", \"react\")\nimport { Form } from '@inertiajs/react'\n\nexport default function CreateUser() {\n    return (\n        <Form action=\"/users\" method=\"post\">\n            {({ errors, processing, wasSuccessful }) => (\n                <>\n                    <input type=\"text\" name=\"name\" />\n                    {errors.name && <div>{errors.name}</div>}\n\n                    <input type=\"email\" name=\"email\" />\n                    {errors.email && <div>{errors.email}</div>}\n\n                    <button type=\"submit\" disabled={processing}>\n                        {processing ? 'Creating...' : 'Create User'}\n                    </button>\n\n                    {wasSuccessful && <div>User created!</div>}\n                </>\n            )}\n        </Form>\n    )\n}\n@endboostsnippet\n\n### Form Component With All Props\n\n@boostsnippet(\"Form Component Full Example\", \"react\")\nimport { Form } from '@inertiajs/react'\n\n<Form action=\"/users\" method=\"post\">\n    {({\n        errors,\n        hasErrors,\n        processing,\n        progress,\n        wasSuccessful,\n        recentlySuccessful,\n        clearErrors,\n        resetAndClearErrors,\n        defaults,\n        isDirty,\n        reset,\n        submit\n    }) => (\n        <>\n            <input type=\"text\" name=\"name\" defaultValue={defaults.name} />\n            {errors.name && <div>{errors.name}</div>}\n\n            <button type=\"submit\" disabled={processing}>\n                {processing ? 'Saving...' : 'Save'}\n            </button>\n\n            {progress && (\n                <progress value={progress.percentage} max=\"100\">\n                    {progress.percentage}%\n                </progress>\n            )}\n\n            {wasSuccessful && <div>Saved!</div>}\n        </>\n    )}\n</Form>\n@endboostsnippet\n\n@if($assist->inertia()->hasFormComponentResets())\n### Form Component Reset Props\n\nThe `<Form>` component supports automatic resetting:\n\n- `resetOnError` - Reset form data when the request fails\n- `resetOnSuccess` - Reset form data when the request succeeds\n- `setDefaultsOnSuccess` - Update default values on success\n\nUse the `search-docs` tool with a query of `form component resetting` for detailed guidance.\n\n@boostsnippet(\"Form with Reset Props\", \"react\")\nimport { Form } from '@inertiajs/react'\n\n<Form\n    action=\"/users\"\n    method=\"post\"\n    resetOnSuccess\n    setDefaultsOnSuccess\n>\n    {({ errors, processing, wasSuccessful }) => (\n        <>\n            <input type=\"text\" name=\"name\" />\n            {errors.name && <div>{errors.name}</div>}\n\n            <button type=\"submit\" disabled={processing}>\n                Submit\n            </button>\n        </>\n    )}\n</Form>\n@endboostsnippet\n@else\nNote: This version of Inertia does not support `resetOnError`, `resetOnSuccess`, or `setDefaultsOnSuccess` on the `<Form>` component. Using these props will cause errors. Upgrade to Inertia v2.2.0+ to use these features.\n@endif\n\nForms can also be built using the `useForm` helper for more programmatic control. Use the `search-docs` tool with a query of `useForm helper` for guidance.\n\n@endif\n\n### `useForm` Hook\n\n@if($assist->inertia()->hasFormComponent() === false)\nFor Inertia v2.0.x: Build forms using the `useForm` helper as the `<Form>` component is not available until v2.1.0+.\n@else\nFor more programmatic control or to follow existing conventions, use the `useForm` hook:\n@endif\n\n@boostsnippet(\"useForm Hook Example\", \"react\")\nimport { useForm } from '@inertiajs/react'\n\nexport default function CreateUser() {\n    const { data, setData, post, processing, errors, reset } = useForm({\n        name: '',\n        email: '',\n        password: '',\n    })\n\n    function submit(e) {\n        e.preventDefault()\n        post('/users', {\n            onSuccess: () => reset('password'),\n        })\n    }\n\n    return (\n        <form onSubmit={submit}>\n            <input\n                type=\"text\"\n                value={data.name}\n                onChange={e => setData('name', e.target.value)}\n            />\n            {errors.name && <div>{errors.name}</div>}\n\n            <input\n                type=\"email\"\n                value={data.email}\n                onChange={e => setData('email', e.target.value)}\n            />\n            {errors.email && <div>{errors.email}</div>}\n\n            <input\n                type=\"password\"\n                value={data.password}\n                onChange={e => setData('password', e.target.value)}\n            />\n            {errors.password && <div>{errors.password}</div>}\n\n            <button type=\"submit\" disabled={processing}>\n                Create User\n            </button>\n        </form>\n    )\n}\n@endboostsnippet\n\n## Inertia v2 Features\n\n### Deferred Props\n\nUse deferred props to load data after initial page render:\n\n@boostsnippet(\"Deferred Props with Empty State\", \"react\")\nexport default function UsersIndex({ users }) {\n    // users will be undefined initially, then populated\n    return (\n        <div>\n            <h1>Users</h1>\n            {!users ? (\n                <div className=\"animate-pulse\">\n                    <div className=\"h-4 bg-gray-200 rounded w-3/4 mb-2\"></div>\n                    <div className=\"h-4 bg-gray-200 rounded w-1/2\"></div>\n                </div>\n            ) : (\n                <ul>\n                    {users.map(user => (\n                        <li key={user.id}>{user.name}</li>\n                    ))}\n                </ul>\n            )}\n        </div>\n    )\n}\n@endboostsnippet\n\n### Polling\n\nAutomatically refresh data at intervals:\n\n@boostsnippet(\"Polling Example\", \"react\")\nimport { router } from '@inertiajs/react'\nimport { useEffect } from 'react'\n\nexport default function Dashboard({ stats }) {\n    useEffect(() => {\n        const interval = setInterval(() => {\n            router.reload({ only: ['stats'] })\n        }, 5000) // Poll every 5 seconds\n\n        return () => clearInterval(interval)\n    }, [])\n\n    return (\n        <div>\n            <h1>Dashboard</h1>\n            <div>Active Users: {stats.activeUsers}</div>\n        </div>\n    )\n}\n@endboostsnippet\n\n### WhenVisible\n\nLazy-load a prop when an element scrolls into view. Useful for deferring expensive data that sits below the fold:\n\n@boostsnippet(\"WhenVisible Example\", \"react\")\nimport { WhenVisible } from '@inertiajs/react'\n\nexport default function Dashboard({ stats }) {\n    return (\n        <div>\n            <h1>Dashboard</h1>\n\n            {/* stats prop is loaded only when this section scrolls into view */}\n            <WhenVisible data=\"stats\" buffer={200} fallback={<div className=\"animate-pulse\">Loading stats...</div>}>\n                {({ fetching }) => (\n                    <div>\n                        <p>Total Users: {stats.total_users}</p>\n                        <p>Revenue: {stats.revenue}</p>\n                        {fetching && <span>Refreshing...</span>}\n                    </div>\n                )}\n            </WhenVisible>\n        </div>\n    )\n}\n@endboostsnippet\n\n## Server-Side Patterns\n\nServer-side patterns (Inertia::render, props, middleware) are covered in inertia-laravel guidelines.\n\n## Common Pitfalls\n\n- Using traditional `<a>` links instead of Inertia's `<Link>` component (breaks SPA behavior)\n- Forgetting to add loading states (skeleton screens) when using deferred props\n- Not handling the `undefined` state of deferred props before data loads\n- Using `<form>` without preventing default submission (use `<Form>` component or `e.preventDefault()`)\n- Forgetting to check if `<Form>` component is available in your Inertia version\n"
  },
  {
    "path": "packages/react/src/App.ts",
    "content": "import {\n  createHeadManager,\n  HeadManagerOnUpdateCallback,\n  HeadManagerTitleCallback,\n  Page,\n  PageHandler,\n  PageProps,\n  router,\n} from '@inertiajs/core'\nimport { createElement, FunctionComponent, ReactNode, useEffect, useMemo, useState } from 'react'\nimport { flushSync } from 'react-dom'\nimport HeadContext from './HeadContext'\nimport PageContext from './PageContext'\nimport { LayoutFunction, ReactComponent, ReactPageHandlerArgs } from './types'\n\nlet currentIsInitialPage = true\nlet routerIsInitialized = false\nlet swapComponent: PageHandler<ReactComponent> = async () => {\n  // Dummy function so we can init the router outside of the useEffect hook. This is\n  // needed so `router.reload()` works right away (on mount) in any of the user's\n  // components. We swap in the real function in the useEffect hook below.\n  currentIsInitialPage = false\n}\n\ntype CurrentPage = {\n  component: ReactComponent | null\n  page: Page\n  key: number | null\n}\n\nexport interface InertiaAppProps<SharedProps extends PageProps = PageProps> {\n  children?: (options: { Component: ReactComponent; props: PageProps; key: number | null }) => ReactNode\n  initialPage: Page<SharedProps>\n  initialComponent?: ReactComponent\n  resolveComponent?: (name: string) => ReactComponent | Promise<ReactComponent>\n  titleCallback?: HeadManagerTitleCallback\n  onHeadUpdate?: HeadManagerOnUpdateCallback\n}\n\nexport type InertiaApp = FunctionComponent<InertiaAppProps>\n\nexport default function App<SharedProps extends PageProps = PageProps>({\n  children,\n  initialPage,\n  initialComponent,\n  resolveComponent,\n  titleCallback,\n  onHeadUpdate,\n}: InertiaAppProps<SharedProps>) {\n  const [current, setCurrent] = useState<CurrentPage>({\n    component: initialComponent || null,\n    page: { ...initialPage, flash: initialPage.flash ?? {} },\n    key: null,\n  })\n\n  const headManager = useMemo(() => {\n    return createHeadManager(\n      typeof window === 'undefined',\n      titleCallback || ((title) => title),\n      onHeadUpdate || (() => {}),\n    )\n  }, [])\n\n  if (!routerIsInitialized) {\n    router.init<ReactComponent>({\n      initialPage,\n      resolveComponent: resolveComponent!,\n      swapComponent: async (args) => swapComponent(args),\n      onFlash: (flash) => {\n        setCurrent((current) => ({\n          ...current,\n          page: { ...current.page, flash },\n        }))\n      },\n    })\n\n    routerIsInitialized = true\n  }\n\n  useEffect(() => {\n    swapComponent = async ({ component, page, preserveState }: ReactPageHandlerArgs) => {\n      if (currentIsInitialPage) {\n        // We block setting the current page on the initial page to\n        // prevent the initial page from being re-rendered again.\n        currentIsInitialPage = false\n        return\n      }\n\n      flushSync(() =>\n        setCurrent((current) => ({\n          component,\n          page,\n          key: preserveState ? current.key : Date.now(),\n        })),\n      )\n    }\n\n    router.on('navigate', () => headManager.forceUpdate())\n  }, [])\n\n  if (!current.component) {\n    return createElement(\n      HeadContext.Provider,\n      { value: headManager },\n      createElement(PageContext.Provider, { value: current.page }, null),\n    )\n  }\n\n  const renderChildren =\n    children ||\n    (({ Component, props, key }) => {\n      const child = createElement(Component, { key, ...props })\n\n      if (typeof Component.layout === 'function') {\n        return (Component.layout as LayoutFunction)(child)\n      }\n\n      if (Array.isArray(Component.layout)) {\n        return (Component.layout as any)\n          .concat(child)\n          .reverse()\n          .reduce((children: any, Layout: any) => createElement(Layout, { children, ...props }))\n      }\n\n      return child\n    })\n\n  return createElement(\n    HeadContext.Provider,\n    { value: headManager },\n    createElement(\n      PageContext.Provider,\n      { value: current.page },\n      renderChildren({\n        Component: current.component,\n        key: current.key,\n        props: current.page.props,\n      }),\n    ),\n  )\n}\n\nApp.displayName = 'Inertia'\n"
  },
  {
    "path": "packages/react/src/Deferred.ts",
    "content": "import { ReactNode, useEffect, useMemo, useState } from 'react'\nimport { router } from '.'\nimport usePage from './usePage'\n\nconst urlWithoutHash = (url: URL | Location): URL => {\n  url = new URL(url.href)\n  url.hash = ''\n\n  return url\n}\n\nconst isSameUrlWithoutHash = (url1: URL | Location, url2: URL | Location): boolean => {\n  return urlWithoutHash(url1).href === urlWithoutHash(url2).href\n}\n\ninterface DeferredProps {\n  children: ReactNode | (() => ReactNode)\n  fallback: ReactNode | (() => ReactNode)\n  data: string | string[]\n}\n\nconst Deferred = ({ children, data, fallback }: DeferredProps) => {\n  if (!data) {\n    throw new Error('`<Deferred>` requires a `data` prop to be a string or array of strings')\n  }\n\n  const [loaded, setLoaded] = useState(false)\n  const pageProps = usePage().props\n  const keys = useMemo(() => (Array.isArray(data) ? data : [data]), [data])\n\n  useEffect(() => {\n    const removeListener = router.on('start', (e) => {\n      const isPartialVisit = e.detail.visit.only.length > 0 || e.detail.visit.except.length > 0\n      const isReloadingKey = e.detail.visit.only.find((key) => keys.includes(key))\n\n      if (isSameUrlWithoutHash(e.detail.visit.url, window.location) && (!isPartialVisit || isReloadingKey)) {\n        setLoaded(false)\n      }\n    })\n\n    return () => {\n      removeListener()\n    }\n  }, [])\n\n  useEffect(() => {\n    setLoaded(keys.every((key) => pageProps[key] !== undefined))\n  }, [pageProps, keys])\n\n  // Always check that props are actually defined before rendering children,\n  // even if loaded is true, to prevent race conditions during reloads\n  const propsAreDefined = useMemo(() => keys.every((key) => pageProps[key] !== undefined), [keys, pageProps])\n\n  if (loaded && propsAreDefined) {\n    return typeof children === 'function' ? children() : children\n  }\n\n  return typeof fallback === 'function' ? fallback() : fallback\n}\n\nDeferred.displayName = 'InertiaDeferred'\n\nexport default Deferred\n"
  },
  {
    "path": "packages/react/src/Form.ts",
    "content": "import {\n  config,\n  FormComponentProps,\n  FormComponentRef,\n  FormComponentResetSymbol,\n  FormComponentSlotProps,\n  FormDataConvertible,\n  formDataToObject,\n  isUrlMethodPair,\n  mergeDataIntoQueryString,\n  Method,\n  resetFormFields,\n  UseFormUtils,\n  VisitOptions,\n} from '@inertiajs/core'\nimport { NamedInputEvent, ValidationConfig } from 'laravel-precognition'\nimport { isEqual } from 'lodash-es'\nimport React, {\n  createContext,\n  createElement,\n  FormEvent,\n  forwardRef,\n  ReactNode,\n  useContext,\n  useEffect,\n  useImperativeHandle,\n  useMemo,\n  useRef,\n  useState,\n} from 'react'\nimport { isReact19 } from './react'\nimport useForm from './useForm'\n\n// Polyfill for startTransition to support React 16.9+\nconst deferStateUpdate = (callback: () => void) => {\n  typeof React.startTransition === 'function' ? React.startTransition(callback) : setTimeout(callback, 0)\n}\n\ntype ComponentProps = (FormComponentProps &\n  Omit<React.FormHTMLAttributes<HTMLFormElement>, keyof FormComponentProps | 'children'> &\n  Omit<React.AllHTMLAttributes<HTMLFormElement>, keyof FormComponentProps | 'children'>) & {\n  children: ReactNode | ((props: FormComponentSlotProps) => ReactNode)\n}\n\ntype FormSubmitOptions = Omit<VisitOptions, 'data' | 'onPrefetched' | 'onPrefetching'>\ntype FormSubmitter = HTMLElement | null\n\nconst noop = () => undefined\n\nconst FormContext = createContext<FormComponentRef | undefined>(undefined)\n\nconst Form = forwardRef<FormComponentRef, ComponentProps>(\n  (\n    {\n      action = '',\n      method = 'get',\n      headers = {},\n      queryStringArrayFormat = 'brackets',\n      errorBag = null,\n      showProgress = true,\n      transform = (data) => data,\n      options = {},\n      onStart = noop,\n      onProgress = noop,\n      onFinish = noop,\n      onBefore = noop,\n      onCancel = noop,\n      onSuccess = noop,\n      onError = noop,\n      onCancelToken = noop,\n      onSubmitComplete = noop,\n      disableWhileProcessing = false,\n      resetOnError = false,\n      resetOnSuccess = false,\n      setDefaultsOnSuccess = false,\n      invalidateCacheTags = [],\n      validateFiles = false,\n      validationTimeout = 1500,\n      withAllErrors = null,\n      children,\n      ...props\n    },\n    ref,\n  ) => {\n    const getTransformedData = (): Record<string, FormDataConvertible> => {\n      const [_url, data] = getUrlAndData()\n      return transform(data)\n    }\n\n    const form = useForm<Record<string, any>>({})\n      .withPrecognition(\n        () => resolvedMethod,\n        () => getUrlAndData()[0],\n      )\n      .setValidationTimeout(validationTimeout)\n\n    if (validateFiles) {\n      form.validateFiles()\n    }\n\n    if (withAllErrors ?? config.get('form.withAllErrors')) {\n      form.withAllErrors()\n    }\n\n    form.transform(getTransformedData)\n\n    const formElement = useRef<HTMLFormElement>(undefined)\n\n    const resolvedMethod = useMemo(() => {\n      return isUrlMethodPair(action) ? action.method : (method.toLowerCase() as Method)\n    }, [action, method])\n\n    const [isDirty, setIsDirty] = useState(false)\n    const defaultData = useRef<FormData>(new FormData())\n\n    const getFormData = (submitter?: FormSubmitter): FormData => new FormData(formElement.current, submitter)\n\n    // Convert the FormData to an object because we can't compare two FormData\n    // instances directly (which is needed for isDirty), mergeDataIntoQueryString()\n    // expects an object, and submitting a FormData instance directly causes problems with nested objects.\n    const getData = (submitter?: FormSubmitter): Record<string, FormDataConvertible> =>\n      formDataToObject(getFormData(submitter))\n\n    const getUrlAndData = (submitter?: FormSubmitter): [string, Record<string, FormDataConvertible>] => {\n      return mergeDataIntoQueryString(\n        resolvedMethod,\n        isUrlMethodPair(action) ? action.url : action,\n        getData(submitter),\n        queryStringArrayFormat,\n      )\n    }\n\n    const updateDirtyState = (event: Event) => {\n      if (event.type === 'reset' && (event as CustomEvent).detail?.[FormComponentResetSymbol]) {\n        // When the form is reset programmatically, prevent native reset behavior\n        event.preventDefault()\n      }\n\n      deferStateUpdate(() =>\n        setIsDirty(event.type === 'reset' ? false : !isEqual(getData(), formDataToObject(defaultData.current))),\n      )\n    }\n\n    const clearErrors = (...names: string[]) => {\n      form.clearErrors(...names)\n\n      return form\n    }\n\n    useEffect(() => {\n      defaultData.current = getFormData()\n\n      form.setDefaults(getData())\n\n      const formEvents: Array<keyof HTMLElementEventMap> = ['input', 'change', 'reset']\n\n      formEvents.forEach((e) => formElement.current!.addEventListener(e, updateDirtyState))\n\n      return () => {\n        formEvents.forEach((e) => formElement.current?.removeEventListener(e, updateDirtyState))\n      }\n    }, [])\n\n    useEffect(() => {\n      form.setValidationTimeout(validationTimeout)\n    }, [validationTimeout])\n\n    useEffect(() => {\n      if (validateFiles) {\n        form.validateFiles()\n      } else {\n        form.withoutFileValidation()\n      }\n    }, [validateFiles])\n\n    const reset = (...fields: string[]) => {\n      if (formElement.current) {\n        resetFormFields(formElement.current, defaultData.current, fields)\n      }\n\n      form.reset(...fields)\n    }\n\n    const resetAndClearErrors = (...fields: string[]) => {\n      clearErrors(...fields)\n      reset(...fields)\n    }\n\n    const maybeReset = (resetOption: boolean | string[]) => {\n      if (!resetOption) {\n        return\n      }\n\n      if (resetOption === true) {\n        reset()\n      } else if (resetOption.length > 0) {\n        reset(...resetOption)\n      }\n    }\n\n    const submit = (submitter?: FormSubmitter) => {\n      const [url, data] = getUrlAndData(submitter)\n      const formTarget = (submitter as HTMLButtonElement | HTMLInputElement | null)?.getAttribute('formtarget')\n\n      if (formTarget === '_blank' && resolvedMethod === 'get') {\n        window.open(url, '_blank')\n        return\n      }\n\n      const submitOptions: FormSubmitOptions = {\n        headers,\n        queryStringArrayFormat,\n        errorBag,\n        showProgress,\n        invalidateCacheTags,\n        onCancelToken,\n        onBefore,\n        onStart,\n        onProgress,\n        onFinish,\n        onCancel,\n        onSuccess: (...args) => {\n          onSuccess(...args)\n          onSubmitComplete({\n            reset,\n            defaults,\n          })\n          maybeReset(resetOnSuccess)\n\n          if (setDefaultsOnSuccess === true) {\n            defaults()\n          }\n        },\n        onError(...args) {\n          onError(...args)\n          maybeReset(resetOnError)\n        },\n        ...options,\n      }\n\n      // We need transform because we can't override the default data with different keys (by design)\n      form.transform(() => transform(data))\n      form.submit(resolvedMethod, url, submitOptions)\n\n      // Reset the transformer back so the submitter is not used for future submissions\n      form.transform(getTransformedData)\n    }\n\n    const defaults = () => {\n      defaultData.current = getFormData()\n      setIsDirty(false)\n    }\n\n    const exposed = {\n      errors: form.errors,\n      hasErrors: form.hasErrors,\n      processing: form.processing,\n      progress: form.progress,\n      wasSuccessful: form.wasSuccessful,\n      recentlySuccessful: form.recentlySuccessful,\n      isDirty,\n      clearErrors,\n      resetAndClearErrors,\n      setError: form.setError,\n      reset,\n      submit,\n      defaults,\n      getData,\n      getFormData,\n\n      // Precognition\n      validator: () => form.validator(),\n      validating: form.validating,\n      valid: form.valid,\n      invalid: form.invalid,\n      validate: (field?: string | NamedInputEvent | ValidationConfig, config?: ValidationConfig) =>\n        form.validate(...UseFormUtils.mergeHeadersForValidation(field, config, headers)),\n      touch: form.touch,\n      touched: form.touched,\n    }\n\n    useImperativeHandle(ref, () => exposed, [form, isDirty, submit])\n\n    const formNode = createElement(\n      'form',\n      {\n        ...props,\n        ref: formElement,\n        action: isUrlMethodPair(action) ? action.url : action,\n        method: resolvedMethod,\n        onSubmit: (event: FormEvent<HTMLFormElement>) => {\n          event.preventDefault()\n          submit((event.nativeEvent as SubmitEvent).submitter)\n        },\n        // React 19 supports passing a boolean to the `inert` attribute, but shows\n        // a warning when receiving a string. Earlier versions require the string 'true'.\n        // See: https://github.com/inertiajs/inertia/pull/2536\n        inert: disableWhileProcessing && form.processing && (isReact19 ? true : 'true'),\n      },\n      typeof children === 'function' ? children(exposed) : children,\n    )\n\n    return createElement(FormContext.Provider, { value: exposed }, formNode)\n  },\n)\n\nForm.displayName = 'InertiaForm'\n\nexport function useFormContext(): FormComponentRef | undefined {\n  return useContext(FormContext)\n}\n\nexport default Form\n"
  },
  {
    "path": "packages/react/src/Head.ts",
    "content": "import { escape } from 'lodash-es'\nimport React, { FunctionComponent, ReactElement, ReactNode, useContext, useEffect, useMemo } from 'react'\nimport HeadContext from './HeadContext'\n\ntype InertiaHeadProps = {\n  title?: string\n  children?: ReactNode\n}\n\ntype InertiaHead = FunctionComponent<InertiaHeadProps>\n\nconst Head: InertiaHead = function ({ children, title }) {\n  const headManager = useContext(HeadContext)\n  const provider = useMemo(() => headManager!.createProvider(), [headManager])\n  const isServer = typeof window === 'undefined'\n\n  useEffect(() => {\n    provider.reconnect()\n    provider.update(renderNodes(children))\n    return () => {\n      provider.disconnect()\n    }\n  }, [provider, children, title])\n\n  function isUnaryTag(node: ReactElement<any>) {\n    return (\n      typeof node.type === 'string' &&\n      [\n        'area',\n        'base',\n        'br',\n        'col',\n        'embed',\n        'hr',\n        'img',\n        'input',\n        'keygen',\n        'link',\n        'meta',\n        'param',\n        'source',\n        'track',\n        'wbr',\n      ].indexOf(node.type) > -1\n    )\n  }\n\n  function renderTagStart(node: ReactElement<any>): string {\n    const attrs = Object.keys(node.props).reduce((carry, name) => {\n      if (['head-key', 'children', 'dangerouslySetInnerHTML'].includes(name)) {\n        return carry\n      }\n\n      const value = String(node.props[name])\n\n      if (value === '') {\n        return carry + ` ${name}`\n      }\n\n      return carry + ` ${name}=\"${escape(value)}\"`\n    }, '')\n\n    return `<${String(node.type)}${attrs}>`\n  }\n\n  function renderTagChildren(node: ReactElement<any>): string {\n    const { children } = node.props\n\n    if (typeof children === 'string') {\n      return children\n    }\n\n    if (Array.isArray(children)) {\n      return children.reduce((html, child) => html + renderTag(child), '')\n    }\n\n    return ''\n  }\n\n  function renderTag(node: ReactElement<any>): string {\n    let html = renderTagStart(node)\n\n    if (node.props.children) {\n      html += renderTagChildren(node)\n    }\n\n    if (node.props.dangerouslySetInnerHTML) {\n      html += node.props.dangerouslySetInnerHTML.__html\n    }\n\n    if (!isUnaryTag(node)) {\n      html += `</${String(node.type)}>`\n    }\n\n    return html\n  }\n\n  function ensureNodeHasInertiaProp(node: ReactElement<any>) {\n    return React.cloneElement(node, {\n      [provider.preferredAttribute()]: node.props['head-key'] !== undefined ? node.props['head-key'] : '',\n    })\n  }\n\n  function renderNode(node: ReactElement<any>) {\n    return renderTag(ensureNodeHasInertiaProp(node))\n  }\n\n  function renderNodes(nodes: ReactNode) {\n    const elements = React.Children.toArray(nodes)\n      .filter((node) => node)\n      .map((node) => renderNode(node as ReactElement<any>))\n\n    if (title && !elements.find((tag) => tag.startsWith('<title'))) {\n      elements.push(`<title ${provider.preferredAttribute()}>${title}</title>`)\n    }\n\n    return elements\n  }\n\n  if (isServer) {\n    provider.update(renderNodes(children))\n  }\n\n  return null\n}\nexport default Head\n"
  },
  {
    "path": "packages/react/src/HeadContext.ts",
    "content": "import { HeadManager } from '@inertiajs/core'\nimport { createContext } from 'react'\n\nconst headContext = createContext<HeadManager | null>(null)\nheadContext.displayName = 'InertiaHeadContext'\n\nexport default headContext\n"
  },
  {
    "path": "packages/react/src/InfiniteScroll.ts",
    "content": "import {\n  getScrollableParent,\n  InfiniteScrollActionSlotProps,\n  InfiniteScrollComponentBaseProps,\n  InfiniteScrollRef,\n  InfiniteScrollSlotProps,\n  useInfiniteScroll,\n  UseInfiniteScrollProps,\n} from '@inertiajs/core'\nimport React, {\n  createElement,\n  forwardRef,\n  useCallback,\n  useEffect,\n  useImperativeHandle,\n  useMemo,\n  useRef,\n  useState,\n} from 'react'\n\nconst resolveHTMLElement = (\n  value: string | React.RefObject<HTMLElement | null> | null,\n  fallback: HTMLElement | null,\n): HTMLElement | null => {\n  if (!value) {\n    return fallback\n  }\n\n  // React ref object { current: HTMLElement | null }\n  if (value && typeof value === 'object' && 'current' in value) {\n    return value.current\n  }\n\n  // CSS Selector string\n  if (typeof value === 'string') {\n    return document.querySelector(value) as HTMLElement | null\n  }\n\n  return fallback\n}\n\n// Helper function to render slot content\nconst renderSlot = (\n  slotContent: React.ReactNode | ((props: InfiniteScrollActionSlotProps) => React.ReactNode) | undefined,\n  slotProps: InfiniteScrollActionSlotProps,\n  fallback: React.ReactNode = null,\n): React.ReactNode => {\n  if (!slotContent) {\n    return fallback\n  }\n\n  return typeof slotContent === 'function' ? slotContent(slotProps) : slotContent\n}\n\ninterface ComponentProps\n  extends\n    InfiniteScrollComponentBaseProps,\n    Omit<React.HTMLAttributes<HTMLElement>, keyof InfiniteScrollComponentBaseProps | 'children'> {\n  children?: React.ReactNode | ((props: InfiniteScrollSlotProps) => React.ReactNode)\n\n  // Element references for custom trigger detection (when you want different trigger elements)\n  startElement?: string | React.RefObject<HTMLElement | null>\n  endElement?: string | React.RefObject<HTMLElement | null>\n  itemsElement?: string | React.RefObject<HTMLElement | null>\n\n  // Render slots for UI components (when you want custom loading/action components)\n  previous?: React.ReactNode | ((props: InfiniteScrollActionSlotProps) => React.ReactNode)\n  next?: React.ReactNode | ((props: InfiniteScrollActionSlotProps) => React.ReactNode)\n  loading?: React.ReactNode | ((props: InfiniteScrollActionSlotProps) => React.ReactNode)\n\n  onlyNext?: boolean\n  onlyPrevious?: boolean\n}\n\nconst InfiniteScroll = forwardRef<InfiniteScrollRef, ComponentProps>(\n  (\n    {\n      data,\n      buffer = 0,\n      as = 'div',\n      manual = false,\n      manualAfter = 0,\n      preserveUrl = false,\n      reverse = false,\n      autoScroll,\n      children,\n      startElement,\n      endElement,\n      itemsElement,\n      previous,\n      next,\n      loading,\n      onlyNext = false,\n      onlyPrevious = false,\n      ...props\n    },\n    ref,\n  ) => {\n    const [startElementFromRef, setStartElementFromRef] = useState<HTMLElement | null>(null)\n    const startElementRef = useCallback((node: HTMLElement | null) => setStartElementFromRef(node), [])\n\n    const [endElementFromRef, setEndElementFromRef] = useState<HTMLElement | null>(null)\n    const endElementRef = useCallback((node: HTMLElement | null) => setEndElementFromRef(node), [])\n\n    const [itemsElementFromRef, setItemsElementFromRef] = useState<HTMLElement | null>(null)\n    const itemsElementRef = useCallback((node: HTMLElement | null) => setItemsElementFromRef(node), [])\n\n    const [loadingPrevious, setLoadingPrevious] = useState(false)\n    const [loadingNext, setLoadingNext] = useState(false)\n    const [requestCount, setRequestCount] = useState(0)\n    const [hasPreviousPage, setHasPreviousPage] = useState(false)\n    const [hasNextPage, setHasNextPage] = useState(false)\n\n    const [resolvedStartElement, setResolvedStartElement] = useState<HTMLElement | null>(null)\n    const [resolvedEndElement, setResolvedEndElement] = useState<HTMLElement | null>(null)\n    const [resolvedItemsElement, setResolvedItemsElement] = useState<HTMLElement | null>(null)\n\n    // Update elements when refs or props change\n    useEffect(() => {\n      const element = startElement ? resolveHTMLElement(startElement, startElementFromRef) : startElementFromRef\n      setResolvedStartElement(element)\n    }, [startElement, startElementFromRef])\n\n    useEffect(() => {\n      const element = endElement ? resolveHTMLElement(endElement, endElementFromRef) : endElementFromRef\n      setResolvedEndElement(element)\n    }, [endElement, endElementFromRef])\n\n    useEffect(() => {\n      const element = itemsElement ? resolveHTMLElement(itemsElement, itemsElementFromRef) : itemsElementFromRef\n      setResolvedItemsElement(element)\n    }, [itemsElement, itemsElementFromRef])\n\n    const scrollableParent = useMemo(() => getScrollableParent(resolvedItemsElement), [resolvedItemsElement])\n\n    const callbackPropsRef = useRef({\n      buffer,\n      onlyNext,\n      onlyPrevious,\n      reverse,\n      preserveUrl,\n    })\n\n    callbackPropsRef.current = {\n      buffer,\n      onlyNext,\n      onlyPrevious,\n      reverse,\n      preserveUrl,\n    }\n\n    const [infiniteScroll, setInfiniteScroll] = useState<UseInfiniteScrollProps | null>(null)\n\n    const dataManager = useMemo(() => infiniteScroll?.dataManager, [infiniteScroll])\n    const elementManager = useMemo(() => infiniteScroll?.elementManager, [infiniteScroll])\n\n    const scrollToBottom = useCallback(() => {\n      if (scrollableParent) {\n        scrollableParent.scrollTo({\n          top: scrollableParent.scrollHeight,\n          behavior: 'instant',\n        })\n      } else {\n        window.scrollTo({\n          top: document.body.scrollHeight,\n          behavior: 'instant',\n        })\n      }\n    }, [scrollableParent])\n\n    // Main setup effect - only recreate when structural dependencies change\n    useEffect(() => {\n      if (!resolvedItemsElement) {\n        return\n      }\n\n      function syncStateFromDataManager() {\n        setRequestCount(infiniteScrollInstance.dataManager.getRequestCount())\n        setHasPreviousPage(infiniteScrollInstance.dataManager.hasPrevious())\n        setHasNextPage(infiniteScrollInstance.dataManager.hasNext())\n      }\n\n      const infiniteScrollInstance = useInfiniteScroll({\n        // Data\n        getPropName: () => data,\n        inReverseMode: () => callbackPropsRef.current.reverse,\n        shouldFetchNext: () => !callbackPropsRef.current.onlyPrevious,\n        shouldFetchPrevious: () => !callbackPropsRef.current.onlyNext,\n        shouldPreserveUrl: () => callbackPropsRef.current.preserveUrl,\n\n        // Elements\n        getTriggerMargin: () => callbackPropsRef.current.buffer,\n        getStartElement: () => resolvedStartElement!,\n        getEndElement: () => resolvedEndElement!,\n        getItemsElement: () => resolvedItemsElement,\n        getScrollableParent: () => scrollableParent,\n\n        // Callbacks\n        onBeforePreviousRequest: () => setLoadingPrevious(true),\n        onBeforeNextRequest: () => setLoadingNext(true),\n        onCompletePreviousRequest: () => {\n          setLoadingPrevious(false)\n          syncStateFromDataManager()\n        },\n        onCompleteNextRequest: () => {\n          setLoadingNext(false)\n          syncStateFromDataManager()\n        },\n        onDataReset: syncStateFromDataManager,\n      })\n\n      setInfiniteScroll(infiniteScrollInstance)\n      const { dataManager, elementManager } = infiniteScrollInstance\n      syncStateFromDataManager()\n\n      elementManager.setupObservers()\n      elementManager.processServerLoadedElements(dataManager.getLastLoadedPage())\n\n      if (autoLoad) {\n        elementManager.enableTriggers()\n      }\n\n      return () => {\n        infiniteScrollInstance.flush()\n        setInfiniteScroll(null)\n      }\n    }, [data, resolvedItemsElement, resolvedStartElement, resolvedEndElement, scrollableParent])\n\n    const manualMode = useMemo(\n      () => manual || (manualAfter > 0 && requestCount >= manualAfter),\n      [manual, manualAfter, requestCount],\n    )\n    const autoLoad = useMemo(() => !manualMode, [manualMode])\n\n    useEffect(() => {\n      autoLoad ? elementManager?.enableTriggers() : elementManager?.disableTriggers()\n    }, [autoLoad, onlyNext, onlyPrevious, resolvedStartElement, resolvedEndElement])\n\n    useEffect(() => {\n      // autoScroll defaults to reverse value if not explicitly set\n      const shouldAutoScroll = autoScroll !== undefined ? autoScroll : reverse\n\n      if (shouldAutoScroll) {\n        scrollToBottom()\n      }\n    }, [scrollableParent])\n\n    useImperativeHandle(\n      ref,\n      () => ({\n        fetchNext: dataManager?.fetchNext || (() => {}),\n        fetchPrevious: dataManager?.fetchPrevious || (() => {}),\n        hasPrevious: dataManager?.hasPrevious || (() => false),\n        hasNext: dataManager?.hasNext || (() => false),\n      }),\n      [dataManager],\n    )\n\n    const headerAutoMode = autoLoad && !onlyNext\n    const footerAutoMode = autoLoad && !onlyPrevious\n\n    const sharedExposed: Pick<\n      InfiniteScrollActionSlotProps,\n      'loadingPrevious' | 'loadingNext' | 'hasPrevious' | 'hasNext'\n    > = {\n      loadingPrevious,\n      loadingNext,\n      hasPrevious: hasPreviousPage,\n      hasNext: hasNextPage,\n    }\n\n    const exposedPrevious: InfiniteScrollActionSlotProps = {\n      loading: loadingPrevious,\n      fetch: dataManager?.fetchPrevious ?? (() => {}),\n      autoMode: headerAutoMode,\n      manualMode: !headerAutoMode,\n      hasMore: hasPreviousPage,\n      ...sharedExposed,\n    }\n\n    const exposedNext: InfiniteScrollActionSlotProps = {\n      loading: loadingNext,\n      fetch: dataManager?.fetchNext ?? (() => {}),\n      autoMode: footerAutoMode,\n      manualMode: !footerAutoMode,\n      hasMore: hasNextPage,\n      ...sharedExposed,\n    }\n\n    const exposedSlot: InfiniteScrollSlotProps = {\n      loading: loadingPrevious || loadingNext,\n      loadingPrevious,\n      loadingNext,\n    }\n\n    const renderElements = []\n\n    // Only render previous trigger if not using custom element selector/ref\n    if (!startElement) {\n      renderElements.push(\n        createElement(\n          'div',\n          { ref: startElementRef },\n          // Render previous slot or fallback to loading indicator\n          renderSlot(previous, exposedPrevious, loadingPrevious ? renderSlot(loading, exposedPrevious) : null),\n        ),\n      )\n    }\n\n    renderElements.push(\n      createElement(\n        as,\n        { ...props, ref: itemsElementRef },\n        typeof children === 'function' ? children(exposedSlot) : children,\n      ),\n    )\n\n    // Only render next trigger if not using custom element selector/ref\n    if (!endElement) {\n      renderElements.push(\n        createElement(\n          'div',\n          { ref: endElementRef },\n          // Render next slot or fallback to loading indicator\n          renderSlot(next, exposedNext, loadingNext ? renderSlot(loading, exposedNext) : null),\n        ),\n      )\n    }\n\n    return createElement(React.Fragment, {}, ...(reverse ? [...renderElements].reverse() : renderElements))\n  },\n)\n\nInfiniteScroll.displayName = 'InertiaInfiniteScroll'\n\nexport default InfiniteScroll\n"
  },
  {
    "path": "packages/react/src/Link.ts",
    "content": "import {\n  ActiveVisit,\n  isUrlMethodPair,\n  LinkComponentBaseProps,\n  LinkPrefetchOption,\n  mergeDataIntoQueryString,\n  Method,\n  PendingVisit,\n  router,\n  shouldIntercept,\n  shouldNavigate,\n  VisitOptions,\n} from '@inertiajs/core'\nimport { createElement, ElementType, forwardRef, useEffect, useMemo, useRef, useState } from 'react'\nimport { config } from '.'\n\nconst noop = () => undefined\n\ninterface BaseInertiaLinkProps extends LinkComponentBaseProps {\n  as?: ElementType\n  onClick?: (event: React.MouseEvent) => void\n}\n\nexport type InertiaLinkProps = BaseInertiaLinkProps &\n  Omit<React.HTMLAttributes<HTMLElement>, keyof BaseInertiaLinkProps> &\n  Omit<React.AllHTMLAttributes<HTMLElement>, keyof BaseInertiaLinkProps>\n\nconst Link = forwardRef<unknown, InertiaLinkProps>(\n  (\n    {\n      children,\n      as = 'a',\n      data = {},\n      href = '',\n      method = 'get',\n      preserveScroll = false,\n      preserveState = null,\n      preserveUrl = false,\n      replace = false,\n      only = [],\n      except = [],\n      headers = {},\n      queryStringArrayFormat = 'brackets',\n      async = false,\n      onClick = noop,\n      onCancelToken = noop,\n      onBefore = noop,\n      onStart = noop,\n      onProgress = noop,\n      onFinish = noop,\n      onCancel = noop,\n      onSuccess = noop,\n      onError = noop,\n      onPrefetching = noop,\n      onPrefetched = noop,\n      prefetch = false,\n      cacheFor = 0,\n      cacheTags = [],\n      viewTransition = false,\n      ...props\n    },\n    ref,\n  ) => {\n    const [inFlightCount, setInFlightCount] = useState(0)\n    const hoverTimeout = useRef<number>(undefined)\n\n    const _method = useMemo(() => {\n      return isUrlMethodPair(href) ? href.method : (method.toLowerCase() as Method)\n    }, [href, method])\n\n    const _as = useMemo(() => {\n      if (typeof as !== 'string' || as.toLowerCase() !== 'a') {\n        // Custom component or element\n        return as\n      }\n\n      return _method !== 'get' ? 'button' : as.toLowerCase()\n    }, [as, _method])\n\n    const mergeDataArray = useMemo(\n      () => mergeDataIntoQueryString(_method, isUrlMethodPair(href) ? href.url : href, data, queryStringArrayFormat),\n      [href, _method, data, queryStringArrayFormat],\n    )\n\n    const url = useMemo(() => mergeDataArray[0], [mergeDataArray])\n    const _data = useMemo(() => mergeDataArray[1], [mergeDataArray])\n\n    const baseParams = useMemo<VisitOptions>(\n      () => ({\n        data: _data,\n        method: _method,\n        preserveScroll,\n        preserveState: preserveState ?? _method !== 'get',\n        preserveUrl,\n        replace,\n        only,\n        except,\n        headers,\n        async,\n      }),\n      [_data, _method, preserveScroll, preserveState, preserveUrl, replace, only, except, headers, async],\n    )\n\n    const visitParams = useMemo<VisitOptions>(\n      () => ({\n        ...baseParams,\n        viewTransition,\n        onCancelToken,\n        onBefore,\n        onStart(visit: PendingVisit) {\n          setInFlightCount((count) => count + 1)\n          onStart(visit)\n        },\n        onProgress,\n        onFinish(visit: ActiveVisit) {\n          setInFlightCount((count) => count - 1)\n          onFinish(visit)\n        },\n        onCancel,\n        onSuccess,\n        onError,\n      }),\n      [\n        baseParams,\n        viewTransition,\n        onCancelToken,\n        onBefore,\n        onStart,\n        onProgress,\n        onFinish,\n        onCancel,\n        onSuccess,\n        onError,\n      ],\n    )\n\n    const prefetchModes: LinkPrefetchOption[] = useMemo(\n      () => {\n        if (prefetch === true) {\n          return ['hover']\n        }\n\n        if (prefetch === false) {\n          return []\n        }\n\n        if (Array.isArray(prefetch)) {\n          return prefetch\n        }\n\n        return [prefetch]\n      },\n      Array.isArray(prefetch) ? prefetch : [prefetch],\n    )\n\n    const cacheForValue = useMemo(() => {\n      if (cacheFor !== 0) {\n        // If they've provided a value, respect it\n        return cacheFor\n      }\n\n      if (prefetchModes.length === 1 && prefetchModes[0] === 'click') {\n        // If they've only provided a prefetch mode of 'click',\n        // we should only prefetch for the next request but not keep it around\n        return 0\n      }\n\n      // Otherwise, default to 30 seconds\n      return config.get('prefetch.cacheFor')\n    }, [cacheFor, prefetchModes])\n\n    const doPrefetch = useMemo(() => {\n      return () => {\n        router.prefetch(\n          url,\n          {\n            ...baseParams,\n            onPrefetching,\n            onPrefetched,\n          },\n          { cacheFor: cacheForValue, cacheTags },\n        )\n      }\n    }, [url, baseParams, onPrefetching, onPrefetched, cacheForValue, cacheTags])\n\n    useEffect(() => {\n      return () => {\n        clearTimeout(hoverTimeout.current)\n      }\n    }, [])\n\n    useEffect(() => {\n      if (prefetchModes.includes('mount')) {\n        setTimeout(() => doPrefetch())\n      }\n    }, prefetchModes)\n\n    const regularEvents = {\n      onClick: (event: React.MouseEvent) => {\n        onClick(event)\n\n        if (shouldIntercept(event)) {\n          event.preventDefault()\n\n          router.visit(url, visitParams)\n        }\n      },\n    }\n\n    const prefetchHoverEvents = {\n      onMouseEnter: () => {\n        hoverTimeout.current = window.setTimeout(() => {\n          doPrefetch()\n        }, config.get('prefetch.hoverDelay'))\n      },\n      onMouseLeave: () => {\n        clearTimeout(hoverTimeout.current)\n      },\n      onClick: regularEvents.onClick,\n    }\n\n    const prefetchClickEvents = {\n      onMouseDown: (event: React.MouseEvent) => {\n        if (shouldIntercept(event)) {\n          event.preventDefault()\n          doPrefetch()\n        }\n      },\n      onKeyDown: (event: React.KeyboardEvent) => {\n        if (shouldNavigate(event)) {\n          event.preventDefault()\n          doPrefetch()\n        }\n      },\n      onMouseUp: (event: React.MouseEvent) => {\n        if (shouldIntercept(event)) {\n          event.preventDefault()\n          router.visit(url, visitParams)\n        }\n      },\n      onKeyUp: (event: React.KeyboardEvent) => {\n        if (shouldNavigate(event)) {\n          event.preventDefault()\n          router.visit(url, visitParams)\n        }\n      },\n      onClick: (event: React.MouseEvent) => {\n        onClick(event)\n\n        if (shouldIntercept(event)) {\n          // Let the mouseup/keyup event handle the visit\n          event.preventDefault()\n        }\n      },\n    }\n\n    const elProps = useMemo(() => {\n      if (_as === 'button') {\n        return { type: 'button' }\n      }\n\n      if (_as === 'a' || typeof _as !== 'string') {\n        return { href: url }\n      }\n\n      return {}\n    }, [_as, url])\n\n    return createElement(\n      _as,\n      {\n        ...props,\n        ...elProps,\n        ref,\n        ...(() => {\n          if (prefetchModes.includes('hover')) {\n            return prefetchHoverEvents\n          }\n\n          if (prefetchModes.includes('click')) {\n            return prefetchClickEvents\n          }\n\n          return regularEvents\n        })(),\n        'data-loading': inFlightCount > 0 ? '' : undefined,\n      },\n      children,\n    )\n  },\n)\nLink.displayName = 'InertiaLink'\n\nexport default Link\n"
  },
  {
    "path": "packages/react/src/PageContext.ts",
    "content": "import { Page } from '@inertiajs/core'\nimport { createContext } from 'react'\n\nconst pageContext = createContext<Page | null>(null)\npageContext.displayName = 'InertiaPageContext'\n\nexport default pageContext\n"
  },
  {
    "path": "packages/react/src/WhenVisible.ts",
    "content": "import { ReloadOptions, router } from '@inertiajs/core'\nimport { createElement, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport usePage from './usePage'\n\ninterface WhenVisibleSlotProps {\n  fetching: boolean\n}\n\ninterface WhenVisibleProps {\n  children: ReactNode | ((props: WhenVisibleSlotProps) => ReactNode)\n  fallback: ReactNode | (() => ReactNode)\n  data?: string | string[]\n  params?: ReloadOptions\n  buffer?: number\n  as?: string\n  always?: boolean\n}\n\nconst WhenVisible = ({ children, data, params, buffer, as, always, fallback }: WhenVisibleProps) => {\n  always = always ?? false\n  as = as ?? 'div'\n  fallback = fallback ?? null\n\n  const pageProps = usePage().props\n  const keys = useMemo(() => (data ? (Array.isArray(data) ? data : [data]) : []), [data])\n\n  const [loaded, setLoaded] = useState(() => keys.length > 0 && keys.every((key) => pageProps[key] !== undefined))\n  const [isFetching, setIsFetching] = useState(false)\n  const fetching = useRef<boolean>(false)\n  const ref = useRef<HTMLDivElement>(null)\n  const observer = useRef<IntersectionObserver | null>(null)\n  const getReloadParamsRef = useRef<() => Partial<ReloadOptions>>(() => ({}))\n\n  useEffect(() => {\n    if (keys.length > 0) {\n      setLoaded(keys.every((key) => pageProps[key] !== undefined))\n    }\n  }, [pageProps, keys])\n\n  const getReloadParams = useCallback<() => Partial<ReloadOptions>>(() => {\n    const reloadParams: Partial<ReloadOptions> = { ...params }\n\n    if (data) {\n      reloadParams.only = (Array.isArray(data) ? data : [data]) as string[]\n    }\n\n    return reloadParams\n  }, [params, data])\n\n  getReloadParamsRef.current = getReloadParams\n\n  const registerObserver = () => {\n    observer.current?.disconnect()\n\n    observer.current = new IntersectionObserver(\n      (entries) => {\n        if (!entries[0].isIntersecting) {\n          return\n        }\n\n        if (fetching.current) {\n          return\n        }\n\n        if (!always && loaded) {\n          return\n        }\n\n        fetching.current = true\n        setIsFetching(true)\n\n        const reloadParams = getReloadParamsRef.current()\n\n        router.reload({\n          ...reloadParams,\n          onStart: (e) => {\n            fetching.current = true\n            setIsFetching(true)\n            reloadParams.onStart?.(e)\n          },\n          onFinish: (e) => {\n            setLoaded(true)\n            fetching.current = false\n            setIsFetching(false)\n            reloadParams.onFinish?.(e)\n\n            if (!always) {\n              observer.current?.disconnect()\n            }\n          },\n        })\n      },\n      {\n        rootMargin: `${buffer || 0}px`,\n      },\n    )\n\n    observer.current.observe(ref.current!)\n  }\n\n  useEffect(() => {\n    if (!ref.current) {\n      return\n    }\n\n    if (loaded && !always) {\n      return\n    }\n\n    registerObserver()\n\n    return () => {\n      observer.current?.disconnect()\n    }\n  }, [always, loaded, buffer])\n\n  const resolveChildren = () => (typeof children === 'function' ? children({ fetching: isFetching }) : children)\n  const resolveFallback = () => (typeof fallback === 'function' ? fallback() : fallback)\n\n  if (always || !loaded) {\n    return createElement(\n      as,\n      {\n        props: null,\n        ref,\n      },\n      loaded ? resolveChildren() : resolveFallback(),\n    )\n  }\n\n  return loaded ? resolveChildren() : null\n}\n\nWhenVisible.displayName = 'InertiaWhenVisible'\n\nexport default WhenVisible\n"
  },
  {
    "path": "packages/react/src/createInertiaApp.ts",
    "content": "import {\n  CreateInertiaAppOptionsForCSR,\n  CreateInertiaAppOptionsForSSR,\n  getInitialPageFromDOM,\n  InertiaAppResponse,\n  InertiaAppSSRResponse,\n  Page,\n  PageProps,\n  router,\n  setupProgress,\n  SharedPageProps,\n} from '@inertiajs/core'\nimport { createElement, Fragment, ReactElement } from 'react'\nimport { renderToString } from 'react-dom/server'\nimport App, { InertiaAppProps, type InertiaApp } from './App'\nimport { config } from './index'\nimport { ReactComponent, ReactInertiaAppConfig } from './types'\n\nexport type SetupOptions<ElementType, SharedProps extends PageProps> = {\n  el: ElementType\n  App: InertiaApp\n  props: InertiaAppProps<SharedProps>\n}\n\n// The 'unknown' type is necessary for backwards compatibility...\ntype ComponentResolver = (\n  name: string,\n) => ReactComponent | Promise<ReactComponent> | { default: ReactComponent } | unknown\n\ntype InertiaAppOptionsForCSR<SharedProps extends PageProps> = CreateInertiaAppOptionsForCSR<\n  SharedProps,\n  ComponentResolver,\n  SetupOptions<HTMLElement, SharedProps>,\n  void,\n  ReactInertiaAppConfig\n>\n\ntype InertiaAppOptionsForSSR<SharedProps extends PageProps> = CreateInertiaAppOptionsForSSR<\n  SharedProps,\n  ComponentResolver,\n  SetupOptions<null, SharedProps>,\n  ReactElement,\n  ReactInertiaAppConfig\n> & {\n  render: typeof renderToString\n}\n\nexport default async function createInertiaApp<SharedProps extends PageProps = PageProps & SharedPageProps>(\n  options: InertiaAppOptionsForCSR<SharedProps>,\n): Promise<void>\nexport default async function createInertiaApp<SharedProps extends PageProps = PageProps & SharedPageProps>(\n  options: InertiaAppOptionsForSSR<SharedProps>,\n): Promise<InertiaAppSSRResponse>\nexport default async function createInertiaApp<SharedProps extends PageProps = PageProps & SharedPageProps>({\n  id = 'app',\n  resolve,\n  setup,\n  title,\n  progress = {},\n  page,\n  render,\n  defaults = {},\n}: InertiaAppOptionsForCSR<SharedProps> | InertiaAppOptionsForSSR<SharedProps>): InertiaAppResponse {\n  config.replace(defaults)\n\n  const isServer = typeof window === 'undefined'\n  const useScriptElementForInitialPage = config.get('future.useScriptElementForInitialPage')\n  const initialPage = page || getInitialPageFromDOM<Page<SharedProps>>(id, useScriptElementForInitialPage)!\n\n  // @ts-expect-error - This can be improved once we remove the 'unknown' type from the resolver...\n  const resolveComponent = (name) => Promise.resolve(resolve(name)).then((module) => module.default || module)\n\n  let head: string[] = []\n\n  const reactApp = await Promise.all([\n    resolveComponent(initialPage.component),\n    router.decryptHistory().catch(() => {}),\n  ]).then(([initialComponent]) => {\n    const props = {\n      initialPage,\n      initialComponent,\n      resolveComponent,\n      titleCallback: title,\n    }\n\n    if (isServer) {\n      const ssrSetup = setup as (options: SetupOptions<null, SharedProps>) => ReactElement\n\n      return ssrSetup({\n        el: null,\n        App,\n        props: { ...props, onHeadUpdate: (elements: string[]) => (head = elements) },\n      })\n    }\n\n    const csrSetup = setup as (options: SetupOptions<HTMLElement, SharedProps>) => void\n\n    return csrSetup({\n      el: document.getElementById(id)!,\n      App,\n      props,\n    })\n  })\n\n  if (!isServer && progress) {\n    setupProgress(progress)\n  }\n\n  if (isServer && render) {\n    const element = () => {\n      if (!useScriptElementForInitialPage) {\n        return createElement(\n          'div',\n          {\n            id,\n            'data-page': JSON.stringify(initialPage),\n          },\n          reactApp as ReactElement,\n        )\n      }\n\n      return createElement(\n        Fragment,\n        null,\n        createElement('script', {\n          'data-page': id,\n          type: 'application/json',\n          dangerouslySetInnerHTML: { __html: JSON.stringify(initialPage).replace(/\\//g, '\\\\/') },\n        }),\n        createElement('div', { id }, reactApp as ReactElement),\n      )\n    }\n\n    const body = await render(element())\n\n    return { head, body }\n  }\n}\n"
  },
  {
    "path": "packages/react/src/index.ts",
    "content": "import { config as coreConfig, progress as Progress, router as Router } from '@inertiajs/core'\nimport { ReactInertiaAppConfig } from './types'\n\nexport const progress = Progress\nexport const router = Router\nexport { default as App } from './App'\nexport { default as createInertiaApp } from './createInertiaApp'\nexport { default as Deferred } from './Deferred'\nexport { default as Form, useFormContext } from './Form'\nexport { default as Head } from './Head'\nexport { default as InfiniteScroll } from './InfiniteScroll'\nexport { InertiaLinkProps, default as Link } from './Link'\nexport { ReactComponent as ResolvedComponent } from './types'\nexport {\n  InertiaFormProps,\n  InertiaPrecognitiveFormProps,\n  SetDataAction,\n  SetDataByKeyValuePair,\n  SetDataByMethod,\n  SetDataByObject,\n  default as useForm,\n} from './useForm'\nexport { default as usePage } from './usePage'\nexport { default as usePoll } from './usePoll'\nexport { default as usePrefetch } from './usePrefetch'\nexport { default as useRemember } from './useRemember'\nexport { default as WhenVisible } from './WhenVisible'\n\nexport const config = coreConfig.extend<ReactInertiaAppConfig>()\n"
  },
  {
    "path": "packages/react/src/react.ts",
    "content": "import React, { DependencyList, EffectCallback, useEffect, useLayoutEffect } from 'react'\n\n// Inspired by react-redux, this hook uses useLayoutEffect in the browser, and useEffect\n// when using SSR. Currently, useLayoutEffect doesn't work when rendered on the server.\nexport function useIsomorphicLayoutEffect(effect: EffectCallback, deps?: DependencyList): void {\n  typeof window === 'undefined' ? useEffect(effect, deps) : useLayoutEffect(effect, deps)\n}\n\n// React.use() was introduced in React 19\nexport const isReact19 = typeof React.use === 'function'\n"
  },
  {
    "path": "packages/react/src/server.ts",
    "content": "export { default as default } from '@inertiajs/core/server'\n"
  },
  {
    "path": "packages/react/src/types.ts",
    "content": "import { PageHandler } from '@inertiajs/core'\nimport { ComponentType, ReactNode } from 'react'\n\nexport type LayoutFunction = (page: ReactNode) => ReactNode\nexport type LayoutComponent = ComponentType<{ children: ReactNode }>\n\nexport type ReactComponent = ComponentType<any> & {\n  layout?: LayoutComponent | LayoutComponent[] | LayoutFunction\n}\n\nexport type ReactPageHandlerArgs = Parameters<PageHandler<ComponentType>>[0]\nexport type ReactInertiaAppConfig = {}\n"
  },
  {
    "path": "packages/react/src/useForm.ts",
    "content": "import {\n  CancelToken,\n  Errors,\n  ErrorValue,\n  FormDataErrors,\n  FormDataKeys,\n  FormDataType,\n  FormDataValues,\n  Method,\n  Progress,\n  RequestPayload,\n  router,\n  UrlMethodPair,\n  UseFormArguments,\n  UseFormSubmitArguments,\n  UseFormSubmitOptions,\n  UseFormTransformCallback,\n  UseFormUtils,\n  UseFormWithPrecognitionArguments,\n  VisitOptions,\n} from '@inertiajs/core'\nimport {\n  createValidator,\n  NamedInputEvent,\n  PrecognitionPath,\n  resolveName,\n  toSimpleValidationErrors,\n  ValidationConfig,\n  Validator,\n} from 'laravel-precognition'\nimport { cloneDeep, get, has, isEqual, set } from 'lodash-es'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { config } from '.'\nimport { useIsomorphicLayoutEffect } from './react'\nimport useRemember from './useRemember'\n\nexport type SetDataByObject<TForm> = (data: Partial<TForm>) => void\nexport type SetDataByMethod<TForm> = (data: (previousData: TForm) => TForm) => void\nexport type SetDataByKeyValuePair<TForm> = <K extends FormDataKeys<TForm>>(\n  key: K,\n  value: FormDataValues<TForm, K>,\n) => void\nexport type SetDataAction<TForm extends Record<any, any>> = SetDataByObject<TForm> &\n  SetDataByMethod<TForm> &\n  SetDataByKeyValuePair<TForm>\n\ntype PrecognitionValidationConfig<TKeys> = ValidationConfig & {\n  only?: TKeys[] | Iterable<TKeys> | ArrayLike<TKeys>\n}\n\nexport interface InertiaFormProps<TForm extends object> {\n  data: TForm\n  isDirty: boolean\n  errors: FormDataErrors<TForm>\n  hasErrors: boolean\n  processing: boolean\n  progress: Progress | null\n  wasSuccessful: boolean\n  recentlySuccessful: boolean\n  setData: SetDataAction<TForm>\n  transform: (callback: UseFormTransformCallback<TForm>) => void\n  setDefaults: {\n    (): void\n    <T extends FormDataKeys<TForm>>(field: T, value: FormDataValues<TForm, T>): void\n    (fields: Partial<TForm>): void\n  }\n  reset: <K extends FormDataKeys<TForm>>(...fields: K[]) => void\n  clearErrors: <K extends FormDataKeys<TForm>>(...fields: K[]) => void\n  resetAndClearErrors: <K extends FormDataKeys<TForm>>(...fields: K[]) => void\n  setError: {\n    <K extends FormDataKeys<TForm>>(field: K, value: ErrorValue): void\n    (errors: FormDataErrors<TForm>): void\n  }\n  submit: (...args: UseFormSubmitArguments) => void\n  get: (url: string, options?: UseFormSubmitOptions) => void\n  patch: (url: string, options?: UseFormSubmitOptions) => void\n  post: (url: string, options?: UseFormSubmitOptions) => void\n  put: (url: string, options?: UseFormSubmitOptions) => void\n  delete: (url: string, options?: UseFormSubmitOptions) => void\n  cancel: () => void\n  dontRemember: <K extends FormDataKeys<TForm>>(...fields: K[]) => InertiaFormProps<TForm>\n  withPrecognition: (...args: UseFormWithPrecognitionArguments) => InertiaPrecognitiveFormProps<TForm>\n}\n\nexport interface InertiaFormValidationProps<TForm extends object> {\n  invalid: <K extends FormDataKeys<TForm>>(field: K) => boolean\n  setValidationTimeout: (duration: number) => InertiaPrecognitiveFormProps<TForm>\n  touch: <K extends FormDataKeys<TForm>>(\n    field: K | NamedInputEvent | Array<K>,\n    ...fields: K[]\n  ) => InertiaPrecognitiveFormProps<TForm>\n  touched: <K extends FormDataKeys<TForm>>(field?: K) => boolean\n  valid: <K extends FormDataKeys<TForm>>(field: K) => boolean\n  validate: <K extends FormDataKeys<TForm> | PrecognitionPath<TForm>>(\n    field?: K | NamedInputEvent | PrecognitionValidationConfig<K>,\n    config?: PrecognitionValidationConfig<K>,\n  ) => InertiaPrecognitiveFormProps<TForm>\n  validateFiles: () => InertiaPrecognitiveFormProps<TForm>\n  validating: boolean\n  validator: () => Validator\n  withAllErrors: () => InertiaPrecognitiveFormProps<TForm>\n  withoutFileValidation: () => InertiaPrecognitiveFormProps<TForm>\n  // Backward compatibility for easy migration from the original Precognition libraries\n  setErrors: (errors: FormDataErrors<TForm>) => InertiaPrecognitiveFormProps<TForm>\n  forgetError: <K extends FormDataKeys<TForm> | NamedInputEvent>(field: K) => InertiaPrecognitiveFormProps<TForm>\n}\n\nexport type InertiaForm<TForm extends object> = InertiaFormProps<TForm>\nexport type InertiaPrecognitiveFormProps<TForm extends object> = InertiaFormProps<TForm> &\n  InertiaFormValidationProps<TForm>\n\nexport default function useForm<TForm extends FormDataType<TForm>>(\n  method: Method | (() => Method),\n  url: string | (() => string),\n  data: TForm | (() => TForm),\n): InertiaPrecognitiveFormProps<TForm>\nexport default function useForm<TForm extends FormDataType<TForm>>(\n  urlMethodPair: UrlMethodPair | (() => UrlMethodPair),\n  data: TForm | (() => TForm),\n): InertiaPrecognitiveFormProps<TForm>\nexport default function useForm<TForm extends FormDataType<TForm>>(\n  rememberKey: string,\n  data: TForm | (() => TForm),\n): InertiaFormProps<TForm>\nexport default function useForm<TForm extends FormDataType<TForm>>(data: TForm | (() => TForm)): InertiaFormProps<TForm>\nexport default function useForm<TForm extends FormDataType<TForm>>(): InertiaFormProps<TForm>\nexport default function useForm<TForm extends FormDataType<TForm>>(\n  ...args: UseFormArguments<TForm>\n): InertiaFormProps<TForm> | InertiaPrecognitiveFormProps<TForm> {\n  const isMounted = useRef(false)\n  const parsedArgs = UseFormUtils.parseUseFormArguments<TForm>(...args)\n\n  const { rememberKey, data: initialData } = parsedArgs\n  const precognitionEndpoint = useRef(parsedArgs.precognitionEndpoint)\n\n  const [defaults, setDefaults] = useState(\n    typeof initialData === 'function' ? cloneDeep(initialData()) : cloneDeep(initialData),\n  )\n  const cancelToken = useRef<CancelToken | null>(null)\n  const recentlySuccessfulTimeoutId = useRef<number>(undefined)\n  const excludeKeysRef = useRef<FormDataKeys<TForm>[]>([])\n  const [data, setData] = rememberKey\n    ? useRemember(defaults, `${rememberKey}:data`, excludeKeysRef)\n    : useState(defaults)\n  const [errors, setErrors] = rememberKey\n    ? useRemember({} as FormDataErrors<TForm>, `${rememberKey}:errors`)\n    : useState({} as FormDataErrors<TForm>)\n  const [hasErrors, setHasErrors] = useState(false)\n  const [processing, setProcessing] = useState(false)\n  const [progress, setProgress] = useState<Progress | null>(null)\n  const [wasSuccessful, setWasSuccessful] = useState(false)\n  const [recentlySuccessful, setRecentlySuccessful] = useState(false)\n  const transform = useRef<UseFormTransformCallback<TForm>>((data) => data)\n  const isDirty = useMemo(() => !isEqual(data, defaults), [data, defaults])\n\n  // Precognition state\n  const validatorRef = useRef<Validator | null>(null)\n  const [validating, setValidating] = useState(false)\n  const [touchedFields, setTouchedFields] = useState<string[]>([])\n  const [validFields, setValidFields] = useState<string[]>([])\n  const withAllErrors = useRef<boolean | null>(null)\n\n  useEffect(() => {\n    isMounted.current = true\n    return () => {\n      isMounted.current = false\n    }\n  }, [])\n\n  // Track if setDefaults was called manually during onSuccess to avoid\n  // overriding user's custom defaults with automatic behavior.\n  const setDefaultsCalledInOnSuccess = useRef(false)\n\n  const submit = useCallback(\n    (...args: UseFormSubmitArguments) => {\n      const { method, url, options } = UseFormUtils.parseSubmitArguments(args, precognitionEndpoint.current)\n\n      setDefaultsCalledInOnSuccess.current = false\n\n      const _options: VisitOptions = {\n        ...options,\n        onCancelToken: (token) => {\n          cancelToken.current = token\n\n          if (options.onCancelToken) {\n            return options.onCancelToken(token)\n          }\n        },\n        onBefore: (visit) => {\n          setWasSuccessful(false)\n          setRecentlySuccessful(false)\n          clearTimeout(recentlySuccessfulTimeoutId.current)\n\n          if (options.onBefore) {\n            return options.onBefore(visit)\n          }\n        },\n        onStart: (visit) => {\n          setProcessing(true)\n\n          if (options.onStart) {\n            return options.onStart(visit)\n          }\n        },\n        onProgress: (event) => {\n          setProgress(event || null)\n\n          if (options.onProgress) {\n            return options.onProgress(event)\n          }\n        },\n        onSuccess: async (page) => {\n          if (isMounted.current) {\n            setProcessing(false)\n            setProgress(null)\n            setErrors({} as FormDataErrors<TForm>)\n            setHasErrors(false)\n            setWasSuccessful(true)\n            setRecentlySuccessful(true)\n            recentlySuccessfulTimeoutId.current = setTimeout(() => {\n              if (isMounted.current) {\n                setRecentlySuccessful(false)\n              }\n            }, config.get('form.recentlySuccessfulDuration'))\n          }\n\n          const onSuccess = options.onSuccess ? await options.onSuccess(page) : null\n\n          if (isMounted.current && !setDefaultsCalledInOnSuccess.current) {\n            setData((data) => {\n              setDefaults(cloneDeep(data))\n              return data\n            })\n          }\n\n          return onSuccess\n        },\n        onError: (errors) => {\n          if (isMounted.current) {\n            setProcessing(false)\n            setProgress(null)\n            setErrors(errors as FormDataErrors<TForm>)\n            setHasErrors(Object.keys(errors).length > 0)\n            validatorRef.current?.setErrors(errors as Errors)\n          }\n\n          if (options.onError) {\n            return options.onError(errors)\n          }\n        },\n        onCancel: () => {\n          if (isMounted.current) {\n            setProcessing(false)\n            setProgress(null)\n          }\n\n          if (options.onCancel) {\n            return options.onCancel()\n          }\n        },\n        onFinish: (visit) => {\n          if (isMounted.current) {\n            setProcessing(false)\n            setProgress(null)\n          }\n\n          cancelToken.current = null\n\n          if (options.onFinish) {\n            return options.onFinish(visit)\n          }\n        },\n      }\n\n      const transformedData = transform.current(data) as RequestPayload\n\n      if (method === 'delete') {\n        router.delete(url, { ..._options, data: transformedData })\n      } else {\n        router[method](url, transformedData, _options)\n      }\n    },\n    [data, setErrors, transform],\n  )\n\n  const setDataFunction = useCallback(\n    (keyOrData: FormDataKeys<TForm> | Function | Partial<TForm>, maybeValue?: any) => {\n      if (typeof keyOrData === 'string') {\n        setData((data) => set(cloneDeep(data), keyOrData, maybeValue))\n      } else if (typeof keyOrData === 'function') {\n        setData((data) => keyOrData(data))\n      } else {\n        setData(keyOrData as TForm)\n      }\n    },\n    [setData],\n  )\n\n  const [dataAsDefaults, setDataAsDefaults] = useState(false)\n\n  const dataRef = useRef(data)\n\n  useEffect(() => {\n    dataRef.current = data\n  })\n\n  const setDefaultsFunction = useCallback(\n    (fieldOrFields?: FormDataKeys<TForm> | Partial<TForm>, maybeValue?: unknown) => {\n      setDefaultsCalledInOnSuccess.current = true\n      let newDefaults = {} as TForm\n\n      if (typeof fieldOrFields === 'undefined') {\n        newDefaults = { ...dataRef.current }\n        setDefaults(dataRef.current)\n        // If setData was called right before setDefaults, data was not\n        // updated in that render yet, so we set a flag to update\n        // defaults right after the next render.\n        setDataAsDefaults(true)\n      } else {\n        setDefaults((defaults) => {\n          newDefaults =\n            typeof fieldOrFields === 'string'\n              ? set(cloneDeep(defaults), fieldOrFields, maybeValue)\n              : Object.assign(cloneDeep(defaults), fieldOrFields)\n\n          return newDefaults as TForm\n        })\n      }\n\n      validatorRef.current?.defaults(newDefaults)\n    },\n    [setDefaults],\n  )\n\n  useIsomorphicLayoutEffect(() => {\n    if (!dataAsDefaults) {\n      return\n    }\n\n    if (isDirty) {\n      // Data has been updated in this next render and is different from\n      // the defaults, so now we can set defaults to the current data.\n      setDefaults(data)\n    }\n\n    setDataAsDefaults(false)\n  }, [dataAsDefaults])\n\n  const reset = useCallback(\n    (...fields: string[]) => {\n      if (fields.length === 0) {\n        setData(defaults)\n      } else {\n        setData((data) =>\n          (fields as Array<FormDataKeys<TForm>>)\n            .filter((key) => has(defaults, key))\n            .reduce(\n              (carry, key) => {\n                return set(carry, key, get(defaults, key))\n              },\n              { ...data } as TForm,\n            ),\n        )\n      }\n\n      validatorRef.current?.reset(...fields)\n    },\n    [setData, defaults],\n  )\n\n  const setError = useCallback(\n    (fieldOrFields: FormDataKeys<TForm> | FormDataErrors<TForm>, maybeValue?: ErrorValue) => {\n      setErrors((errors) => {\n        const newErrors = {\n          ...errors,\n          ...(typeof fieldOrFields === 'string' ? { [fieldOrFields]: maybeValue } : fieldOrFields),\n        }\n        setHasErrors(Object.keys(newErrors).length > 0)\n\n        validatorRef.current?.setErrors(newErrors)\n\n        return newErrors\n      })\n    },\n    [setErrors, setHasErrors],\n  )\n\n  const clearErrors = useCallback(\n    (...fields: string[]) => {\n      setErrors((errors) => {\n        const newErrors = Object.keys(errors).reduce(\n          (carry, field) => ({\n            ...carry,\n            ...(fields.length > 0 && !fields.includes(field) ? { [field]: (errors as Errors)[field] } : {}),\n          }),\n          {},\n        )\n        setHasErrors(Object.keys(newErrors).length > 0)\n\n        if (validatorRef.current) {\n          if (fields.length === 0) {\n            validatorRef.current.setErrors({})\n          } else {\n            fields.forEach(validatorRef.current.forgetError)\n          }\n        }\n\n        return newErrors as FormDataErrors<TForm>\n      })\n    },\n    [setErrors, setHasErrors],\n  )\n\n  const resetAndClearErrors = useCallback(\n    (...fields: string[]) => {\n      reset(...fields)\n      clearErrors(...fields)\n    },\n    [reset, clearErrors],\n  )\n\n  const createSubmitMethod =\n    (method: Method) =>\n    (url: string, options: VisitOptions = {}) => {\n      submit(method, url, options)\n    }\n  const getMethod = useCallback(createSubmitMethod('get'), [submit])\n  const post = useCallback(createSubmitMethod('post'), [submit])\n  const put = useCallback(createSubmitMethod('put'), [submit])\n  const patch = useCallback(createSubmitMethod('patch'), [submit])\n  const deleteMethod = useCallback(createSubmitMethod('delete'), [submit])\n\n  const cancel = useCallback(() => {\n    if (cancelToken.current) {\n      cancelToken.current.cancel()\n    }\n  }, [])\n\n  const transformFunction = useCallback((callback: UseFormTransformCallback<TForm>) => {\n    transform.current = callback\n  }, [])\n\n  // Build base form properties\n  const form = {\n    data,\n    setData: setDataFunction,\n    isDirty,\n    errors,\n    hasErrors,\n    processing,\n    progress,\n    wasSuccessful,\n    recentlySuccessful,\n    transform: transformFunction,\n    setDefaults: setDefaultsFunction,\n    reset,\n    setError,\n    clearErrors,\n    resetAndClearErrors,\n    submit,\n    get: getMethod,\n    post,\n    put,\n    patch,\n    delete: deleteMethod,\n    cancel,\n    dontRemember: <K extends FormDataKeys<TForm>>(...keys: K[]) => {\n      excludeKeysRef.current = keys\n      return form\n    },\n  } as InertiaFormProps<TForm>\n\n  const tap = <T>(value: T, callback: (value: T) => unknown): T => {\n    callback(value)\n    return value\n  }\n\n  const valid = useCallback(\n    <K extends FormDataKeys<TForm>>(field: K) => validFields.includes(field as string),\n    [validFields],\n  )\n\n  const invalid = useCallback(<K extends FormDataKeys<TForm>>(field: K) => field in errors, [errors])\n\n  const touched = useCallback(\n    <K extends FormDataKeys<TForm>>(field?: K) =>\n      typeof field === 'string' ? touchedFields.includes(field as string) : touchedFields.length > 0,\n    [touchedFields],\n  )\n\n  const validate = (field?: string | NamedInputEvent | ValidationConfig, config?: ValidationConfig) => {\n    // Handle config object passed as first argument\n    if (typeof field === 'object' && !('target' in field)) {\n      config = field\n      field = undefined\n    }\n\n    if (field === undefined) {\n      validatorRef.current!.validate(config)\n    } else {\n      const fieldName = resolveName(field)\n      const currentData = dataRef.current\n      const transformedData = transform.current(currentData) as Record<string, unknown>\n      validatorRef.current!.validate(fieldName, get(transformedData, fieldName), config)\n    }\n\n    return form\n  }\n\n  // Create withPrecognition method that returns a precognitive form\n  const withPrecognition = (...args: UseFormWithPrecognitionArguments): InertiaPrecognitiveFormProps<TForm> => {\n    precognitionEndpoint.current = UseFormUtils.createWayfinderCallback(...args)\n\n    if (!validatorRef.current) {\n      const validator = createValidator((client) => {\n        const { method, url } = precognitionEndpoint.current!()\n        // Get the current data from the ref, not the closure\n        const currentData = dataRef.current\n        const transformedData = transform.current(currentData) as Record<string, unknown>\n        return client[method](url, transformedData)\n      }, cloneDeep(defaults))\n\n      validatorRef.current = validator\n\n      validator\n        .on('validatingChanged', () => {\n          setValidating(validator.validating())\n        })\n        .on('validatedChanged', () => {\n          setValidFields(validator.valid())\n        })\n        .on('touchedChanged', () => {\n          setTouchedFields(validator.touched())\n        })\n        .on('errorsChanged', () => {\n          const validationErrors =\n            (withAllErrors.current ?? config.get('form.withAllErrors'))\n              ? validator.errors()\n              : toSimpleValidationErrors(validator.errors())\n\n          setErrors(validationErrors as FormDataErrors<TForm>)\n          setHasErrors(Object.keys(validationErrors).length > 0)\n          setValidFields(validator.valid())\n        })\n    }\n\n    // Create precognitive form with all validation methods\n    const precognitiveForm = Object.assign(form, {\n      validating,\n      validator: () => validatorRef.current!,\n      valid,\n      invalid,\n      touched,\n      withoutFileValidation: () => tap(precognitiveForm, () => validatorRef.current?.withoutFileValidation()),\n      touch: (\n        field: FormDataKeys<TForm> | NamedInputEvent | Array<FormDataKeys<TForm>>,\n        ...fields: FormDataKeys<TForm>[]\n      ) => {\n        if (Array.isArray(field)) {\n          validatorRef.current?.touch(field)\n        } else if (typeof field === 'string') {\n          validatorRef.current?.touch([field, ...fields])\n        } else {\n          validatorRef.current?.touch(field)\n        }\n\n        return precognitiveForm\n      },\n      withAllErrors: () => tap(precognitiveForm, () => (withAllErrors.current = true)),\n      setValidationTimeout: (duration: number) =>\n        tap(precognitiveForm, () => validatorRef.current?.setTimeout(duration)),\n      validateFiles: () => tap(precognitiveForm, () => validatorRef.current?.validateFiles()),\n      validate,\n      setErrors: (errors: FormDataErrors<TForm>) => tap(precognitiveForm, () => form.setError(errors)),\n      forgetError: (field: FormDataKeys<TForm> | NamedInputEvent) =>\n        tap(precognitiveForm, () =>\n          form.clearErrors(resolveName(field as string | NamedInputEvent) as FormDataKeys<TForm>),\n        ),\n    }) as InertiaPrecognitiveFormProps<TForm>\n\n    return precognitiveForm\n  }\n\n  form.withPrecognition = withPrecognition\n\n  return precognitionEndpoint.current ? form.withPrecognition(precognitionEndpoint.current) : form\n}\n"
  },
  {
    "path": "packages/react/src/usePage.ts",
    "content": "import { Page, PageProps, SharedPageProps } from '@inertiajs/core'\nimport React from 'react'\nimport PageContext from './PageContext'\nimport { isReact19 } from './react'\n\nexport default function usePage<TPageProps extends PageProps = PageProps>(): Page<TPageProps & SharedPageProps> {\n  // React.use() was introduced in React 19, fallback to React.useContext() for earlier versions\n  const page = isReact19 ? React.use(PageContext) : React.useContext(PageContext)\n\n  if (!page) {\n    throw new Error('usePage must be used within the Inertia component')\n  }\n\n  return page as Page<TPageProps & SharedPageProps>\n}\n"
  },
  {
    "path": "packages/react/src/usePoll.ts",
    "content": "import { PollOptions, ReloadOptions, router } from '@inertiajs/core'\nimport { useEffect, useRef } from 'react'\n\nexport default function usePoll(\n  interval: number,\n  requestOptions: ReloadOptions = {},\n  options: PollOptions = {\n    keepAlive: false,\n    autoStart: true,\n  },\n) {\n  const pollRef = useRef(\n    router.poll(interval, requestOptions, {\n      ...options,\n      autoStart: false,\n    }),\n  )\n\n  useEffect(() => {\n    if (options.autoStart ?? true) {\n      pollRef.current.start()\n    }\n\n    return () => pollRef.current.stop()\n  }, [])\n\n  return {\n    stop: pollRef.current.stop,\n    start: pollRef.current.start,\n  }\n}\n"
  },
  {
    "path": "packages/react/src/usePrefetch.ts",
    "content": "import { router, VisitOptions } from '@inertiajs/core'\nimport { useEffect, useState } from 'react'\n\nexport default function usePrefetch(options: VisitOptions = {}): {\n  lastUpdatedAt: number | null\n  isPrefetching: boolean\n  isPrefetched: boolean\n  flush: () => void\n} {\n  const cached = typeof window === 'undefined' ? null : router.getCached(window.location.pathname, options)\n  const inFlight = typeof window === 'undefined' ? null : router.getPrefetching(window.location.pathname, options)\n\n  const [lastUpdatedAt, setLastUpdatedAt] = useState<number | null>(cached?.staleTimestamp || null)\n  const [isPrefetching, setIsPrefetching] = useState(inFlight !== null)\n  const [isPrefetched, setIsPrefetched] = useState(cached !== null)\n\n  useEffect(() => {\n    const onPrefetchingListener = router.on('prefetching', (e) => {\n      if (e.detail.visit.url.pathname === window.location.pathname) {\n        setIsPrefetching(true)\n      }\n    })\n\n    const onPrefetchedListener = router.on('prefetched', (e) => {\n      if (e.detail.visit.url.pathname === window.location.pathname) {\n        setIsPrefetching(false)\n        setIsPrefetched(true)\n        setLastUpdatedAt(e.detail.fetchedAt)\n      }\n    })\n\n    return () => {\n      onPrefetchedListener()\n      onPrefetchingListener()\n    }\n  }, [])\n\n  return {\n    lastUpdatedAt,\n    isPrefetching,\n    isPrefetched,\n    flush: () => router.flush(window.location.pathname, options),\n  }\n}\n"
  },
  {
    "path": "packages/react/src/useRemember.ts",
    "content": "import { router } from '@inertiajs/core'\nimport { Dispatch, MutableRefObject, SetStateAction, useEffect, useState } from 'react'\n\nexport default function useRemember<State>(\n  initialState: State,\n  key?: string,\n  excludeKeysRef?: MutableRefObject<string[]>,\n): [State, Dispatch<SetStateAction<State>>] {\n  const [state, setState] = useState(() => {\n    const restored = router.restore(key) as State\n\n    return restored !== undefined ? restored : initialState\n  })\n\n  useEffect(() => {\n    const keys = excludeKeysRef?.current\n    if (keys && keys.length > 0 && typeof state === 'object' && state !== null) {\n      const filtered = { ...state } as Record<string, unknown>\n      keys.forEach((k) => delete filtered[k])\n      router.remember(filtered, key)\n    } else {\n      router.remember(state, key)\n    }\n  }, [state, key])\n\n  return [state, setState]\n}\n"
  },
  {
    "path": "packages/react/test-app/Layouts/NestedLayout.tsx",
    "content": "import { usePage } from '@inertiajs/react'\nimport { useId, useState } from 'react'\n\nexport default ({ children }: { children: React.ReactNode }) => {\n  const [createdAt] = useState(Date.now())\n\n  window._inertia_nested_layout_id = useId()\n  window._inertia_nested_layout_props = usePage().props\n\n  return (\n    <div>\n      <span>Nested Layout</span>\n      <span>{createdAt}</span>\n      <div>{children}</div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Layouts/Prefetch.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default ({ children }: { children: React.ReactNode }) => {\n  return (\n    <div>\n      <Link href=\"/prefetch/1\" prefetch>\n        On Hover (Default)\n      </Link>\n      <Link href=\"/prefetch/2\" prefetch=\"mount\">\n        On Mount\n      </Link>\n      <Link href=\"/prefetch/3\" prefetch=\"click\">\n        On Click\n      </Link>\n      <Link href=\"/prefetch/4\" prefetch={['hover', 'mount']} cacheFor=\"1s\">\n        On Hover + Mount\n      </Link>\n      <Link href=\"/prefetch/5\" prefetch=\"mount\" cacheFor=\"0\">\n        On Mount (Once)\n      </Link>\n      <Link href=\"/prefetch/6\" prefetch=\"click\">\n        On Enter\n      </Link>\n      <Link href=\"/prefetch/7\" prefetch=\"click\" as=\"button\">\n        On Spacebar\n      </Link>\n      <div>{children}</div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Layouts/SWR.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default ({ children }: { children: React.ReactNode }) => {\n  return (\n    <div>\n      <Link href=\"/prefetch/swr/2\" prefetch cacheFor=\"1s\">\n        1s Expired\n      </Link>\n      <Link href=\"/prefetch/swr/3\" prefetch cacheFor={1000}>\n        1s Expired (Number)\n      </Link>\n      <Link href=\"/prefetch/swr/4\" prefetch cacheFor={['1s', '3s']}>\n        1s Stale, 2s Expired\n      </Link>\n      <Link href=\"/prefetch/swr/5\" prefetch cacheFor={[1000, 3000]}>\n        1s Stale, 2s Expired (Number)\n      </Link>\n      <div>{children}</div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Layouts/SiteLayout.tsx",
    "content": "import { usePage } from '@inertiajs/react'\nimport { useId, useState } from 'react'\n\nexport default ({ children }: { children: React.ReactNode }) => {\n  const [createdAt] = useState(Date.now())\n\n  window._inertia_layout_id = useId()\n  window._inertia_site_layout_props = usePage().props\n\n  return (\n    <div>\n      <span>Site Layout</span>\n      <span>{createdAt}</span>\n      <div>{children}</div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Layouts/WithScrollRegion.tsx",
    "content": "import { useEffect, useState } from 'react'\n\nexport default ({ children }: { children: React.ReactNode }) => {\n  const [documentScrollTop, setDocumentScrollTop] = useState(0)\n  const [documentScrollLeft, setDocumentScrollLeft] = useState(0)\n  const [slotScrollTop, setSlotScrollTop] = useState(0)\n  const [slotScrollLeft, setSlotScrollLeft] = useState(0)\n\n  const handleScrollEvent = () => {\n    setDocumentScrollLeft(document.documentElement.scrollLeft)\n    setDocumentScrollTop(document.documentElement.scrollTop)\n    const slot = document.getElementById('slot')\n    if (slot) {\n      setSlotScrollTop(slot.scrollTop)\n      setSlotScrollLeft(slot.scrollLeft)\n    }\n  }\n\n  useEffect(() => {\n    document.addEventListener('scroll', handleScrollEvent)\n\n    return () => {\n      document.removeEventListener('scroll', handleScrollEvent)\n    }\n  })\n\n  return (\n    <div style={{ width: '200vw' }}>\n      <span className=\"layout-text\">With scroll regions</span>\n      <button onClick={handleScrollEvent}>Update scroll positions</button>\n      <div className=\"document-position\">\n        Document scroll position is {documentScrollLeft} & {documentScrollTop}\n      </div>\n      <div style={{ height: '200vh' }}>\n        <span className=\"slot-position\">\n          Slot scroll position is {slotScrollLeft} & {slotScrollTop}\n        </span>\n        <div\n          scroll-region=\"\"\n          id=\"slot\"\n          style={{ height: '100px', width: '500px', overflow: 'scroll' }}\n          onScroll={handleScrollEvent}\n        >\n          {children}\n        </div>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Layouts/WithoutScrollRegion.tsx",
    "content": "import { useEffect, useState } from 'react'\n\nexport default ({ children }: { children: React.ReactNode }) => {\n  const [documentScrollTop, setDocumentScrollTop] = useState(0)\n  const [documentScrollLeft, setDocumentScrollLeft] = useState(0)\n  const [slotScrollTop, setSlotScrollTop] = useState(0)\n  const [slotScrollLeft, setSlotScrollLeft] = useState(0)\n\n  const handleScrollEvent = () => {\n    setDocumentScrollLeft(document.documentElement.scrollLeft)\n    setDocumentScrollTop(document.documentElement.scrollTop)\n    const slot = document.getElementById('slot')\n    if (slot) {\n      setSlotScrollTop(slot.scrollTop)\n      setSlotScrollLeft(slot.scrollLeft)\n    }\n  }\n\n  useEffect(() => {\n    document.addEventListener('scroll', handleScrollEvent)\n\n    return () => {\n      document.removeEventListener('scroll', handleScrollEvent)\n    }\n  })\n\n  return (\n    <div style={{ width: '200vw' }}>\n      <span className=\"layout-text\">Without scroll regions</span>\n      <button onClick={handleScrollEvent}>Update scroll positions</button>\n      <div className=\"document-position\">\n        Document scroll position is {documentScrollLeft} & {documentScrollTop}\n      </div>\n      <div style={{ height: '200vh' }}>\n        <span className=\"slot-position\">\n          Slot scroll position is {slotScrollLeft} & {slotScrollTop}\n        </span>\n        <div id=\"slot\" style={{ height: '100px', width: '500px', overflow: 'scroll' }} onScroll={handleScrollEvent}>\n          {children}\n        </div>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Article.tsx",
    "content": "import { Link } from '@inertiajs/react'\nimport { useEffect, useState } from 'react'\n\nexport default () => {\n  const enableSmoothScroll = () => {\n    document.documentElement.style.scrollBehavior = 'smooth'\n  }\n\n  const [scrollLog, setScrollLog] = useState<number[]>([])\n\n  const handleScrollEvent = () => {\n    setScrollLog((prev) => [...prev, document.documentElement.scrollTop])\n  }\n\n  useEffect(() => {\n    document.addEventListener('scroll', handleScrollEvent)\n    return () => document.removeEventListener('scroll', handleScrollEvent)\n  })\n\n  return (\n    <>\n      <h1 style={{ fontSize: '40px' }}>Article Header</h1>\n      <article style={{ fontSize: '20px', maxWidth: '500px' }}>\n        <p>\n          Sunt culpa sit sunt enim aliquip. Esse ea ea quis voluptate. Enim consectetur aliqua ex ex magna cupidatat id\n          minim sit elit. Amet pariatur occaecat pariatur duis eiusmod dolore magna. Et commodo cupidatat in commodo\n          elit cupidatat minim qui id non enim ad. Culpa aliquip ad Lorem sit consectetur ullamco culpa duis nisi et\n          fugiat mollit eiusmod. Laboris voluptate veniam consequat proident in nulla irure velit.\n        </p>\n        <p>\n          Sit sint laboris sunt eiusmod ipsum laborum eiusmod amet commodo exercitation in duis magna. Proident sunt\n          minim in elit qui. Id pariatur commodo fugiat excepteur in deserunt Lorem ipsum occaecat est. Excepteur sit\n          tempor ipsum ex officia veniam enim amet velit fugiat mollit cillum. Incididunt aliqua nulla id occaecat\n          nulla. Non ea ad est occaecat deserunt officia qui commodo exercitation.\n        </p>\n        <p>\n          Voluptate laborum quis aliqua ullamco magna amet ullamco laborum qui cillum eu. Dolore dolore aliqua proident\n          proident sunt ipsum in. Enim velit dolore labore dolor quis incididunt duis culpa Lorem. Eu adipisicing non\n          elit fugiat voluptate labore ipsum dolore consectetur commodo. Et in et cillum duis consequat quis ex eu\n          commodo. Eiusmod aliqua excepteur consectetur eiusmod aute et consectetur sit pariatur dolore qui officia\n          pariatur.\n        </p>\n        <p>\n          Non sunt eu mollit qui reprehenderit. Aute culpa anim voluptate do in esse duis laborum ad dolore. Ullamco\n          nisi in nostrud officia do. Duis pariatur officia id duis. Deserunt ad incididunt est sint consectetur\n          reprehenderit mollit est Lorem ea pariatur anim dolor adipisicing. Nostrud irure magna nostrud laboris aute\n          sunt veniam laboris veniam incididunt sit. Nulla proident ad aliqua fugiat culpa sunt est in dolor velit ad\n          irure nulla.\n        </p>\n        <p>\n          Do aute laborum deserunt non laborum voluptate voluptate. Anim ut laborum magna sunt cupidatat irure.\n          Cupidatat fugiat minim sint cillum laborum excepteur irure id est irure ad occaecat adipisicing enim. Deserunt\n          nulla anim proident velit irure nostrud est est reprehenderit consequat pariatur qui. Fugiat Lorem sint eu\n          laborum minim pariatur cillum mollit nulla consequat ullamco ex. Ex consectetur ad ut irure fugiat occaecat\n          aliqua exercitation cillum ipsum anim dolore tempor.\n        </p>\n        <p>\n          Adipisicing consequat irure fugiat Lorem deserunt aliquip do cupidatat. Lorem labore elit ex qui nostrud qui\n          cillum sunt adipisicing occaecat. Sunt nostrud amet amet cupidatat fugiat Lorem quis nulla id cillum esse eu.\n          Ullamco aliqua dolore irure amet mollit anim velit dolore.\n        </p>\n        <p>\n          Veniam cupidatat ipsum ea officia ipsum nisi laborum culpa qui dolore. Aliqua Lorem nisi labore ea velit\n          aliquip irure excepteur eu. Laboris proident duis non labore sunt quis aute tempor laboris enim anim eiusmod.\n        </p>\n        <p>\n          Minim proident ut aliqua ea ut culpa fugiat ullamco nisi esse nostrud reprehenderit id. Id id ullamco velit\n          anim nisi magna Lorem tempor. Et veniam occaecat ut labore consequat fugiat duis.\n        </p>\n        <p>\n          Adipisicing ea consectetur adipisicing aute eu pariatur enim labore consequat occaecat consectetur minim nisi.\n          Cillum commodo sunt labore reprehenderit. Duis esse excepteur magna tempor eiusmod exercitation Lorem\n          reprehenderit excepteur pariatur. Esse cupidatat occaecat magna do aliquip Lorem. Consectetur adipisicing\n          consequat dolore nostrud esse eu cillum id commodo duis. Aliquip dolor cillum cupidatat fugiat.\n        </p>\n        <p>\n          Ex eiusmod id est laborum sunt ex ea aute adipisicing ad magna deserunt duis. Nostrud velit dolore id commodo\n          quis enim fugiat. Sint non quis consectetur voluptate aliqua dolore ad voluptate nulla. Irure sit\n          reprehenderit sint laboris non elit. Duis minim nisi esse dolor. Sit ex in consequat non occaecat commodo\n          irure et. Commodo qui ipsum Lorem magna consequat consequat et minim eiusmod Lorem eiusmod cupidatat\n          voluptate.\n        </p>\n        <h2 id=\"far-down\">Far down</h2>\n        <p>\n          Ex eiusmod id est laborum sunt ex ea aute adipisicing ad magna deserunt duis. Nostrud velit dolore id commodo\n          quis enim fugiat. Sint non quis consectetur voluptate aliqua dolore ad voluptate nulla. Irure sit\n          reprehenderit sint laboris non elit. Duis minim nisi esse dolor. Sit ex in consequat non occaecat commodo\n          irure et. Commodo qui ipsum Lorem magna consequat consequat et minim eiusmod Lorem eiusmod cupidatat\n          voluptate.\n        </p>\n      </article>\n\n      <div className=\"document-position\">Scroll log: {JSON.stringify(scrollLog)}</div>\n\n      <Link id=\"home\" data-testid=\"home\" href=\"/\">\n        {' '}\n        Home{' '}\n      </Link>\n\n      <Link id=\"article-far-down\" data-testid=\"article-far-down\" href=\"/article#far-down\">\n        {' '}\n        Article Far Down{' '}\n      </Link>\n\n      <button id=\"enable-smooth-scroll\" data-testid=\"enable-smooth-scroll\" onClick={enableSmoothScroll}>\n        Enable Smooth Scroll\n      </button>\n\n      <button id=\"clear-scroll-log\" data-testid=\"clear-scroll-log\" onClick={() => setScrollLog([])}>\n        Clear Scroll Log\n      </button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/ClientSideVisit/Page1.tsx",
    "content": "import { Page } from '@inertiajs/core'\nimport { router } from '@inertiajs/react'\nimport { useState } from 'react'\n\ninterface PageProps {\n  foo: string\n  bar: string\n}\n\nexport default ({ foo, bar }: PageProps) => {\n  const [errors, setErrors] = useState(0)\n  const [finished, setFinished] = useState(0)\n  const [success, setSuccess] = useState(0)\n  const [random] = useState(Math.random())\n\n  const bagErrors = () => {\n    router.replace({\n      preserveState: true,\n      props: (props: Page['props']) => ({ ...props, errors: { bag: { foo: 'bar' } } }),\n      errorBag: 'bag',\n      onError: (err) => {\n        setErrors(Object.keys(err).length)\n      },\n      onFinish: () => setFinished(finished + 1),\n      onSuccess: () => setSuccess(success + 1),\n    })\n  }\n\n  const defaultErrors = () => {\n    router.replace({\n      preserveState: true,\n      props: (props: PageProps) => ({ ...props, errors: { foo: 'bar', baz: 'qux' } }),\n      onError: (err) => {\n        setErrors(Object.keys(err).length)\n      },\n      onFinish: () => setFinished(finished + 1),\n      onSuccess: () => setSuccess(success + 1),\n    })\n  }\n\n  const replace = () => {\n    router.replace({\n      preserveState: true,\n      props: (props) => ({ ...props, foo: 'foo from client' }),\n      onFinish: () => setFinished(finished + 1),\n      onSuccess: () => setSuccess(success + 1),\n    })\n  }\n\n  const replaceAndPreserveStateWithErrors = (errors = {}) => {\n    router.replace({\n      preserveState: 'errors',\n      props: (props: PageProps) => ({ ...props, errors }),\n    })\n  }\n\n  const push = () => {\n    router.push({\n      url: '/client-side-visit-2',\n      component: 'ClientSideVisit/Page2',\n      props: { baz: 'baz from client' },\n    })\n  }\n\n  return (\n    <div>\n      <div>{foo}</div>\n      <div>{bar}</div>\n      <button onClick={replace}>Replace</button>\n      <button onClick={() => replaceAndPreserveStateWithErrors({ name: 'Field is required' })}>\n        Replace with errors\n      </button>\n      <button onClick={() => replaceAndPreserveStateWithErrors()}>Replace without errors</button>\n      <button onClick={push}>Push</button>\n      <button onClick={defaultErrors}>Errors (default)</button>\n      <button onClick={bagErrors}>Errors (bag)</button>\n      <div>Errors: {errors}</div>\n      <div>Finished: {finished}</div>\n      <div>Success: {success}</div>\n      <div id=\"random\">Random: {random}</div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/ClientSideVisit/Page2.tsx",
    "content": "export default ({ baz }: { baz: string }) => {\n  return <div>{baz}</div>\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/ClientSideVisit/Props.tsx",
    "content": "import { router } from '@inertiajs/react'\n\ninterface Tag {\n  id: number\n  name: string\n}\n\ninterface User {\n  name: string\n  age: number\n}\n\nexport default ({\n  items = [],\n  tags = [],\n  user,\n  count = 0,\n  singleValue,\n  undefinedValue,\n}: {\n  items?: string[]\n  tags?: Tag[]\n  user?: User\n  count?: number\n  singleValue?: string | string[]\n  undefinedValue?: string | string[]\n}) => {\n  const replacePropString = () => {\n    router.replaceProp('user.name', 'Jane Smith')\n  }\n\n  const replacePropNumber = () => {\n    router.replaceProp('count', 10)\n  }\n\n  const replacePropFunction = () => {\n    router.replaceProp('count', (oldValue: number) => oldValue * 2)\n  }\n\n  const appendToPropArray = () => {\n    router.appendToProp('items', 'item3')\n  }\n\n  const appendToPropMultiple = () => {\n    router.appendToProp('items', ['item4', 'item5'])\n  }\n\n  const appendToPropFunction = () => {\n    router.appendToProp('tags', () => ({ id: 3, name: 'tag3' }))\n  }\n\n  const appendArrayToArray = () => {\n    router.appendToProp('tags', [\n      { id: 3, name: 'tag3' },\n      { id: 4, name: 'tag4' },\n    ])\n  }\n\n  const prependToPropArray = () => {\n    router.prependToProp('items', 'item0')\n  }\n\n  const prependToPropMultiple = () => {\n    router.prependToProp('items', ['itemA', 'itemB'])\n  }\n\n  const prependToPropFunction = () => {\n    router.prependToProp('tags', () => ({ id: 0, name: 'tag0' }))\n  }\n\n  // Edge case tests for mergeArrays behavior\n  const appendToNonArray = () => {\n    router.appendToProp('singleValue', 'world')\n  }\n\n  const prependToNonArray = () => {\n    router.prependToProp('singleValue', 'hey')\n  }\n\n  const appendArrayToNonArray = () => {\n    router.appendToProp('singleValue', ['there', 'world'])\n  }\n\n  const prependArrayToNonArray = () => {\n    router.prependToProp('singleValue', ['hey', 'hi'])\n  }\n\n  const appendToUndefined = () => {\n    router.appendToProp('undefinedValue', 'new value')\n  }\n\n  const prependToUndefined = () => {\n    router.prependToProp('undefinedValue', 'start value')\n  }\n\n  return (\n    <div>\n      <h1>Client Side Visit Props Testing</h1>\n\n      <div>\n        User: {user?.name || 'Unknown'} (Age: {user?.age || 'Unknown'})\n      </div>\n      <div>Count: {count}</div>\n\n      <div>Items: {JSON.stringify(items)}</div>\n      <div>Tags: {JSON.stringify(tags)}</div>\n      <div>Single Value: {JSON.stringify(singleValue)}</div>\n      <div>Undefined Value: {JSON.stringify(undefinedValue)}</div>\n\n      <hr />\n\n      <h2>Replace Prop Tests</h2>\n      <button onClick={replacePropString}>Replace user.name</button>\n      <button onClick={replacePropNumber}>Replace count</button>\n      <button onClick={replacePropFunction}>Replace count (function)</button>\n\n      <h2>Append To Prop Tests</h2>\n      <button onClick={appendToPropArray}>Append to items (single)</button>\n      <button onClick={appendToPropMultiple}>Append to items (multiple)</button>\n      <button onClick={appendToPropFunction}>Append to tags (function)</button>\n      <button onClick={appendArrayToArray}>Append array to array (objects)</button>\n\n      <h2>Prepend To Prop Tests</h2>\n      <button onClick={prependToPropArray}>Prepend to items (single)</button>\n      <button onClick={prependToPropMultiple}>Prepend to items (multiple)</button>\n      <button onClick={prependToPropFunction}>Prepend to tags (function)</button>\n\n      <h2>Edge Case Tests (mergeArrays behavior)</h2>\n      <button onClick={appendToNonArray}>Append to non-array (single + single)</button>\n      <button onClick={prependToNonArray}>Prepend to non-array (single + single)</button>\n      <button onClick={appendArrayToNonArray}>Append array to non-array (single + array)</button>\n      <button onClick={prependArrayToNonArray}>Prepend array to non-array (array + single)</button>\n      <button onClick={appendToUndefined}>Append to undefined</button>\n      <button onClick={prependToUndefined}>Prepend to undefined</button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/ClientSideVisit/Sequential.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default ({ foo = '', bar = '' }: { foo?: string; bar?: string }) => {\n  const replaceSequentially = () => {\n    router.replaceProp('foo', 'baz')\n    router.replaceProp('bar', 'qux')\n  }\n\n  return (\n    <div>\n      <p>Foo: {foo}</p>\n      <p>Bar: {bar}</p>\n\n      <button onClick={replaceSequentially}>Replace foo and bar sequentially</button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/ComplexMergeSelective.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default ({\n  mixed,\n}: {\n  mixed: {\n    name: string\n    users: string[]\n    chat: { data: number[] }\n    post: { id: number; comments: { allowed: boolean; data: string[] } }\n  }\n}) => {\n  const reload = () => {\n    router.reload({\n      only: ['mixed'],\n    })\n  }\n\n  return (\n    <div>\n      <div>name is {mixed.name}</div>\n      <div>users: {mixed.users.join(', ')}</div>\n      <div>chat.data: {mixed.chat.data.join(', ')}</div>\n      <div>post.id: {mixed.post.id}</div>\n      <div>post.comments.allowed: {mixed.post.comments.allowed ? 'true' : 'false'}</div>\n      <div>post.comments.data: {mixed.post.comments.data.join(', ')}</div>\n      <button onClick={reload}>Reload</button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/CustomConfig.tsx",
    "content": "import type { VisitOptions } from '@inertiajs/core'\nimport { config, Link, useForm, usePage } from '@inertiajs/react'\n\nexport default () => {\n  const page = usePage()\n  const form = useForm({})\n\n  const submit = () => {\n    form.post(page.url)\n  }\n\n  config.set({\n    'form.recentlySuccessfulDuration': 1000,\n    'prefetch.cacheFor': '2s',\n  })\n\n  config.set('visitOptions', (href: string, options: VisitOptions) => {\n    if (href !== '/dump/post') {\n      return {}\n    }\n\n    return { headers: { ...options.headers, 'X-From-Callback': 'bar' } }\n  })\n\n  return (\n    <div>\n      <Link prefetch href=\"/dump/get\">\n        Prefetch Link\n      </Link>\n      <Link method=\"post\" headers={{ 'X-From-Link': 'foo' }} href=\"/dump/post\">\n        Post Dump\n      </Link>\n      <button onClick={submit}>Submit Form</button>\n      {form.recentlySuccessful && <p>Form was recently successful!</p>}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/DeepMergeProps.tsx",
    "content": "import { router } from '@inertiajs/react'\nimport { useState } from 'react'\n\ntype PageProps = {\n  bar: number[]\n  foo: { page: number; data: number[]; per_page: number; meta: { label: string } }\n  baz: number[]\n}\n\nexport default ({ bar, foo, baz }: PageProps) => {\n  const [page, setPage] = useState(foo.page)\n\n  const reloadIt = () => {\n    router.reload({\n      data: {\n        page,\n      },\n      only: ['foo', 'baz'],\n      onSuccess(visit) {\n        setPage((visit.props as unknown as PageProps).foo.page)\n      },\n    })\n  }\n\n  const getFresh = () => {\n    setPage(0)\n    router.visit('/deep-merge-props', {\n      reset: ['foo', 'baz'],\n    })\n  }\n\n  return (\n    <>\n      <div>bar count is {bar.length}</div>\n      <div>baz count is {baz.length}</div>\n      <div>foo.data count is {foo.data.length}</div>\n      <div>foo.page is {foo.page}</div>\n      <div>foo.per_page is {foo.per_page}</div>\n      <div>foo.meta.label is {foo.meta.label}</div>\n      <button onClick={reloadIt}>Reload</button>\n      <button onClick={getFresh}>Get Fresh</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/DeferredProps/BackButton/PageA.tsx",
    "content": "import { Deferred, Link, usePage } from '@inertiajs/react'\n\nconst FastProp = () => {\n  const { fastProp } = usePage<{ fastProp?: string }>().props\n\n  return fastProp\n}\n\nconst SlowProp = () => {\n  const { slowProp } = usePage<{ slowProp?: string }>().props\n\n  return slowProp\n}\n\nexport default () => {\n  return (\n    <>\n      <Deferred data=\"fastProp\" fallback={<div>Loading fast prop...</div>}>\n        <FastProp />\n      </Deferred>\n\n      <Deferred data=\"slowProp\" fallback={<div>Loading slow prop...</div>}>\n        <SlowProp />\n      </Deferred>\n\n      <Link href=\"/deferred-props/back-button/b\">Go to Page B</Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/DeferredProps/BackButton/PageB.tsx",
    "content": "import { Deferred, Link, usePage } from '@inertiajs/react'\n\nconst Data = () => {\n  const { data } = usePage<{ data?: string }>().props\n\n  return data\n}\n\nexport default () => {\n  return (\n    <>\n      <Deferred data=\"data\" fallback={<div>Loading data...</div>}>\n        <Data />\n      </Deferred>\n\n      <Link href=\"/deferred-props/back-button/a\">Go to Page A</Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/DeferredProps/InstantReload.tsx",
    "content": "import { Deferred, router } from '@inertiajs/react'\nimport { useEffect } from 'react'\n\nexport default ({ foo, bar }: { foo?: { text: string }; bar?: { text: string } }) => {\n  useEffect(() => {\n    router.reload({\n      only: ['foo'],\n    })\n  }, [])\n\n  return (\n    <>\n      <Deferred data=\"foo\" fallback={<div>Loading foo...</div>}>\n        <div>{foo?.text}</div>\n      </Deferred>\n\n      <Deferred data=\"bar\" fallback={<div>Loading bar...</div>}>\n        <div>{bar?.text}</div>\n      </Deferred>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/DeferredProps/ManyGroups.tsx",
    "content": "import { Deferred, Link, usePage } from '@inertiajs/react'\n\nexport default () => {\n  const { foo, bar, baz, qux, quux } = usePage<{\n    foo?: { text: string }\n    bar?: { text: string }\n    baz?: { text: string }\n    qux?: { text: string }\n    quux?: { text: string }\n  }>().props\n\n  return (\n    <>\n      <Deferred data=\"foo\" fallback={<div>Loading foo...</div>}>\n        {foo?.text}\n      </Deferred>\n\n      <Deferred data=\"bar\" fallback={<div>Loading bar...</div>}>\n        {bar?.text}\n      </Deferred>\n\n      <Deferred data=\"baz\" fallback={<div>Loading baz...</div>}>\n        {baz?.text}\n      </Deferred>\n\n      <Deferred data=\"qux\" fallback={<div>Loading qux...</div>}>\n        {qux?.text}\n      </Deferred>\n\n      <Deferred data=\"quux\" fallback={<div>Loading quux...</div>}>\n        {quux?.text}\n      </Deferred>\n\n      <Link href=\"/deferred-props/page-1\">Page 1</Link>\n      <Link href=\"/deferred-props/page-2\">Page 2</Link>\n      <Link href=\"/deferred-props/many-groups\">Many groups</Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/DeferredProps/Page1.tsx",
    "content": "import { Deferred, Link, usePage } from '@inertiajs/react'\n\nconst Foo = () => {\n  const { foo } = usePage<{ foo?: { text: string } }>().props\n\n  return foo?.text\n}\n\nconst Bar = () => {\n  const { bar } = usePage<{ bar?: { text: string } }>().props\n\n  return bar?.text\n}\n\nexport default () => {\n  return (\n    <>\n      <Deferred data=\"foo\" fallback={<div>Loading foo...</div>}>\n        <Foo />\n      </Deferred>\n\n      <Deferred data=\"bar\" fallback={() => <div>Loading bar...</div>}>\n        {() => <Bar />}\n      </Deferred>\n\n      <Link href=\"/deferred-props/page-1\">Page 1</Link>\n      <Link href=\"/deferred-props/page-2\">Page 2</Link>\n      <Link href=\"/deferred-props/page-3\" prefetch>\n        Page 3\n      </Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/DeferredProps/Page2.tsx",
    "content": "import { Deferred, Link, usePage } from '@inertiajs/react'\n\nconst Baz = () => {\n  const { baz } = usePage<{ baz?: string }>().props\n\n  return baz\n}\n\nconst Qux = () => {\n  const { qux } = usePage<{ qux?: string }>().props\n\n  return qux\n}\n\nconst Both = () => {\n  const { baz, qux } = usePage<{ baz?: string; qux?: string }>().props\n\n  return `both ${baz} and ${qux}`\n}\nexport default () => {\n  return (\n    <>\n      <Deferred data=\"baz\" fallback={<div>Loading baz...</div>}>\n        <Baz />\n      </Deferred>\n\n      <Deferred data=\"qux\" fallback={<div>Loading qux...</div>}>\n        <Qux />\n      </Deferred>\n\n      <Deferred data={['baz', 'qux']} fallback={<div>Loading baz and qux...</div>}>\n        <Both />\n      </Deferred>\n\n      <Link href=\"/deferred-props/page-2\">Page 2</Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/DeferredProps/Page3.tsx",
    "content": "import { Deferred, usePage } from '@inertiajs/react'\n\nconst Alpha = () => {\n  const { alpha } = usePage<{ alpha?: string }>().props\n\n  return alpha\n}\n\nconst Beta = () => {\n  const { beta } = usePage<{ beta?: string }>().props\n\n  return beta\n}\n\nexport default () => {\n  return (\n    <>\n      <Deferred data=\"alpha\" fallback={<div>Loading alpha...</div>}>\n        <Alpha />\n      </Deferred>\n\n      <Deferred data=\"beta\" fallback={<div>Loading beta...</div>}>\n        <Beta />\n      </Deferred>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/DeferredProps/PartialReloads.tsx",
    "content": "import { Deferred, router, usePage } from '@inertiajs/react'\n\nconst FooTimestamp = () => {\n  const { foo } = usePage<{ foo?: { timestamp: string } }>().props\n\n  return <div id=\"foo-timestamp\">{foo?.timestamp}</div>\n}\n\nconst BarTimestamp = () => {\n  const { bar } = usePage<{ bar?: { timestamp: string } }>().props\n\n  return <div id=\"bar-timestamp\">{bar?.timestamp}</div>\n}\n\nconst PartialReloads = () => {\n  const reloadOnlyFoo = () => {\n    router.reload({\n      only: ['foo'],\n    })\n  }\n\n  const reloadOnlyBar = () => {\n    router.reload({\n      only: ['bar'],\n    })\n  }\n\n  const reloadBoth = () => {\n    router.reload({\n      only: ['foo', 'bar'],\n    })\n  }\n\n  return (\n    <>\n      <Deferred data=\"foo\" fallback={<div>Loading foo...</div>}>\n        <FooTimestamp />\n      </Deferred>\n\n      <Deferred data=\"bar\" fallback={<div>Loading bar...</div>}>\n        <BarTimestamp />\n      </Deferred>\n\n      <button onClick={reloadOnlyFoo}>Reload foo only</button>\n      <button onClick={reloadOnlyBar}>Reload bar only</button>\n      <button onClick={reloadBoth}>Reload both</button>\n    </>\n  )\n}\n\nexport default PartialReloads\n"
  },
  {
    "path": "packages/react/test-app/Pages/DeferredProps/RapidNavigation.tsx",
    "content": "import { Deferred, Link, router, usePage } from '@inertiajs/react'\n\nconst Users = () => {\n  const { users } = usePage<{ users?: { text: string } }>().props\n  return <div>{users?.text}</div>\n}\n\nconst Stats = () => {\n  const { stats } = usePage<{ stats?: { text: string } }>().props\n  return <div>{stats?.text}</div>\n}\n\nconst Activity = () => {\n  const { activity } = usePage<{ activity?: { text: string } }>().props\n  return <div>{activity?.text}</div>\n}\n\nexport default () => {\n  const { id } = usePage<{ id: string }>().props\n\n  return (\n    <>\n      <div>Page: {id}</div>\n\n      <Deferred data=\"users\" fallback={<div>Loading users...</div>}>\n        <Users />\n      </Deferred>\n\n      <Deferred data=\"stats\" fallback={<div>Loading stats...</div>}>\n        <Stats />\n      </Deferred>\n\n      <Deferred data=\"activity\" fallback={<div>Loading activity...</div>}>\n        <Activity />\n      </Deferred>\n\n      <Link href=\"/deferred-props/rapid-navigation/a\">Page A</Link>\n      <Link href=\"/deferred-props/rapid-navigation/b\">Page B</Link>\n      <Link href=\"/deferred-props/rapid-navigation/c\">Page C</Link>\n      <Link href=\"/deferred-props/page-1\">Navigate Away</Link>\n\n      <button\n        onClick={() => {\n          const shouldNavigate = confirm('Navigate away?')\n          if (shouldNavigate) {\n            router.visit('/deferred-props/page-2')\n          }\n        }}\n      >\n        Navigate with onBefore\n      </button>\n\n      <button onClick={() => router.reload()}>Plain reload</button>\n\n      <button onClick={() => router.visit(`/deferred-props/rapid-navigation/${id}?foo=bar`)}>Add query param</button>\n\n      <button onClick={() => router.prefetch('/deferred-props/page-1')}>Prefetch Page 1</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/DeferredProps/ReloadWithoutOptionalChaining.tsx",
    "content": "import { Deferred, router, usePage } from '@inertiajs/react'\n\nconst Results = () => {\n  const { results } = usePage<{ results: { data: string[]; page: number } }>().props\n\n  return (\n    <>\n      <div id=\"results-data\">{results.data.join(', ')}</div>\n      <div id=\"results-page\">Page: {results.page}</div>\n    </>\n  )\n}\n\nexport default () => {\n  const handleReload = () => {\n    router.reload({\n      data: { page: 2 },\n    })\n  }\n\n  return (\n    <>\n      <Deferred data=\"results\" fallback={<div>Loading results...</div>}>\n        <Results />\n      </Deferred>\n\n      <button onClick={handleReload}>Reload with page 2</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/DeferredProps/WithErrors.tsx",
    "content": "import { Deferred, useForm, usePage } from '@inertiajs/react'\n\nconst Foo = () => {\n  const { foo } = usePage<{ foo?: { text: string } }>().props\n\n  return <div id=\"foo\">{foo?.text}</div>\n}\n\nexport default () => {\n  const { errors } = usePage<{ errors: { name?: string } }>().props\n  const form = useForm({\n    name: '',\n  })\n\n  const submit = () => {\n    form.post('/deferred-props/with-errors')\n  }\n\n  return (\n    <>\n      <Deferred data=\"foo\" fallback={<div>Loading foo...</div>}>\n        <Foo />\n      </Deferred>\n\n      {errors?.name && <p id=\"page-error\">{errors.name}</p>}\n      {form.errors.name && <p id=\"form-error\">{form.errors.name}</p>}\n\n      <button type=\"button\" onClick={submit}>\n        Submit\n      </button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/DeferredProps/WithPartialReload.tsx",
    "content": "import { Deferred, Link, router, usePage } from '@inertiajs/react'\n\nconst WithPartialReload = ({ withOnly, withExcept }: { withOnly?: string[]; withExcept?: string[] }) => {\n  const handleTriggerPartialReload = () => {\n    router.reload({\n      only: withOnly,\n      except: withExcept,\n    })\n  }\n\n  return (\n    <div>\n      <Deferred data=\"users\" fallback={<span>Loading...</span>}>\n        <DeferredUsers />\n      </Deferred>\n      <button onClick={handleTriggerPartialReload}>Trigger a partial reload</button>\n      <Link href=\"/deferred-props/page-1\" prefetch=\"hover\">\n        Prefetch\n      </Link>\n    </div>\n  )\n}\n\nconst DeferredUsers = () => {\n  const props = usePage<{ users?: Array<{ id: number; name: string }> }>().props\n\n  return (\n    <div>\n      {props.users?.map((user) => (\n        <span key={user.id}>{user.name}</span>\n      ))}\n    </div>\n  )\n}\n\nexport default WithPartialReload\n"
  },
  {
    "path": "packages/react/test-app/Pages/DeferredProps/WithQueryParams.tsx",
    "content": "import { Deferred, usePage } from '@inertiajs/react'\n\nconst Users = () => {\n  const { users } = usePage<{ users?: { text: string } }>().props\n\n  return <div>{users?.text}</div>\n}\n\nexport default () => {\n  const { filter } = usePage<{ filter: string }>().props\n\n  return (\n    <>\n      <div>Filter: {filter}</div>\n\n      <Deferred data=\"users\" fallback={<div>Loading users...</div>}>\n        <Users />\n      </Deferred>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/DeferredProps/WithReload.tsx",
    "content": "import { Deferred, router, usePage } from '@inertiajs/react'\n\nconst Results = () => {\n  const { results } = usePage<{ results?: { data: string[]; page: number } }>().props\n\n  return (\n    <>\n      <div id=\"results-data\">{results?.data?.join(', ')}</div>\n      <div id=\"results-page\">Page: {results?.page}</div>\n    </>\n  )\n}\n\nexport default () => {\n  const handleReload = () => {\n    router.reload({\n      data: { page: 2 },\n    })\n  }\n\n  return (\n    <>\n      <Deferred data=\"results\" fallback={<div>Loading results...</div>}>\n        <Results />\n      </Deferred>\n\n      <button onClick={handleReload}>Reload with page 2</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Dump.tsx",
    "content": "import type { Method } from '@inertiajs/core'\nimport { usePage } from '@inertiajs/react'\nimport { useEffect, useMemo } from 'react'\nimport type { MulterFile } from '../types'\n\nexport default ({\n  headers,\n  method,\n  form,\n  query,\n  url,\n  files,\n}: {\n  headers: Record<string, string>\n  method: Method\n  form: Record<string, unknown>\n  query: Record<string, unknown>\n  url: string\n  files: MulterFile[] | object\n}) => {\n  const page = usePage()\n\n  const dump = useMemo(\n    () => ({\n      headers,\n      method,\n      form,\n      files: files ? files : {},\n      query,\n      url,\n      $page: page,\n    }),\n    [headers, method, form, files, query, url, page],\n  )\n\n  useEffect(() => {\n    window._inertia_request_dump = dump\n  }, [dump])\n\n  return (\n    <div>\n      <div className=\"text\">This is Inertia page component containing a data dump of the request</div>\n      <hr />\n      <pre className=\"dump\">{JSON.stringify(dump, null, 2)}</pre>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/ErrorModal.tsx",
    "content": "import { config, router } from '@inertiajs/react'\n\nexport default ({ dialog }: { dialog: boolean }) => {\n  const invalidVisit = () => {\n    router.post('/non-inertia')\n  }\n\n  const invalidVisitJson = () => {\n    router.post('/json')\n  }\n\n  if (dialog) {\n    config.set('future.useDialogForErrorModal', true)\n  }\n\n  return (\n    <div>\n      <span onClick={invalidVisit} className=\"invalid-visit\">\n        Invalid Visit\n      </span>\n      <span onClick={invalidVisitJson} className=\"invalid-visit-json\">\n        Invalid Visit (JSON response)\n      </span>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Events.tsx",
    "content": "import { Link, router, usePage } from '@inertiajs/react'\n\ndeclare global {\n  interface Window {\n    messages: unknown[]\n  }\n}\n\nwindow.messages = []\n\nexport default () => {\n  const payloadWithFile = {\n    file: new File(['foobar'], 'example.bin'),\n  }\n\n  const page = usePage()\n\n  const internalAlert = (...args: unknown[]) => {\n    args.forEach((arg) => window.messages.push(arg))\n  }\n\n  const withoutEventListeners = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.post(page.url, {})\n  }\n\n  const removeInertiaListener = (e: React.MouseEvent) => {\n    e.preventDefault()\n    const removeEventListener = router.on('before', () => internalAlert('Inertia.on(before)'))\n\n    internalAlert('Removing Inertia.on Listener')\n    removeEventListener()\n\n    router.post(\n      page.url,\n      {},\n      {\n        onBefore: () => internalAlert('onBefore'),\n        onStart: () => internalAlert('onStart'),\n      },\n    )\n  }\n\n  const beforeVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.on('before', (event) => {\n      internalAlert('Inertia.on(before)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:before', (event) => {\n      internalAlert('addEventListener(inertia:before)')\n      internalAlert(event)\n    })\n\n    router.post(\n      page.url,\n      {},\n      {\n        onBefore: (event) => {\n          internalAlert('onBefore')\n          internalAlert(event)\n        },\n        onStart: () => internalAlert('onStart'),\n      },\n    )\n  }\n\n  const beforeVisitPreventLocal = (e: React.MouseEvent) => {\n    e.preventDefault()\n    document.addEventListener('inertia:before', () => internalAlert('addEventListener(inertia:before)'))\n    router.on('before', () => internalAlert('Inertia.on(before)'))\n\n    router.post(\n      page.url,\n      {},\n      {\n        onBefore: () => {\n          internalAlert('onBefore')\n          return false\n        },\n        onStart: () => internalAlert('This listener should not have been called.'),\n      },\n    )\n  }\n\n  const beforeVisitPreventGlobalInertia = (e: React.MouseEvent) => {\n    e.preventDefault()\n    document.addEventListener('inertia:before', () => internalAlert('addEventListener(inertia:before)'))\n    router.on('before', () => {\n      internalAlert('Inertia.on(before)')\n      return false\n    })\n\n    router.post(\n      page.url,\n      {},\n      {\n        onBefore: () => internalAlert('onBefore'),\n        onStart: () => internalAlert('This listener should not have been called.'),\n      },\n    )\n  }\n\n  const beforeVisitPreventGlobalNative = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.on('before', () => internalAlert('Inertia.on(before)'))\n    document.addEventListener('inertia:before', (event) => {\n      internalAlert('addEventListener(inertia:before)')\n      event.preventDefault()\n    })\n\n    router.post(\n      page.url,\n      {},\n      {\n        onBefore: () => internalAlert('onBefore'),\n        onStart: () => internalAlert('This listener should not have been called.'),\n      },\n    )\n  }\n\n  const cancelTokenVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    // @ts-expect-error - We're testing that the router doesn't have an onCancelToken listener\n    router.on('cancelToken', () => internalAlert('This listener should not have been called.'))\n    document.addEventListener('inertia:cancelToken', () => internalAlert('This listener should not have been called.'))\n\n    router.post(\n      page.url,\n      {},\n      {\n        onCancelToken: (event) => {\n          internalAlert('onCancelToken')\n          internalAlert(event)\n        },\n      },\n    )\n  }\n\n  const startVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.on('start', (event) => {\n      internalAlert('Inertia.on(start)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:start', (event) => {\n      internalAlert('addEventListener(inertia:start)')\n      internalAlert(event)\n    })\n\n    router.post(\n      page.url,\n      {},\n      {\n        onStart: (event) => {\n          internalAlert('onStart')\n          internalAlert(event)\n        },\n      },\n    )\n  }\n\n  const progressVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.on('progress', (event) => {\n      internalAlert('Inertia.on(progress)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:progress', (event) => {\n      internalAlert('addEventListener(inertia:progress)')\n      internalAlert(event)\n    })\n\n    router.post(page.url, payloadWithFile, {\n      onProgress: (event) => {\n        internalAlert('onProgress')\n        internalAlert(event)\n      },\n    })\n  }\n\n  const progressNoFilesVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.on('progress', (event) => {\n      internalAlert('Inertia.on(progress)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:progress', (event) => {\n      internalAlert('addEventListener(inertia:progress)')\n      internalAlert(event)\n    })\n\n    router.post(\n      page.url,\n      {},\n      {\n        onBefore: () => internalAlert('progressNoFilesOnBefore'),\n        onProgress: (event) => {\n          internalAlert('onProgress')\n          internalAlert(event)\n        },\n      },\n    )\n  }\n\n  const cancelVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.on('cancel', (event) => {\n      internalAlert('Inertia.on(cancel)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:cancel', (event) => {\n      internalAlert('addEventListener(inertia:cancel)')\n      internalAlert(event)\n    })\n\n    router.post(\n      page.url,\n      {},\n      {\n        onCancelToken: (token) => token.cancel(),\n        // @ts-expect-error - We're testing that the onCancel callback has no arguments, so event will be undefined\n        onCancel: (event) => {\n          internalAlert('onCancel')\n          internalAlert(event)\n        },\n      },\n    )\n  }\n\n  const errorVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.on('error', (event) => {\n      internalAlert('Inertia.on(error)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:error', (event) => {\n      internalAlert('addEventListener(inertia:error)')\n      internalAlert(event)\n    })\n\n    router.post(\n      '/events/errors',\n      {},\n      {\n        onError: (errors) => {\n          internalAlert('onError')\n          internalAlert(errors)\n        },\n      },\n    )\n  }\n\n  const errorPromiseVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.post(\n      '/events/errors',\n      {},\n      {\n        onError: () => callbackSuccessErrorPromise('onError'),\n        onSuccess: () => internalAlert('This listener should not have been called'),\n        onFinish: () => internalAlert('onFinish'),\n      },\n    )\n  }\n\n  const successVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.on('success', (event) => {\n      internalAlert('Inertia.on(success)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:success', (event) => {\n      internalAlert('addEventListener(inertia:success)')\n      internalAlert(event)\n    })\n\n    router.post(\n      page.url,\n      {},\n      {\n        onError: () => internalAlert('This listener should not have been called'),\n        onSuccess: (page) => {\n          internalAlert('onSuccess')\n          internalAlert(page)\n        },\n      },\n    )\n  }\n\n  const successPromiseVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.post(\n      page.url,\n      {},\n      {\n        onSuccess: () => callbackSuccessErrorPromise('onSuccess'),\n        onError: () => internalAlert('This listener should not have been called'),\n        onFinish: () => internalAlert('onFinish'),\n      },\n    )\n  }\n\n  const finishVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.on('finish', (event) => {\n      internalAlert('Inertia.on(finish)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:finish', (event) => {\n      internalAlert('addEventListener(inertia:finish)')\n      internalAlert(event)\n    })\n\n    router.post(\n      page.url,\n      {},\n      {\n        onFinish: (event) => {\n          internalAlert('onFinish')\n          internalAlert(event)\n        },\n      },\n    )\n  }\n\n  const invalidVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.on('invalid', (event) => {\n      internalAlert('Inertia.on(invalid)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:invalid', (event) => {\n      internalAlert('addEventListener(inertia:invalid)')\n      internalAlert(event)\n    })\n\n    router.post(\n      '/non-inertia',\n      {},\n      {\n        // @ts-expect-error - We're testing that the VisitCallbacks interface does not have an onInvalid method\n        onInvalid: () => internalAlert('This listener should not have been called.'),\n      },\n    )\n  }\n\n  const exceptionVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.on('exception', (event) => {\n      internalAlert('Inertia.on(exception)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:exception', (event) => {\n      internalAlert('addEventListener(inertia:exception)')\n      internalAlert(event)\n    })\n\n    router.post(\n      '/disconnect',\n      {},\n      {\n        // @ts-expect-error - We're testing that the VisitCallbacks interface does not have an onException method\n        onException: () => internalAlert('This listener should not have been called.'),\n      },\n    )\n  }\n\n  const navigateVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.on('navigate', (event) => {\n      internalAlert('Inertia.on(navigate)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:navigate', (event) => {\n      internalAlert('addEventListener(inertia:navigate)')\n      internalAlert(event)\n    })\n\n    router.get(\n      '/',\n      {},\n      {\n        // @ts-expect-error - We're testing that the VisitCallbacks interface does not have an onNavigate method\n        onNavigate: () => internalAlert('This listener should not have been called.'),\n      },\n    )\n  }\n\n  const registerAllListeners = () => {\n    router.on('before', () => internalAlert('Inertia.on(before)'))\n    // @ts-expect-error - We're testing that the router doesn't have an onCancelToken listener\n    router.on('cancelToken', () => internalAlert('Inertia.on(cancelToken)'))\n    router.on('cancel', () => internalAlert('Inertia.on(cancel)'))\n    router.on('start', () => internalAlert('Inertia.on(start)'))\n    router.on('progress', () => internalAlert('Inertia.on(progress)'))\n    router.on('error', () => internalAlert('Inertia.on(error)'))\n    router.on('success', () => internalAlert('Inertia.on(success)'))\n    router.on('invalid', () => internalAlert('Inertia.on(invalid)'))\n    router.on('exception', () => internalAlert('Inertia.on(exception)'))\n    router.on('finish', () => internalAlert('Inertia.on(finish)'))\n    router.on('navigate', () => internalAlert('Inertia.on(navigate)'))\n    document.addEventListener('inertia:before', () => internalAlert('addEventListener(inertia:before)'))\n    document.addEventListener('inertia:cancelToken', () => internalAlert('addEventListener(inertia:cancelToken)'))\n    document.addEventListener('inertia:cancel', () => internalAlert('addEventListener(inertia:cancel)'))\n    document.addEventListener('inertia:start', () => internalAlert('addEventListener(inertia:start)'))\n    document.addEventListener('inertia:progress', () => internalAlert('addEventListener(inertia:progress)'))\n    document.addEventListener('inertia:error', () => internalAlert('addEventListener(inertia:error)'))\n    document.addEventListener('inertia:success', () => internalAlert('addEventListener(inertia:success)'))\n    document.addEventListener('inertia:invalid', () => internalAlert('addEventListener(inertia:invalid)'))\n    document.addEventListener('inertia:exception', () => internalAlert('addEventListener(inertia:exception)'))\n    document.addEventListener('inertia:finish', () => internalAlert('addEventListener(inertia:finish)'))\n    document.addEventListener('inertia:navigate', () => internalAlert('addEventListener(inertia:navigate)'))\n\n    return {\n      onBefore: () => internalAlert('onBefore'),\n      onCancelToken: () => internalAlert('onCancelToken'),\n      onCancel: () => internalAlert('onCancel'),\n      onStart: () => internalAlert('onStart'),\n      onProgress: () => internalAlert('onProgress'),\n      onError: () => internalAlert('onError'),\n      onSuccess: () => internalAlert('onSuccess'),\n      onInvalid: () => internalAlert('onInvalid'), // Does not exist.\n      onException: () => internalAlert('onException'), // Does not exist.\n      onFinish: () => internalAlert('onFinish'),\n      onNavigate: () => internalAlert('onNavigate'), // Does not exist.\n    }\n  }\n\n  const lifecycleSuccess = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.post(page.url, payloadWithFile, registerAllListeners())\n  }\n\n  const lifecycleError = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.post('/events/errors', payloadWithFile, registerAllListeners())\n  }\n\n  const lifecycleCancel = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.post('/sleep', payloadWithFile, {\n      ...registerAllListeners(),\n      onCancelToken: (token) => {\n        internalAlert('onCancelToken')\n\n        setTimeout(() => {\n          internalAlert('CANCELLING!')\n          token.cancel()\n        }, 250)\n      },\n    })\n  }\n\n  const lifecycleCancelAfterFinish = (e: React.MouseEvent) => {\n    e.preventDefault()\n    type CancelToken = {\n      cancel: () => void\n    }\n\n    let cancelToken = null as CancelToken | null\n\n    router.post(page.url, payloadWithFile, {\n      ...registerAllListeners(),\n      onCancelToken: (token: CancelToken) => {\n        internalAlert('onCancelToken')\n        cancelToken = token\n      },\n      onFinish: () => {\n        internalAlert('onFinish')\n        internalAlert('CANCELLING!')\n        cancelToken?.cancel()\n      },\n    })\n  }\n\n  const callbackSuccessErrorPromise = (eventName: string) => {\n    internalAlert(eventName)\n    setTimeout(() => internalAlert('onFinish should have been fired by now if Promise functionality did not work'), 5)\n    return new Promise((resolve) => setTimeout(resolve, 20))\n  }\n\n  return (\n    <div>\n      {/* Listeners */}\n      <a href=\"#\" onClick={withoutEventListeners} className=\"without-listeners\">\n        Basic Visit\n      </a>\n      <a href=\"#\" onClick={removeInertiaListener} className=\"remove-inertia-listener\">\n        Remove Inertia Listener\n      </a>\n\n      {/* Events: Before */}\n      <a href=\"#\" onClick={beforeVisit} className=\"before\">\n        Before Event\n      </a>\n      <a href=\"#\" onClick={beforeVisitPreventLocal} className=\"before-prevent-local\">\n        Before Event (Prevent)\n      </a>\n      <Link\n        href={page.url}\n        method=\"post\"\n        onBefore={(visit) => internalAlert('linkOnBefore', visit)}\n        onStart={() => internalAlert('linkOnStart')}\n        className=\"link-before\"\n      >\n        Before Event Link\n      </Link>\n      <Link\n        href={page.url}\n        method=\"post\"\n        onBefore={() => {\n          internalAlert('linkOnBefore')\n          return false\n        }}\n        onStart={() => internalAlert('This listener should not have been called.')}\n        className=\"link-before-prevent-local\"\n      >\n        Before Event Link (Prevent)\n      </Link>\n      <a href=\"#\" onClick={beforeVisitPreventGlobalInertia} className=\"before-prevent-global-inertia\">\n        Before Event - Prevent globally using Inertia Event Listener\n      </a>\n      <a href=\"#\" onClick={beforeVisitPreventGlobalNative} className=\"before-prevent-global-native\">\n        Before Event - Prevent globally using Native Event Listeners\n      </a>\n\n      {/* Events: CancelToken */}\n      <a href=\"#\" onClick={cancelTokenVisit} className=\"canceltoken\">\n        Cancel Token Event\n      </a>\n      <Link\n        href={page.url}\n        method=\"post\"\n        onCancelToken={(event) => internalAlert('linkOnCancelToken', event)}\n        className=\"link-canceltoken\"\n      >\n        Cancel Token Event Link\n      </Link>\n\n      {/* Events: Cancel */}\n      <a href=\"#\" onClick={cancelVisit} className=\"cancel\">\n        Cancel Event\n      </a>\n      <Link\n        href={page.url}\n        method=\"post\"\n        onCancelToken={(token) => token.cancel()}\n        // @ts-expect-error - We're testing that the onCancel callback has no arguments, so event will be undefined\n        onCancel={(event) => internalAlert('linkOnCancel', event)}\n        className=\"link-cancel\"\n      >\n        Cancel Event Link\n      </Link>\n\n      {/* Events: Start */}\n      <a href=\"#\" onClick={startVisit} className=\"start\">\n        Start Event\n      </a>\n      <Link\n        href={page.url}\n        method=\"post\"\n        onStart={(event) => internalAlert('linkOnStart', event)}\n        className=\"link-start\"\n      >\n        Start Event Link\n      </Link>\n\n      {/* Events: Progress */}\n      <a href=\"#\" onClick={progressVisit} className=\"progress\">\n        Progress Event\n      </a>\n      <a href=\"#\" onClick={progressNoFilesVisit} className=\"progress-no-files\">\n        Missing Progress Event (no files)\n      </a>\n      <Link\n        href={page.url}\n        method=\"post\"\n        data={payloadWithFile}\n        onProgress={(event) => internalAlert('linkOnProgress', event)}\n        className=\"link-progress\"\n      >\n        Progress Event Link\n      </Link>\n      <Link\n        href={page.url}\n        method=\"post\"\n        onBefore={() => internalAlert('linkProgressNoFilesOnBefore')}\n        onProgress={(event) => internalAlert('linkOnProgress', event)}\n        className=\"link-progress-no-files\"\n      >\n        Progress Event Link (no files)\n      </Link>\n\n      {/* Events: Error */}\n      <a href=\"#\" onClick={errorVisit} className=\"error\">\n        Error Event\n      </a>\n      <a href=\"#\" onClick={errorPromiseVisit} className=\"error-promise\">\n        Error Event (delaying onFinish w/ Promise)\n      </a>\n      <Link\n        href=\"/events/errors\"\n        method=\"post\"\n        onError={(errors) => internalAlert('linkOnError', errors)}\n        onSuccess={() => internalAlert('This listener should not have been called')}\n        className=\"link-error\"\n      >\n        Error Event Link\n      </Link>\n      <Link\n        href=\"/events/errors\"\n        method=\"post\"\n        onError={() => callbackSuccessErrorPromise('linkOnError')}\n        onSuccess={() => internalAlert('This listener should not have been called')}\n        onFinish={() => internalAlert('linkOnFinish')}\n        className=\"link-error-promise\"\n      >\n        Error Event Link (delaying onFinish w/ Promise)\n      </Link>\n\n      {/* Events: Success */}\n      <a href=\"#\" onClick={successVisit} className=\"success\">\n        Success Event\n      </a>\n      <a href=\"#\" onClick={successPromiseVisit} className=\"success-promise\">\n        Success Event (delaying onFinish w/ Promise)\n      </a>\n      <Link\n        href={page.url}\n        method=\"post\"\n        onError={() => internalAlert('This listener should not have been called')}\n        onSuccess={(event) => internalAlert('linkOnSuccess', event)}\n        className=\"link-success\"\n      >\n        Success Event Link\n      </Link>\n      <Link\n        href={page.url}\n        method=\"post\"\n        onError={() => internalAlert('This listener should not have been called')}\n        onSuccess={() => callbackSuccessErrorPromise('linkOnSuccess')}\n        onFinish={() => internalAlert('linkOnFinish')}\n        className=\"link-success-promise\"\n      >\n        Success Event Link (delaying onFinish w/ Promise)\n      </Link>\n\n      {/* Events: Invalid */}\n      <a href=\"#\" onClick={invalidVisit} className=\"invalid\">\n        Invalid Event\n      </a>\n\n      {/* Events: Exception */}\n      <a href=\"#\" onClick={exceptionVisit} className=\"exception\">\n        Exception Event\n      </a>\n\n      {/* Events: Finish */}\n      <a href=\"#\" onClick={finishVisit} className=\"finish\">\n        Finish Event\n      </a>\n      <Link\n        href={page.url}\n        method=\"post\"\n        onFinish={(event) => internalAlert('linkOnFinish', event)}\n        className=\"link-finish\"\n      >\n        Finish Event Link\n      </Link>\n\n      {/* Events: Navigate */}\n      <a href=\"#\" onClick={navigateVisit} className=\"navigate\">\n        Navigate Event\n      </a>\n\n      {/* Events: Prefetch */}\n      <Link\n        as=\"button\"\n        href=\"/prefetch/2\"\n        prefetch=\"hover\"\n        onPrefetching={(visit) => internalAlert('linkOnPrefetching', visit)}\n        onPrefetched={(response, visit) => internalAlert('linkOnPrefetched', response, visit)}\n        className=\"link-prefetch-hover\"\n      >\n        Prefetch Event Link (Hover)\n      </Link>\n\n      {/* Lifecycles */}\n      <a href=\"#\" onClick={lifecycleSuccess} className=\"lifecycle-success\">\n        Lifecycle Success\n      </a>\n      <a href=\"#\" onClick={lifecycleError} className=\"lifecycle-error\">\n        Lifecycle Error\n      </a>\n      <a href=\"#\" onClick={lifecycleCancel} className=\"lifecycle-cancel\">\n        Lifecycle Cancel\n      </a>\n      <a href=\"#\" onClick={lifecycleCancelAfterFinish} className=\"lifecycle-cancel-after-finish\">\n        Lifecycle Cancel - After Finish\n      </a>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Flash/ClientSideVisits.tsx",
    "content": "import { router, usePage } from '@inertiajs/react'\n\ndeclare global {\n  interface Window {\n    flashCount: number\n  }\n}\n\nwindow.flashCount ??= 0\n\nexport default () => {\n  const page = usePage()\n\n  const withFlash = () => {\n    router.replace({\n      flash: { foo: 'bar' },\n      onFlash: () => window.flashCount++,\n    })\n  }\n\n  const withFlashFunction = () => {\n    router.replace({\n      flash: (flash) => ({ ...flash, bar: 'baz' }),\n      onFlash: () => window.flashCount++,\n    })\n  }\n\n  const withoutFlash = () => {\n    router.replace({\n      props: (props) => ({ ...props }),\n      onFlash: () => window.flashCount++,\n    })\n  }\n\n  return (\n    <div>\n      <span id=\"flash\">{JSON.stringify(page.flash)}</span>\n\n      <button onClick={withFlash}>With flash object</button>\n      <button onClick={withFlashFunction}>With flash function</button>\n      <button onClick={withoutFlash}>Without flash</button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Flash/Events.tsx",
    "content": "import { router, usePage } from '@inertiajs/react'\n\ndeclare global {\n  interface Window {\n    messages: unknown[]\n  }\n}\n\nwindow.messages = []\n\nconst internalAlert = (...args: unknown[]) => {\n  window.messages.push(...args)\n}\n\nexport default () => {\n  const page = usePage()\n\n  const visitWithFlash = () => {\n    router.on('flash', (event) => {\n      internalAlert('Inertia.on(flash)')\n      internalAlert(event.detail.flash)\n    })\n\n    document.addEventListener('inertia:flash', (event) => {\n      internalAlert('addEventListener(inertia:flash)')\n      internalAlert((event as CustomEvent).detail.flash)\n    })\n\n    router.post(\n      '/flash/events/with-data',\n      {},\n      {\n        onFlash: (flash) => {\n          internalAlert('onFlash')\n          internalAlert(flash)\n        },\n        onSuccess: (page) => {\n          internalAlert('onSuccess')\n          internalAlert(page.flash)\n        },\n      },\n    )\n  }\n\n  const visitWithoutFlash = () => {\n    router.on('flash', () => {\n      internalAlert('Inertia.on(flash)')\n    })\n\n    document.addEventListener('inertia:flash', () => {\n      internalAlert('addEventListener(inertia:flash)')\n    })\n\n    router.post(\n      '/flash/events/without-data',\n      {},\n      {\n        onFlash: () => {\n          internalAlert('onFlash')\n        },\n        onSuccess: () => {\n          internalAlert('onSuccess')\n        },\n      },\n    )\n  }\n\n  const navigateAway = () => {\n    router.get('/')\n  }\n\n  return (\n    <div>\n      <span id=\"flash\">{JSON.stringify(page.flash)}</span>\n\n      <a\n        href=\"#\"\n        onClick={(e) => {\n          e.preventDefault()\n          visitWithFlash()\n        }}\n        className=\"with-flash\"\n      >\n        Visit with flash\n      </a>\n      <a\n        href=\"#\"\n        onClick={(e) => {\n          e.preventDefault()\n          visitWithoutFlash()\n        }}\n        className=\"without-flash\"\n      >\n        Visit without flash\n      </a>\n      <a\n        href=\"#\"\n        onClick={(e) => {\n          e.preventDefault()\n          navigateAway()\n        }}\n        className=\"navigate-away\"\n      >\n        Navigate away\n      </a>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Flash/InitialFlash.tsx",
    "content": "import { router, usePage } from '@inertiajs/react'\nimport { useRef, useState } from 'react'\n\nexport default () => {\n  const page = usePage()\n  const [, forceUpdate] = useState(0)\n  const flashEvents = useRef<Record<string, unknown>[]>([])\n  const listenerSetup = useRef(false)\n\n  if (!listenerSetup.current) {\n    listenerSetup.current = true\n    router.on('flash', (e) => {\n      flashEvents.current.push(e.detail.flash)\n      forceUpdate((n) => n + 1)\n    })\n  }\n\n  return (\n    <div>\n      <span id=\"flash\">{page.flash ? JSON.stringify(page.flash) : 'no-flash'}</span>\n      <span id=\"flash-events\">{JSON.stringify(flashEvents.current)}</span>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Flash/Partial.tsx",
    "content": "import { router, usePage } from '@inertiajs/react'\nimport { useRef, useState } from 'react'\n\nexport default ({ count }: { count: number }) => {\n  const page = usePage()\n  const [flashEventCount, setFlashEventCount] = useState(0)\n  const listenerSetup = useRef(false)\n\n  if (!listenerSetup.current) {\n    listenerSetup.current = true\n    router.on('flash', () => {\n      setFlashEventCount((n) => n + 1)\n    })\n  }\n\n  const reloadWithSameFlash = () => {\n    router.reload({ only: ['count'], data: { flashType: 'same', count: Date.now() } })\n  }\n\n  const reloadWithDifferentFlash = () => {\n    router.reload({ only: ['count'], data: { flashType: 'different', count: Date.now() } })\n  }\n\n  return (\n    <div>\n      <span id=\"flash\">{JSON.stringify(page.flash)}</span>\n      <span id=\"flash-event-count\">{flashEventCount}</span>\n      <span id=\"count\">{count}</span>\n\n      <button onClick={reloadWithSameFlash}>Reload with same flash</button>\n      <button onClick={reloadWithDifferentFlash}>Reload with different flash</button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Flash/RouterFlash.tsx",
    "content": "import { router, usePage } from '@inertiajs/react'\n\nexport default () => {\n  const page = usePage()\n\n  const setFlash = () => {\n    router.flash({ foo: 'bar' })\n  }\n\n  const setFlashKeyValue = () => {\n    router.flash('foo', 'bar')\n  }\n\n  const mergeFlash = () => {\n    router.flash((current) => ({ ...current, bar: 'baz' }))\n  }\n\n  const clearFlash = () => {\n    router.flash(() => ({}))\n  }\n\n  return (\n    <div>\n      <span id=\"flash\">{JSON.stringify(page.flash)}</span>\n\n      <button onClick={setFlash}>Set flash</button>\n      <button onClick={setFlashKeyValue}>Set flash key-value</button>\n      <button onClick={mergeFlash}>Merge flash</button>\n      <button onClick={clearFlash}>Clear flash</button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Flash/WithDeferred.tsx",
    "content": "import { Deferred, router, usePage } from '@inertiajs/react'\nimport { useRef, useState } from 'react'\n\nexport default ({ data }: { data?: string }) => {\n  const page = usePage()\n  const [flashEventCount, setFlashEventCount] = useState(0)\n  const listenerSetup = useRef(false)\n\n  if (!listenerSetup.current) {\n    listenerSetup.current = true\n    router.on('flash', () => {\n      setFlashEventCount((n) => n + 1)\n    })\n  }\n\n  return (\n    <div>\n      <span id=\"flash\">{JSON.stringify(page.flash)}</span>\n      <span id=\"flash-event-count\">{flashEventCount}</span>\n\n      <Deferred data=\"data\" fallback={<div id=\"loading\">Loading...</div>}>\n        <div id=\"data\">{data}</div>\n      </Deferred>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Flash/WithInfiniteScroll.tsx",
    "content": "import { InfiniteScroll, router, usePage } from '@inertiajs/react'\nimport { useRef, useState } from 'react'\n\nexport default ({ users }: { users: { data: { id: number; name: string }[] } }) => {\n  const page = usePage()\n  const [flashEventCount, setFlashEventCount] = useState(0)\n  const listenerSetup = useRef(false)\n\n  if (!listenerSetup.current) {\n    listenerSetup.current = true\n    router.on('flash', () => {\n      setFlashEventCount((n) => n + 1)\n    })\n  }\n\n  return (\n    <div>\n      <span id=\"flash\">{JSON.stringify(page.flash)}</span>\n      <span id=\"flash-event-count\">{flashEventCount}</span>\n\n      <InfiniteScroll data=\"users\" style={{ display: 'grid', gap: '20px' }}>\n        {users.data.map((user) => (\n          <div key={user.id} style={{ height: '15vh', border: '1px solid #ccc' }}>\n            {user.name}\n          </div>\n        ))}\n      </InfiniteScroll>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/ChildComponent.tsx",
    "content": "import { Form } from '@inertiajs/react'\nimport { useMemo, useState } from 'react'\n\nconst ChildElement = ({ name }: { name: string }) => {\n  const [internalState, setInternalState] = useState('')\n  const transformedState = useMemo(() => internalState.toUpperCase(), [internalState])\n\n  return (\n    <div>\n      <label htmlFor={name}>Child Input</label>\n      <input id={name} name={name} value={transformedState} onChange={(e) => setInternalState(e.target.value)} />\n    </div>\n  )\n}\n\nexport default () => {\n  return (\n    <Form action=\"/dump/post\" method=\"post\">\n      {({ isDirty }) => (\n        <>\n          <h1>Form Elements</h1>\n\n          <div>\n            Form is <span>{isDirty ? 'dirty' : 'clean'}</span>\n          </div>\n\n          <ChildElement name=\"child\" />\n\n          <button type=\"submit\">Submit</button>\n        </>\n      )}\n    </Form>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Context/ChildComponent.tsx",
    "content": "import { useFormContext } from '@inertiajs/react'\n\nexport default ({ formId }: { formId?: string }) => {\n  const form = useFormContext()\n\n  return (\n    <>\n      {form ? (\n        <div>\n          <span>Child: Form is {form.isDirty ? 'dirty' : 'clean'}</span>\n          {form.hasErrors && <span> | Child: Form has errors</span>}\n          {form.processing && <span> | Child: Form is processing</span>}\n          {form.wasSuccessful && <span> | Child: Form was successful</span>}\n          {form.recentlySuccessful && <span> | Child: Form recently successful</span>}\n          {form.errors.name && <span> | Error: {form.errors.name}</span>}\n        </div>\n      ) : (\n        <div>No form context available</div>\n      )}\n\n      <button\n        type=\"button\"\n        onClick={() => form?.setError('name', formId ? 'Error from child' : 'Error set from child component')}\n      >\n        Set Error\n      </button>\n      <button type=\"button\" onClick={() => form?.clearErrors('name')}>\n        Clear Error\n      </button>\n      {!formId && (\n        <>\n          <button type=\"button\" onClick={() => form?.submit()}>\n            Submit from Child\n          </button>\n          <button type=\"button\" onClick={() => form?.reset()}>\n            Reset from Child\n          </button>\n          <button type=\"button\" onClick={() => form?.defaults()}>\n            Set Defaults\n          </button>\n        </>\n      )}\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Context/DeeplyNestedComponent.tsx",
    "content": "import { useFormContext } from '@inertiajs/react'\n\nexport default () => {\n  const form = useFormContext()\n\n  return form ? (\n    <div>\n      <span>Deeply Nested: Form is {form.isDirty ? 'dirty' : 'clean'}</span>\n    </div>\n  ) : (\n    <div>No context</div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Context/Default.tsx",
    "content": "import { Form } from '@inertiajs/react'\nimport ChildComponent from './ChildComponent'\nimport NestedComponent from './NestedComponent'\nimport OutsideFormComponent from './OutsideFormComponent'\n\nexport default () => (\n  <>\n    <Form action=\"/dump/post\" method=\"post\">\n      {({ isDirty, hasErrors, errors }) => (\n        <>\n          <div>\n            <span>Parent: Form is {isDirty ? 'dirty' : 'clean'}</span>\n            {hasErrors && <span> | Parent: Form has errors</span>}\n            {errors.name && <span> | {errors.name}</span>}\n          </div>\n\n          <input type=\"text\" name=\"name\" defaultValue=\"John Doe\" />\n          <input type=\"email\" name=\"email\" defaultValue=\"john@example.com\" />\n\n          <ChildComponent />\n          <NestedComponent />\n        </>\n      )}\n    </Form>\n\n    <OutsideFormComponent />\n  </>\n)\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Context/Methods.tsx",
    "content": "import { Form } from '@inertiajs/react'\nimport MethodsTestComponent from './MethodsTestComponent'\n\nexport default () => (\n  <Form action=\"/form-component/context/methods\" method=\"post\">\n    {({ errors }) => (\n      <>\n        {Object.keys(errors).length > 0 && <pre>{JSON.stringify(errors, null, 2)}</pre>}\n\n        <input type=\"text\" name=\"name\" defaultValue=\"Initial Name\" />\n        <input type=\"email\" name=\"email\" defaultValue=\"initial@example.com\" />\n        <textarea name=\"bio\" defaultValue=\"Initial bio\" />\n\n        <MethodsTestComponent />\n      </>\n    )}\n  </Form>\n)\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Context/MethodsTestComponent.tsx",
    "content": "import { useFormContext } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const form = useFormContext()\n  const [getDataResult, setGetDataResult] = useState('')\n  const [getFormDataResult, setGetFormDataResult] = useState('')\n\n  const testGetData = () => {\n    if (form) {\n      setGetDataResult(JSON.stringify(form.getData(), null, 2))\n    }\n  }\n\n  const testGetFormData = () => {\n    if (form) {\n      const formData = form.getFormData()\n      const obj: Record<string, FormDataEntryValue> = {}\n      formData.forEach((value, key) => {\n        obj[key] = value\n      })\n      setGetFormDataResult(JSON.stringify(obj, null, 2))\n    }\n  }\n\n  if (!form) {\n    return <div>No form context available</div>\n  }\n\n  return (\n    <>\n      {form.processing && <span>Child: processing</span>}\n      {form.wasSuccessful && <span>Child: was successful</span>}\n      {form.recentlySuccessful && <span>Child: recently successful</span>}\n      {form.hasErrors && <pre>{JSON.stringify(form.errors, null, 2)}</pre>}\n\n      <button type=\"button\" onClick={() => form.submit()}>\n        submit()\n      </button>\n      <button type=\"button\" onClick={() => form.reset()}>\n        reset()\n      </button>\n      <button type=\"button\" onClick={() => form.reset('name')}>\n        reset('name')\n      </button>\n      <button type=\"button\" onClick={() => form.reset('name', 'email')}>\n        reset('name', 'email')\n      </button>\n\n      <button type=\"button\" onClick={() => form.clearErrors()}>\n        clearErrors()\n      </button>\n      <button type=\"button\" onClick={() => form.clearErrors('name')}>\n        clearErrors('name')\n      </button>\n      <button type=\"button\" onClick={() => form.setError('name', 'Name is invalid')}>\n        setError('name')\n      </button>\n      <button\n        type=\"button\"\n        onClick={() =>\n          form.setError({\n            name: 'Name error from child',\n            email: 'Email error from child',\n            bio: 'Bio error from child',\n          })\n        }\n      >\n        setError({'{...}'})\n      </button>\n\n      <button type=\"button\" onClick={() => form.resetAndClearErrors()}>\n        resetAndClearErrors()\n      </button>\n      <button type=\"button\" onClick={() => form.resetAndClearErrors('name')}>\n        resetAndClearErrors('name')\n      </button>\n\n      <button type=\"button\" onClick={testGetData}>\n        getData()\n      </button>\n      <button type=\"button\" onClick={testGetFormData}>\n        getFormData()\n      </button>\n\n      {getDataResult && <pre id=\"get-data-result\">{getDataResult}</pre>}\n      {getFormDataResult && <pre id=\"get-form-data-result\">{getFormDataResult}</pre>}\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Context/Multiple.tsx",
    "content": "import { Form } from '@inertiajs/react'\nimport ChildComponent from './ChildComponent'\n\nexport default () => (\n  <>\n    <Form action=\"/dump/post\" method=\"post\">\n      {({ isDirty, errors }) => (\n        <>\n          <div>\n            <span>Form 1 Parent: {isDirty ? 'dirty' : 'clean'}</span>\n            {errors.name && <span> | Error: {errors.name}</span>}\n          </div>\n          <input type=\"text\" name=\"name\" defaultValue=\"Form 1 Name\" />\n          <ChildComponent formId=\"form1\" />\n        </>\n      )}\n    </Form>\n\n    <Form action=\"/dump/post\" method=\"post\">\n      {({ isDirty, errors }) => (\n        <>\n          <div>\n            <span>Form 2 Parent: {isDirty ? 'dirty' : 'clean'}</span>\n            {errors.name && <span> | Error: {errors.name}</span>}\n          </div>\n          <input type=\"text\" name=\"name\" defaultValue=\"Form 2 Name\" />\n          <ChildComponent formId=\"form2\" />\n        </>\n      )}\n    </Form>\n  </>\n)\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Context/NestedComponent.tsx",
    "content": "import DeeplyNestedComponent from './DeeplyNestedComponent'\n\nexport default () => <DeeplyNestedComponent />\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Context/OutsideFormComponent.tsx",
    "content": "import { useFormContext } from '@inertiajs/react'\n\nexport default () => {\n  const form = useFormContext()\n\n  return form === undefined ? (\n    <div>Correctly returns undefined when used outside a Form component</div>\n  ) : (\n    <div>Unexpectedly has form context</div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/DataMethods.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>Test getData() and getFormData() Methods</h1>\n\n      <Form>\n        {({ getData, getFormData }) => (\n          <>\n            <input type=\"text\" name=\"name\" id=\"name\" />\n\n            <button\n              type=\"button\"\n              onClick={() => {\n                const data = getData()\n                console.log('getData result: ' + JSON.stringify(data))\n              }}\n            >\n              Test getData()\n            </button>\n\n            <button\n              type=\"button\"\n              onClick={() => {\n                const formData = getFormData()\n                console.log('getFormData entries: ' + JSON.stringify(Object.fromEntries(formData.entries())))\n              }}\n            >\n              Test getFormData()\n            </button>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/DefaultValue.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default ({\n  user,\n}: {\n  user: {\n    name: string\n  }\n}) => {\n  return (\n    <Form action=\"/form-component/default-value\" method=\"patch\">\n      {({ errors }) => (\n        <>\n          <h1>Form Default Values</h1>\n\n          <div>\n            <label htmlFor=\"name\">Name</label>\n            <input type=\"text\" name=\"name\" id=\"name\" defaultValue={user.name} />\n            <div id=\"error_name\">{errors['user.name']}</div>\n          </div>\n\n          <button type=\"submit\">Submit</button>\n        </>\n      )}\n    </Form>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/DisableWhileProcessing.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default ({ disable }: { disable: boolean }) => {\n  return (\n    <div>\n      <h1>Form Disable While Processing Test</h1>\n\n      <Form\n        method=\"post\"\n        action={`/form-component/disable-while-processing/${disable ? 'yes' : 'no'}/submit`}\n        disableWhileProcessing={disable}\n      >\n        {({ errors }) => (\n          <>\n            <div>\n              <input type=\"text\" name=\"name\" placeholder=\"Name\" defaultValue=\"John Doe\" />\n              {errors.name && <p id=\"error_name\">{errors.name}</p>}\n            </div>\n\n            <div>\n              <button type=\"submit\">Submit</button>\n            </div>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/DottedKeys.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default function DottedKeys() {\n  return (\n    <div>\n      <h1>Dotted Keys Form Test</h1>\n\n      {/* Test basic and nested dotted keys */}\n      <Form action=\"/dump/post\" method=\"post\">\n        <h2>Basic Dotted Keys</h2>\n        <input type=\"text\" name=\"user.name\" placeholder=\"User Name\" />\n        <input type=\"text\" name=\"user.profile.city\" placeholder=\"City\" />\n        <input type=\"text\" name=\"user.skills[]\" placeholder=\"First Skill\" />\n        <input type=\"text\" name=\"user.skills[]\" placeholder=\"Second Skill\" />\n        <input type=\"text\" name=\"company.address.street\" placeholder=\"Street\" />\n        <button type=\"submit\">Submit Basic</button>\n      </Form>\n\n      {/* Test escaped dots (literal keys) */}\n      <Form action=\"/dump/post\" method=\"post\">\n        <h2>Escaped Dots</h2>\n        <input type=\"text\" name=\"config\\.app\\.name\" placeholder=\"App Name\" />\n        <input type=\"text\" name=\"settings.theme\\.mode\" placeholder=\"Theme Mode\" />\n        <button type=\"submit\">Submit Escaped</button>\n      </Form>\n\n      {/* Test mixed bracket and dotted notation */}\n      <Form action=\"/dump/post\" method=\"post\">\n        <h2>Mixed Notation</h2>\n        <input type=\"text\" name=\"user[roles][]\" defaultValue=\"admin\" />\n        <input type=\"text\" name=\"user[roles][]\" defaultValue=\"editor\" />\n        <input type=\"text\" name=\"settings.ui.theme\" placeholder=\"UI Theme\" />\n        <button type=\"submit\">Submit Mixed</button>\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Elements.tsx",
    "content": "import { QueryStringArrayFormatOption } from '@inertiajs/core'\nimport { config, Form } from '@inertiajs/react'\n\nexport default ({\n  queryStringArrayFormat,\n}: {\n  queryStringArrayFormat: QueryStringArrayFormatOption | 'force-brackets'\n}) => {\n  const format: QueryStringArrayFormatOption =\n    queryStringArrayFormat === 'force-brackets' ? 'brackets' : queryStringArrayFormat\n\n  if (queryStringArrayFormat === 'force-brackets') {\n    config.set('form.forceIndicesArrayFormatInFormData', false)\n  }\n\n  return (\n    <Form action=\"/dump/post\" method=\"post\" queryStringArrayFormat={format}>\n      {({ isDirty }) => (\n        <>\n          <h1>Form Elements</h1>\n\n          <div>\n            Form is <span>{isDirty ? 'dirty' : 'clean'}</span>\n          </div>\n\n          {/* Text input */}\n          <div>\n            <input type=\"text\" name=\"name\" id=\"name\" placeholder=\"Name\" />\n          </div>\n\n          {/* Select with default selected option */}\n          <div>\n            <select name=\"country\" id=\"country\" defaultValue=\"uk\">\n              <option value=\"us\">United States</option>\n              <option value=\"ca\">Canada</option>\n              <option value=\"uk\">United Kingdom</option>\n            </select>\n          </div>\n\n          {/* Select with default disabled option */}\n          <div>\n            <select name=\"role\" id=\"role\" defaultValue=\"\">\n              <option value=\"\" disabled>\n                Role\n              </option>\n              <option value=\"User\">User</option>\n              <option value=\"Admin\">Admin</option>\n              <option value=\"Super\">Super</option>\n            </select>\n          </div>\n\n          {/* Radio buttons */}\n          <div>\n            <label>\n              <input type=\"radio\" name=\"plan\" value=\"free\" /> Free\n            </label>\n            <label>\n              <input type=\"radio\" name=\"plan\" value=\"pro\" /> Pro\n            </label>\n            <label>\n              <input type=\"radio\" name=\"plan\" value=\"enterprise\" /> Enterprise\n            </label>\n          </div>\n\n          {/* Checkbox (single) */}\n          <div>\n            <input type=\"checkbox\" name=\"subscribe\" value=\"yes\" id=\"subscribe\" />\n            <label htmlFor=\"subscribe\">Subscribe to newsletter</label>\n          </div>\n\n          {/* Checkbox (multiple) */}\n          <div>\n            <label>\n              <input type=\"checkbox\" name=\"interests[]\" value=\"sports\" /> Sports\n            </label>\n            <label>\n              <input type=\"checkbox\" name=\"interests[]\" value=\"music\" /> Music\n            </label>\n            <label>\n              <input type=\"checkbox\" name=\"interests[]\" value=\"tech\" /> Tech\n            </label>\n          </div>\n\n          {/* Multiple select */}\n          <div>\n            <select name=\"skills[]\" id=\"skills\" multiple defaultValue=\"\">\n              <option disabled value=\"\">\n                Skills\n              </option>\n              <option value=\"vue\">Vue</option>\n              <option value=\"react\">React</option>\n              <option value=\"angular\">Angular</option>\n              <option value=\"svelte\">Svelte</option>\n            </select>\n          </div>\n\n          {/* File input (single) */}\n          <div>\n            <input type=\"file\" name=\"avatar\" id=\"avatar\" placeholder=\"Avatar\" />\n          </div>\n\n          {/* File input (multiple) */}\n          <div>\n            <input type=\"file\" name=\"documents[]\" id=\"documents\" multiple placeholder=\"Documents\" />\n          </div>\n\n          {/* Textarea */}\n          <div>\n            <textarea name=\"bio\" id=\"bio\" rows={3} placeholder=\"Bio\"></textarea>\n          </div>\n\n          {/* Hidden input */}\n          <div>\n            <input type=\"hidden\" name=\"token\" id=\"token\" value=\"abc123\" />\n          </div>\n\n          {/* Number input */}\n          <div>\n            <input type=\"number\" name=\"age\" id=\"age\" placeholder=\"Age\" />\n          </div>\n\n          {/* Deep nested input */}\n          <div>\n            <input type=\"text\" name=\"user[address][street]\" id=\"nested_street\" placeholder=\"Street\" />\n          </div>\n\n          {/* Indexed array of objects */}\n          <div>\n            <input type=\"text\" name=\"items[0][name]\" defaultValue=\"Item A\" id=\"item_a\" />\n            <input type=\"text\" name=\"items[1][name]\" defaultValue=\"Item B\" id=\"item_b\" />\n          </div>\n\n          {/* Disabled input (should be ignored) */}\n          <div>\n            <input type=\"text\" name=\"disabled_field\" value=\"Ignore me\" disabled />\n          </div>\n\n          <button type=\"submit\">Submit</button>\n          <button type=\"reset\">Reset</button>\n        </>\n      )}\n    </Form>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/EmptyAction.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>Form Empty Action Test</h1>\n\n      <Form method=\"post\">\n        {({ errors }) => (\n          <>\n            <div>\n              <input type=\"text\" name=\"name\" placeholder=\"Name\" defaultValue=\"John Doe\" />\n              {errors.name && <p id=\"error_name\">{errors.name}</p>}\n            </div>\n\n            <div>\n              <button type=\"submit\">Submit</button>\n            </div>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Errors.tsx",
    "content": "import { Form } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const [errorBag, setErrorBag] = useState<string | null>(null)\n\n  return (\n    <Form action={errorBag ? '/form-component/errors/bag' : '/form-component/errors'} method=\"post\" errorBag={errorBag}>\n      {({ errors, hasErrors, setError, clearErrors }) => (\n        <>\n          <h1>Form Errors</h1>\n\n          {hasErrors ? <div>Form has errors</div> : <div>No errors</div>}\n\n          <div>\n            <label htmlFor=\"name\">Name</label>\n            <input type=\"text\" name=\"name\" id=\"name\" />\n            <div id=\"error_name\">{errors.name}</div>\n          </div>\n\n          <div>\n            <label htmlFor=\"handle\">Handle</label>\n            <input type=\"text\" name=\"handle\" id=\"handle\" />\n            <div id=\"error_handle\">{errors.handle}</div>\n          </div>\n\n          <div>\n            <button\n              type=\"button\"\n              onClick={() =>\n                setError({\n                  name: 'The name field is required.',\n                  handle: 'The handle field is invalid.',\n                })\n              }\n            >\n              Set Errors\n            </button>\n            <button type=\"button\" onClick={() => clearErrors()}>\n              Clear Errors\n            </button>\n            <button type=\"button\" onClick={() => clearErrors('name')}>\n              Clear Name Error\n            </button>\n            <button type=\"button\" onClick={() => setErrorBag('bag')}>\n              Use Error Bag\n            </button>\n          </div>\n\n          <button type=\"submit\">Submit</button>\n        </>\n      )}\n    </Form>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Events.tsx",
    "content": "import { Form } from '@inertiajs/react'\nimport { useCallback, useMemo, useState } from 'react'\n\nexport default () => {\n  const [events, setEvents] = useState<string[]>([])\n  const [cancelInOnBefore, setCancelInOnBefore] = useState(false)\n  const [shouldFail, setShouldFail] = useState(false)\n  const [shouldDelay, setShouldDelay] = useState(false)\n\n  const [cancelToken, setCancelToken] = useState<{ cancel: () => void } | null>(null)\n\n  function log(eventName: string) {\n    setEvents((previousEvents) => [...previousEvents, eventName])\n  }\n\n  const action = useMemo(() => {\n    if (shouldFail) {\n      return '/form-component/events/errors'\n    }\n\n    if (shouldDelay) {\n      return '/form-component/events/delay'\n    }\n\n    return '/form-component/events/success'\n  }, [shouldFail, shouldDelay])\n\n  const formEvents = useMemo(\n    () => ({\n      onBefore: () => {\n        log('onBefore')\n\n        if (cancelInOnBefore) {\n          log('onCancel')\n          return false\n        }\n      },\n      onStart: () => log('onStart'),\n      onProgress: () => log('onProgress'),\n      onFinish: () => log('onFinish'),\n      onCancel: () => log('onCancel'),\n      onSuccess: () => log('onSuccess'),\n      onError: () => log('onError'),\n      onCancelToken: (token: { cancel: () => void }) => {\n        log('onCancelToken')\n        setCancelToken(token)\n      },\n    }),\n    [cancelInOnBefore],\n  )\n\n  const cancelVisit = useCallback(() => {\n    if (cancelToken) {\n      cancelToken.cancel()\n      setCancelToken(null)\n    }\n  }, [cancelToken])\n\n  return (\n    <Form action={action} method=\"post\" {...formEvents}>\n      {({ processing, progress, wasSuccessful, recentlySuccessful }) => (\n        <>\n          <h1>Form Events & State</h1>\n\n          <div>\n            Events: <span id=\"events\">{events.join(',')}</span>\n          </div>\n\n          <div>\n            Processing: <span id=\"processing\">{String(processing)}</span>\n          </div>\n\n          <div>\n            Progress:{' '}\n            <span id=\"progress\" className={progress?.percentage ? 'uploading' : undefined}>\n              {progress?.percentage || 0}\n            </span>\n          </div>\n\n          <div>\n            Was successful: <span id=\"was-successful\">{String(wasSuccessful)}</span>\n          </div>\n\n          <div>\n            Recently successful: <span id=\"recently-successful\">{String(recentlySuccessful)}</span>\n          </div>\n\n          <div>\n            <input type=\"file\" name=\"avatar\" id=\"avatar\" />\n          </div>\n\n          <div>\n            <button type=\"button\" onClick={() => setCancelInOnBefore(true)}>\n              Cancel in onBefore\n            </button>\n            <button type=\"button\" onClick={() => setShouldFail(true)}>\n              Fail Request\n            </button>\n            <button type=\"button\" onClick={() => setShouldDelay(true)}>\n              Should Delay\n            </button>\n            <button type=\"button\" onClick={cancelVisit}>\n              Cancel Visit\n            </button>\n            <button type=\"submit\">Submit</button>\n          </div>\n        </>\n      )}\n    </Form>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/FormTarget.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <Form action=\"/non-inertia/download\" method=\"get\">\n      <input type=\"text\" name=\"search\" id=\"search\" defaultValue=\"test-query\" />\n\n      <button type=\"submit\" formTarget=\"_blank\" name=\"format\" value=\"csv\" id=\"button-blank\">\n        Button with formTarget blank\n      </button>\n      <input type=\"submit\" formTarget=\"_blank\" name=\"type\" value=\"export\" id=\"input-blank\" />\n    </Form>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Headers.tsx",
    "content": "import { Form } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const [headers, setHeaders] = useState<Record<string, string>>({\n    'X-Foo': 'Bar',\n  })\n\n  function addCustomHeader() {\n    setHeaders((previousHeaders) => ({\n      ...previousHeaders,\n      'X-Custom': 'MyCustomValue',\n    }))\n  }\n\n  return (\n    <Form action=\"/dump/post\" method=\"post\" headers={headers}>\n      <h1>Form Headers</h1>\n\n      <div>\n        <button type=\"button\" onClick={addCustomHeader}>\n          Add Custom Header\n        </button>\n      </div>\n\n      <button type=\"submit\">Submit</button>\n    </Form>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/InvalidateTags.tsx",
    "content": "import { Form, Link } from '@inertiajs/react'\n\nexport default ({ lastLoaded, propType }: { lastLoaded: number; propType: string }) => {\n  return (\n    <div>\n      <div id=\"links\">\n        <Link href=\"/prefetch/tags/1\" prefetch=\"hover\" cacheTags={propType === 'string' ? 'user' : ['user']}>\n          User Tagged Page\n        </Link>\n        <Link href=\"/prefetch/tags/2\" prefetch=\"hover\" cacheTags={propType === 'string' ? 'product' : ['product']}>\n          Product Tagged Page\n        </Link>\n      </div>\n\n      <div id=\"form-section\">\n        <h3>Form Component with invalidateCacheTags</h3>\n        <Form action=\"/dump/post\" method=\"post\" invalidateCacheTags={propType === 'string' ? 'user' : ['user']}>\n          <input id=\"form-name\" name=\"name\" type=\"text\" placeholder=\"Enter name\" defaultValue=\"\" />\n          <button id=\"submit-invalidate-user\" type=\"submit\">\n            Submit (Invalidate User Tags)\n          </button>\n        </Form>\n      </div>\n\n      <div>\n        <div>Form Component Invalidate Tags Test Page</div>\n        <div>\n          Last loaded at <span id=\"last-loaded\">{lastLoaded}</span>\n        </div>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Methods.tsx",
    "content": "import type { Method } from '@inertiajs/core'\nimport { Form } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const [method, setMethod] = useState<Method>('get')\n\n  return (\n    <div>\n      <h1>HTTP Methods</h1>\n\n      <div>\n        <button onClick={() => setMethod('get')}>GET</button>\n        <button onClick={() => setMethod('post')}>POST</button>\n        <button onClick={() => setMethod('put')}>PUT</button>\n        <button onClick={() => setMethod('patch')}>PATCH</button>\n        <button onClick={() => setMethod('delete')}>DELETE</button>\n      </div>\n\n      <div>Current method: {method}</div>\n\n      <Form action={`/dump/${method}`} method={method}>\n        <div>\n          <input type=\"text\" name=\"name\" placeholder=\"Name\" defaultValue=\"John Doe\" />\n        </div>\n\n        <div>\n          <input type=\"checkbox\" name=\"active\" value=\"true\" defaultChecked />\n          <label>Active</label>\n        </div>\n\n        <div>\n          <button type=\"submit\">Submit {method.toUpperCase()}</button>\n        </div>\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/MixedKeySerialization.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>Mixed Key Serialization</h1>\n\n      <Form action=\"/dump/post\" method=\"post\">\n        <div>\n          <input type=\"text\" name=\"fields[entries][100][name]\" placeholder=\"Name for ID 100\" defaultValue=\"John Doe\" />\n        </div>\n\n        <div>\n          <input\n            type=\"email\"\n            name=\"fields[entries][100][email]\"\n            placeholder=\"Email for ID 100\"\n            defaultValue=\"john@example.com\"\n          />\n        </div>\n\n        <div>\n          <input\n            type=\"text\"\n            name=\"fields[entries][new:1][name]\"\n            placeholder=\"Name for new entry\"\n            defaultValue=\"Jane Smith\"\n          />\n        </div>\n\n        <div>\n          <input\n            type=\"email\"\n            name=\"fields[entries][new:1][email]\"\n            placeholder=\"Email for new entry\"\n            defaultValue=\"jane@example.com\"\n          />\n        </div>\n\n        <button type=\"submit\">Submit</button>\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Options.tsx",
    "content": "import type { Method, QueryStringArrayFormatOption } from '@inertiajs/core'\nimport { Form } from '@inertiajs/react'\nimport { useMemo, useState } from 'react'\nimport Article from './../Article'\n\nexport default () => {\n  const [only, setOnlyValues] = useState<string[]>([])\n  const [except, setExceptValues] = useState<string[]>([])\n  const [reset, setResetValues] = useState<string[]>([])\n  const [replace, setReplace] = useState(false)\n  const [state, setState] = useState('Default State')\n  const [preserveScroll, setPreserveScroll] = useState(false)\n  const [preserveState, setPreserveState] = useState(false)\n  const [preserveUrl, setPreserveUrl] = useState(false)\n  const [queryStringArrayFormat, setQueryStringArrayFormat] = useState<QueryStringArrayFormatOption | undefined>(\n    undefined,\n  )\n\n  function setOnly() {\n    setOnlyValues(['users'])\n  }\n\n  function setExcept() {\n    setExceptValues(['stats'])\n  }\n\n  function setReset() {\n    setResetValues(['orders'])\n  }\n\n  function enableReplace() {\n    setReplace(true)\n  }\n\n  function enablePreserveScroll() {\n    setPreserveScroll(true)\n  }\n\n  function enablePreserveState() {\n    setPreserveState(true)\n    setState('Replaced State')\n  }\n\n  function enablePreserveUrl() {\n    setPreserveUrl(true)\n  }\n\n  const action = useMemo(() => {\n    if (preserveScroll) {\n      return '/article'\n    }\n\n    if (preserveState) {\n      return '/form-component/options'\n    }\n\n    if (preserveUrl) {\n      return '/form-component/options?page=2'\n    }\n\n    return queryStringArrayFormat ? '/dump/get' : '/dump/post'\n  }, [preserveScroll, preserveState, preserveUrl, queryStringArrayFormat])\n\n  const method = useMemo((): Method => {\n    if (preserveScroll || preserveState || preserveUrl) {\n      return 'get'\n    }\n\n    return queryStringArrayFormat ? 'get' : 'post'\n  }, [preserveScroll, preserveState, preserveUrl, queryStringArrayFormat])\n\n  return (\n    <Form\n      action={action}\n      method={method}\n      options={{\n        only,\n        except,\n        reset,\n        replace,\n        preserveScroll,\n        preserveState,\n        preserveUrl,\n      }}\n      queryStringArrayFormat={queryStringArrayFormat}\n    >\n      {() => (\n        <>\n          <h1>Form Options</h1>\n\n          <input type=\"text\" name=\"tags[]\" value=\"alpha\" readOnly />\n          <input type=\"text\" name=\"tags[]\" value=\"beta\" readOnly />\n\n          <div>\n            State: <span id=\"state\">{state}</span>\n          </div>\n\n          <div>\n            <button type=\"button\" onClick={setOnly}>\n              Set Only (users)\n            </button>\n            <button type=\"button\" onClick={setExcept}>\n              Set Except (stats)\n            </button>\n            <button type=\"button\" onClick={setReset}>\n              Set Reset (orders)\n            </button>\n            <button type=\"button\" onClick={() => setQueryStringArrayFormat('brackets')}>\n              Use Brackets Format\n            </button>\n            <button type=\"button\" onClick={() => setQueryStringArrayFormat('indices')}>\n              Use Indices Format\n            </button>\n            <button type=\"button\" onClick={enablePreserveScroll}>\n              Enable Preserve Scroll\n            </button>\n            <button type=\"button\" onClick={enablePreserveState}>\n              Enable Preserve State\n            </button>\n            <button type=\"button\" onClick={enablePreserveUrl}>\n              Enable Preserve URL\n            </button>\n            <button type=\"button\" onClick={enableReplace}>\n              Enable Replace\n            </button>\n            <button type=\"submit\">Submit</button>\n          </div>\n\n          {preserveScroll && <Article />}\n        </>\n      )}\n    </Form>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Precognition/BeforeValidation.tsx",
    "content": "import { Form } from '@inertiajs/react'\nimport { isEqual } from 'lodash-es'\n\nexport default function PrecognitionBefore() {\n  const handleBeforeValidation = (\n    newRequest: { data: Record<string, unknown> | null; touched: string[] },\n    oldRequest: { data: Record<string, unknown> | null; touched: string[] },\n  ) => {\n    const payloadIsCorrect =\n      isEqual(newRequest, { data: { name: 'block' }, touched: ['name'] }) &&\n      isEqual(oldRequest, { data: {}, touched: [] })\n\n    if (payloadIsCorrect && newRequest.data?.name === 'block') {\n      return false\n    }\n\n    return true\n  }\n\n  return (\n    <div>\n      <h1>Precognition - onBefore</h1>\n\n      <Form action=\"/precognition/default\" method=\"post\" validationTimeout={100}>\n        {({ errors, invalid, validate, validating }) => (\n          <>\n            <div>\n              <label htmlFor=\"name\">Name:</label>\n              <input\n                id=\"name\"\n                name=\"name\"\n                onChange={() =>\n                  validate('name', {\n                    onBeforeValidation: handleBeforeValidation,\n                  })\n                }\n              />\n              {invalid('name') && <p className=\"error\">{errors.name}</p>}\n            </div>\n\n            <div>\n              <label htmlFor=\"email\">Email:</label>\n              <input id=\"email\" name=\"email\" onChange={() => validate('email')} />\n              {invalid('email') && <p className=\"error\">{errors.email}</p>}\n            </div>\n\n            {validating && <p className=\"validating\">Validating...</p>}\n\n            <button type=\"submit\">Submit</button>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Precognition/Callbacks.tsx",
    "content": "import { Form } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const [successCalled, setSuccessCalled] = useState(false)\n  const [errorCalled, setErrorCalled] = useState(false)\n  const [finishCalled, setFinishCalled] = useState(false)\n\n  return (\n    <div>\n      <h1>Form Precognition Callbacks</h1>\n\n      <h2>Callbacks Test</h2>\n      <Form action=\"/precognition/default\" method=\"post\" validationTimeout={100}>\n        {({ validate, validating, touch }) => (\n          <>\n            <div>\n              <input name=\"name\" placeholder=\"Name\" onBlur={() => touch('name')} />\n            </div>\n\n            {validating && <p>Validating...</p>}\n            {successCalled && <p>onPrecognitionSuccess called!</p>}\n            {errorCalled && <p>onValidationError called!</p>}\n            {finishCalled && <p>onFinish called!</p>}\n\n            <button\n              type=\"button\"\n              onClick={() => {\n                setSuccessCalled(false)\n                setErrorCalled(false)\n                setFinishCalled(false)\n                validate({\n                  onPrecognitionSuccess: () => {\n                    setSuccessCalled(true)\n                  },\n                  onValidationError: () => {\n                    setErrorCalled(true)\n                  },\n                  onFinish: () => {\n                    setFinishCalled(true)\n                  },\n                })\n              }}\n            >\n              Validate\n            </button>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Precognition/Cancel.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>Precognition - Cancel Tests</h1>\n\n      <h2>Auto Cancel Test</h2>\n      <Form action=\"/precognition/default?slow=1\" method=\"post\" validationTimeout={100}>\n        {({ invalid, errors, validate, validating }) => (\n          <>\n            <div>\n              <input id=\"auto-cancel-name-input\" name=\"name\" placeholder=\"Name\" onBlur={() => validate('name')} />\n              {invalid('name') && <p className=\"error\">{errors.name}</p>}\n            </div>\n\n            {validating && <p className=\"validating\">Validating...</p>}\n\n            <button type=\"submit\">Submit</button>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Precognition/Default.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>Form Precognition</h1>\n\n      <Form action=\"/precognition/default\" method=\"post\" validationTimeout={100}>\n        {({ invalid, errors, validate, valid, validating }) => (\n          <>\n            <div>\n              <input name=\"name\" placeholder=\"Name\" onBlur={() => validate('name')} />\n              {invalid('name') && <p>{errors.name}</p>}\n              {valid('name') && <p>Name is valid!</p>}\n            </div>\n\n            <div>\n              <input name=\"email\" placeholder=\"Email\" onBlur={() => validate('email')} />\n              {invalid('email') && <p>{errors.email}</p>}\n              {valid('email') && <p>Email is valid!</p>}\n            </div>\n\n            {validating && <p>Validating...</p>}\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Precognition/DynamicArrayInputs.tsx",
    "content": "import { Form } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const [items, setItems] = useState<Array<{ name: string }>>([])\n\n  function addItem() {\n    setItems([...items, { name: '' }])\n  }\n\n  function updateItem(index: number, value: string) {\n    const newItems = [...items]\n    newItems[index] = { name: value }\n    setItems(newItems)\n  }\n\n  return (\n    <div>\n      <button id=\"add-item\" onClick={addItem}>\n        Add Item\n      </button>\n\n      <Form action=\"/precognition/dynamic-array-inputs\" method=\"post\" validationTimeout={100}>\n        {({ invalid, errors, validate, validating }) => (\n          <>\n            {items.map((item, idx) => (\n              <div key={idx}>\n                <input\n                  value={item.name}\n                  name={`items.${idx}.name`}\n                  onChange={(e) => updateItem(idx, e.target.value)}\n                  onBlur={() => validate(`items.${idx}.name`)}\n                />\n                {invalid(`items.${idx}.name`) && <p id={`items.${idx}.name-error`}>{errors[`items.${idx}.name`]}</p>}\n              </div>\n            ))}\n\n            {validating && <p>Validating...</p>}\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Precognition/ErrorSync.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>Precognition Error Sync Test</h1>\n\n      <Form action=\"/precognition/error-sync\" method=\"post\" validationTimeout={100}>\n        {({ invalid, errors, validate, validating }) => (\n          <>\n            <div>\n              <input name=\"name\" placeholder=\"Name\" onBlur={() => validate('name')} />\n              {invalid('name') && <p id=\"name-error\">{errors.name}</p>}\n            </div>\n\n            <div>\n              <input name=\"email\" placeholder=\"Email\" onBlur={() => validate('email')} />\n              {invalid('email') && <p id=\"email-error\">{errors.email}</p>}\n            </div>\n\n            {validating && <p id=\"validating\">Validating...</p>}\n\n            <button type=\"submit\" id=\"submit-btn\">\n              Submit\n            </button>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Precognition/Files.tsx",
    "content": "import { Form } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const [validateFilesEnabled, setValidateFilesEnabled] = useState(false)\n\n  return (\n    <div>\n      <h1>Form Precognition Files</h1>\n\n      <Form action=\"/precognition/files\" method=\"post\" validationTimeout={100} validateFiles={validateFilesEnabled}>\n        {({ invalid, errors, validate, valid, validating }) => (\n          <>\n            <div>\n              <input name=\"name\" placeholder=\"Name\" onBlur={() => validate('name')} />\n              {invalid('name') && <p>{errors.name}</p>}\n              {valid('name') && <p>Name is valid!</p>}\n            </div>\n\n            <div>\n              <input type=\"file\" name=\"avatar\" id=\"avatar\" />\n              {invalid('avatar') && <p>{errors.avatar}</p>}\n              {valid('avatar') && <p>Avatar is valid!</p>}\n            </div>\n\n            {validating && <p>Validating...</p>}\n\n            <button type=\"button\" onClick={() => setValidateFilesEnabled(!validateFilesEnabled)}>\n              Toggle Validate Files ({validateFilesEnabled ? 'enabled' : 'disabled'})\n            </button>\n\n            <button type=\"button\" onClick={() => validate({ only: ['name', 'avatar'] })}>\n              Validate Both\n            </button>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Precognition/Headers.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default function PrecognitionHeaders() {\n  return (\n    <div>\n      <h1>Precognition - Custom Headers</h1>\n\n      <Form\n        action=\"/precognition/headers\"\n        method=\"post\"\n        headers={{ 'X-Custom-Header': 'custom-value' }}\n        validationTimeout={100}\n      >\n        {({ invalid, errors, validate, validating }) => (\n          <>\n            <div>\n              <input name=\"name\" placeholder=\"Name\" onBlur={() => validate('name')} />\n              {invalid('name') && <p>{errors.name}</p>}\n            </div>\n\n            {validating && <p>Validating...</p>}\n\n            <button type=\"submit\">Submit</button>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Precognition/Methods.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>Form Precognition - Touch, Reset & Validate</h1>\n\n      <Form action=\"/precognition/default\" method=\"post\" validationTimeout={100}>\n        {({ invalid, errors, validate, touch, touched, validating, reset }) => (\n          <>\n            <div>\n              <input name=\"name\" placeholder=\"Name\" onBlur={() => touch('name')} />\n              {invalid('name') && <p>{errors.name}</p>}\n            </div>\n\n            <div>\n              <input name=\"email\" placeholder=\"Email\" onBlur={() => touch('email')} />\n              {invalid('email') && <p>{errors.email}</p>}\n            </div>\n\n            {validating && <p>Validating...</p>}\n\n            <p id=\"name-touched\">{touched('name') ? 'Name is touched' : 'Name is not touched'}</p>\n            <p id=\"email-touched\">{touched('email') ? 'Email is touched' : 'Email is not touched'}</p>\n            <p id=\"any-touched\">{touched() ? 'Form has touched fields' : 'Form has no touched fields'}</p>\n\n            <button type=\"button\" onClick={() => validate()}>\n              Validate All Touched\n            </button>\n            <button type=\"button\" onClick={() => validate('name')}>\n              Validate Name\n            </button>\n            <button type=\"button\" onClick={() => validate({ only: ['name', 'email'] })}>\n              Validate Name and Email\n            </button>\n            <button type=\"button\" onClick={() => touch('name', 'email')}>\n              Touch Name and Email\n            </button>\n            <button\n              type=\"button\"\n              onClick={() => {\n                touch('name')\n                touch('name')\n              }}\n            >\n              Touch Name Twice\n            </button>\n            <button type=\"button\" onClick={() => reset()}>\n              Reset All\n            </button>\n            <button type=\"button\" onClick={() => reset('name')}>\n              Reset Name\n            </button>\n            <button type=\"button\" onClick={() => reset('name', 'email')}>\n              Reset Name and Email\n            </button>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Precognition/Transform.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>Form Precognition Transform</h1>\n\n      <Form\n        action=\"/precognition/default\"\n        method=\"post\"\n        validationTimeout={100}\n        transform={(data) => ({ name: String(data.name || '').repeat(2) })}\n      >\n        {({ invalid, errors, validate, valid, validating }) => (\n          <>\n            <div>\n              <input name=\"name\" placeholder=\"Name\" onBlur={() => validate('name')} />\n              {invalid('name') && <p>{errors.name}</p>}\n              {valid('name') && <p>Name is valid!</p>}\n            </div>\n\n            {validating && <p>Validating...</p>}\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Precognition/TransformKeys.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst transformData = (data: Record<string, any>) => {\n  const document = data.document || {}\n  return document\n}\n\nexport default () => {\n  return (\n    <div>\n      <h1>Form Precognition Transform Keys</h1>\n\n      <Form action=\"/precognition/transform-keys\" method=\"post\" validationTimeout={100} transform={transformData}>\n        {({ invalid, errors, validate, valid, validating }) => (\n          <>\n            <div>\n              <input\n                id=\"email-input\"\n                name=\"document[customer][email]\"\n                placeholder=\"Email\"\n                onBlur={() => validate('customer.email')}\n              />\n              {invalid('customer.email') && <p>{errors['customer.email']}</p>}\n              {valid('customer.email') && <p>Email is valid!</p>}\n            </div>\n\n            {validating && <p>Validating...</p>}\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Precognition/WithAllErrors.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>Form Precognition - All Errors</h1>\n\n      <Form action=\"/precognition/with-all-errors\" method=\"post\" validationTimeout={100} withAllErrors>\n        {({ invalid, errors, validate, valid, validating }) => (\n          <>\n            <div>\n              <input name=\"name\" placeholder=\"Name\" onBlur={() => validate('name')} />\n              {invalid('name') && (\n                <div>\n                  {Array.isArray(errors.name) ? (\n                    errors.name.map((error, index) => (\n                      <p key={index} id={`name-error-${index}`}>\n                        {error}\n                      </p>\n                    ))\n                  ) : (\n                    <p id=\"name-error-0\">{errors.name}</p>\n                  )}\n                </div>\n              )}\n              {valid('name') && <p>Name is valid!</p>}\n            </div>\n\n            <div>\n              <input name=\"email\" placeholder=\"Email\" onBlur={() => validate('email')} />\n              {invalid('email') && (\n                <div>\n                  {Array.isArray(errors.email) ? (\n                    errors.email.map((error, index) => (\n                      <p key={index} id={`email-error-${index}`}>\n                        {error}\n                      </p>\n                    ))\n                  ) : (\n                    <p id=\"email-error-0\">{errors.email}</p>\n                  )}\n                </div>\n              )}\n              {valid('email') && <p>Email is valid!</p>}\n            </div>\n\n            {validating && <p>Validating...</p>}\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Precognition/WithAllErrorsConfig.tsx",
    "content": "import { config, Form } from '@inertiajs/react'\n\nexport default () => {\n  // Set global config for withAllErrors (no prop on the Form component)\n  config.set('form.withAllErrors', true)\n\n  return (\n    <div>\n      <h1>Form Precognition - All Errors via Config</h1>\n\n      <Form action=\"/precognition/with-all-errors\" method=\"post\" validationTimeout={100}>\n        {({ invalid, errors, validate, valid, validating }) => (\n          <>\n            <div>\n              <input name=\"name\" placeholder=\"Name\" onBlur={() => validate('name')} />\n              {invalid('name') && (\n                <div>\n                  {Array.isArray(errors.name) ? (\n                    errors.name.map((error, index) => (\n                      <p key={index} id={`name-error-${index}`}>\n                        {error}\n                      </p>\n                    ))\n                  ) : (\n                    <p id=\"name-error-0\">{errors.name}</p>\n                  )}\n                </div>\n              )}\n              {valid('name') && <p>Name is valid!</p>}\n            </div>\n\n            <div>\n              <input name=\"email\" placeholder=\"Email\" onBlur={() => validate('email')} />\n              {invalid('email') && (\n                <div>\n                  {Array.isArray(errors.email) ? (\n                    errors.email.map((error, index) => (\n                      <p key={index} id={`email-error-${index}`}>\n                        {error}\n                      </p>\n                    ))\n                  ) : (\n                    <p id=\"email-error-0\">{errors.email}</p>\n                  )}\n                </div>\n              )}\n              {valid('email') && <p>Email is valid!</p>}\n            </div>\n\n            {validating && <p>Validating...</p>}\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Precognition/WithoutAllErrors.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>Form Precognition - Array Errors</h1>\n\n      <Form action=\"/precognition/with-all-errors\" method=\"post\" validationTimeout={100}>\n        {({ invalid, errors, validate, valid, validating }) => (\n          <>\n            <div>\n              <input name=\"name\" placeholder=\"Name\" onBlur={() => validate('name')} />\n              {invalid('name') && <p>{errors.name}</p>}\n              {valid('name') && <p>Name is valid!</p>}\n            </div>\n\n            <div>\n              <input name=\"email\" placeholder=\"Email\" onBlur={() => validate('email')} />\n              {invalid('email') && <p>{errors.email}</p>}\n              {valid('email') && <p>Email is valid!</p>}\n            </div>\n\n            {validating && <p>Validating...</p>}\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Progress.tsx",
    "content": "import { Form } from '@inertiajs/react'\nimport { useEffect, useRef, useState } from 'react'\n\nexport default () => {\n  const [showProgress, setShowProgress] = useState<boolean | undefined>(undefined)\n  const [nprogressVisible, setNprogressVisible] = useState(false)\n  const [nprogressAppearances, setNprogressAppearances] = useState(0)\n\n  const observerRef = useRef<MutationObserver | null>(null)\n\n  function disableProgress() {\n    setShowProgress(false)\n  }\n\n  useEffect(() => {\n    observerRef.current = new MutationObserver(() => {\n      const nprogressElement = document.querySelector('#nprogress') as HTMLElement | null\n      const nprogressIsCurrentlyVisible = nprogressElement && nprogressElement.style.display !== 'none'\n\n      if (nprogressIsCurrentlyVisible) {\n        if (!nprogressVisible) {\n          setNprogressVisible(true)\n          setNprogressAppearances((previousCount) => previousCount + 1)\n        }\n      } else {\n        setNprogressVisible(false)\n      }\n    })\n\n    observerRef.current.observe(document.body, { childList: true, subtree: true })\n\n    return () => observerRef.current?.disconnect()\n  }, [nprogressVisible])\n\n  return (\n    <Form action=\"/form-component/progress\" method=\"post\" showProgress={showProgress}>\n      <h1>Progress</h1>\n\n      <div>\n        Nprogress appearances: <span id=\"nprogress-appearances\">{nprogressAppearances}</span>\n      </div>\n\n      <div>\n        <button type=\"button\" onClick={disableProgress}>\n          Disable Progress\n        </button>\n        <button type=\"submit\">Submit</button>\n      </div>\n    </Form>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Ref.tsx",
    "content": "import { FormComponentRef } from '@inertiajs/core'\nimport { Form } from '@inertiajs/react'\nimport { useRef } from 'react'\n\nexport default function Ref() {\n  const formRef = useRef<FormComponentRef>(null)\n\n  const submitProgrammatically = () => {\n    formRef.current?.submit()\n  }\n\n  const resetForm = () => {\n    formRef.current?.reset()\n  }\n\n  const resetNameField = () => {\n    formRef.current?.reset('name')\n  }\n\n  const clearAllErrors = () => {\n    formRef.current?.clearErrors()\n  }\n\n  const setTestError = () => {\n    formRef.current?.setError('name', 'This is a test error')\n  }\n\n  const setCurrentAsDefaults = () => {\n    formRef.current?.defaults()\n  }\n\n  const callPrecognitionMethods = () => {\n    const validator = formRef.current?.validator()\n\n    if (validator && !formRef.current?.touched('company') && !formRef.current?.valid('company')) {\n      formRef.current?.validate({ only: ['company'] })\n    }\n  }\n\n  return (\n    <div>\n      <h1>Form Ref Test</h1>\n\n      <Form ref={formRef} action=\"/dump/post\" method=\"post\">\n        {({ isDirty, hasErrors, errors }) => (\n          <>\n            {/* State display for testing */}\n            <div>Form is {isDirty ? 'dirty' : 'clean'}</div>\n            {hasErrors && <div>Form has errors</div>}\n            {errors.name && <div id=\"error_name\">{errors.name}</div>}\n\n            <div>\n              <input type=\"text\" name=\"name\" placeholder=\"Name\" defaultValue=\"John Doe\" />\n            </div>\n\n            <div>\n              <input type=\"email\" name=\"email\" placeholder=\"Email\" defaultValue=\"john@example.com\" />\n            </div>\n\n            <div>\n              <button type=\"submit\">Submit via Form</button>\n            </div>\n          </>\n        )}\n      </Form>\n\n      <div>\n        <button onClick={submitProgrammatically}>Submit Programmatically</button>\n        <button onClick={resetForm}>Reset Form</button>\n        <button onClick={resetNameField}>Reset Name Field</button>\n        <button onClick={clearAllErrors}>Clear Errors</button>\n        <button onClick={setTestError}>Set Test Error</button>\n        <button onClick={setCurrentAsDefaults}>Set Current as Defaults</button>\n        <button onClick={callPrecognitionMethods}>Call Precognition Methods</button>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Reset.tsx",
    "content": "import { FormComponentRef } from '@inertiajs/core'\nimport { Form } from '@inertiajs/react'\nimport { useRef } from 'react'\n\ndeclare global {\n  interface Window {\n    resetForm: (...fields: string[]) => void\n  }\n}\n\nexport default function Reset() {\n  const formRef = useRef<FormComponentRef>(null)\n\n  // Expose reset function to window for testing\n  window.resetForm = (...fields: string[]) => {\n    formRef.current?.reset(...fields)\n  }\n\n  return (\n    <Form action=\"/dump/post\" method=\"post\" ref={formRef}>\n      <h1>Form Reset</h1>\n\n      {/* Basic Text Inputs */}\n      <h2>Basic Text Inputs</h2>\n      <input type=\"text\" name=\"name\" id=\"name\" defaultValue=\"John Doe\" />\n      <input type=\"email\" name=\"email\" id=\"email\" defaultValue=\"john@example.com\" />\n\n      {/* Select Elements */}\n      <h2>Select Elements</h2>\n      <select name=\"country\" id=\"country\" defaultValue=\"uk\">\n        <option value=\"us\">United States</option>\n        <option value=\"ca\">Canada</option>\n        <option value=\"uk\">United Kingdom</option>\n      </select>\n      <select name=\"role\" id=\"role\" defaultValue=\"\">\n        <option value=\"\">Select a role</option>\n        <option value=\"user\">User</option>\n        <option value=\"admin\">Admin</option>\n        <option value=\"super\">Super</option>\n      </select>\n\n      {/* Radio Buttons */}\n      <h2>Radio Buttons</h2>\n\n      {/* Radio buttons with default checked */}\n      <div>\n        <label>\n          <input type=\"radio\" name=\"plan\" id=\"plan_free\" value=\"free\" /> Free\n        </label>\n        <label>\n          <input type=\"radio\" name=\"plan\" id=\"plan_pro\" value=\"pro\" defaultChecked /> Pro\n        </label>\n        <label>\n          <input type=\"radio\" name=\"plan\" id=\"plan_enterprise\" value=\"enterprise\" /> Enterprise\n        </label>\n      </div>\n\n      {/* Radio buttons without default */}\n      <div>\n        <label>\n          <input type=\"radio\" name=\"payment\" id=\"payment_card\" value=\"card\" /> Card\n        </label>\n        <label>\n          <input type=\"radio\" name=\"payment\" id=\"payment_bank\" value=\"bank\" /> Bank\n        </label>\n        <label>\n          <input type=\"radio\" name=\"payment\" id=\"payment_paypal\" value=\"paypal\" /> PayPal\n        </label>\n      </div>\n\n      {/* Radio buttons designed to test multiple defaults edge case */}\n      <div>\n        <label>\n          <input type=\"radio\" name=\"priority\" id=\"priority_low\" value=\"low\" defaultChecked /> Low\n        </label>\n        <label>\n          <input type=\"radio\" name=\"priority\" id=\"priority_medium\" value=\"medium\" /> Medium\n        </label>\n        <label>\n          <input type=\"radio\" name=\"priority\" id=\"priority_high\" value=\"high\" /> High\n        </label>\n      </div>\n\n      {/* Checkboxes */}\n      <h2>Checkboxes</h2>\n\n      {/* Checkbox (single) with default checked */}\n      <div>\n        <input type=\"checkbox\" name=\"subscribe\" id=\"subscribe\" value=\"yes\" defaultChecked />\n        <label htmlFor=\"subscribe\">Subscribe to newsletter</label>\n      </div>\n\n      {/* Checkbox (single) without default */}\n      <div>\n        <input type=\"checkbox\" name=\"terms\" id=\"terms\" value=\"accepted\" />\n        <label htmlFor=\"terms\">Accept terms</label>\n      </div>\n\n      {/* Checkbox (multiple) with some checked */}\n      <div>\n        <label>\n          <input type=\"checkbox\" name=\"interests[]\" id=\"interests_sports\" value=\"sports\" defaultChecked /> Sports\n        </label>\n        <label>\n          <input type=\"checkbox\" name=\"interests[]\" id=\"interests_music\" value=\"music\" /> Music\n        </label>\n        <label>\n          <input type=\"checkbox\" name=\"interests[]\" id=\"interests_tech\" value=\"tech\" defaultChecked /> Tech\n        </label>\n        <label>\n          <input type=\"checkbox\" name=\"interests[]\" id=\"interests_art\" value=\"art\" /> Art\n        </label>\n      </div>\n\n      {/* Multiple Select Elements */}\n      <h2>Multiple Select Elements</h2>\n      <select name=\"skills[]\" id=\"skills\" multiple defaultValue={['vue', 'angular']}>\n        <option value=\"vue\">Vue</option>\n        <option value=\"react\">React</option>\n        <option value=\"angular\">Angular</option>\n        <option value=\"svelte\">Svelte</option>\n      </select>\n      <select name=\"languages[]\" id=\"languages\" multiple defaultValue={[]}>\n        <option value=\"javascript\">JavaScript</option>\n        <option value=\"typescript\">TypeScript</option>\n        <option value=\"python\">Python</option>\n        <option value=\"php\">PHP</option>\n      </select>\n      <select name=\"tools[]\" id=\"tools\" multiple defaultValue={['vscode', 'webstorm', 'sublime']}>\n        <option value=\"vscode\">VSCode</option>\n        <option value=\"webstorm\">WebStorm</option>\n        <option value=\"sublime\">Sublime</option>\n      </select>\n      <select name=\"editor\" id=\"editor\" defaultValue=\"vim\">\n        <option value=\"\">Select Editor</option>\n        <option value=\"vim\">Vim</option>\n        <option value=\"emacs\">Emacs</option>\n        <option value=\"nano\">Nano</option>\n      </select>\n\n      {/* File Inputs & Textareas */}\n      <h2>File Inputs & Textareas</h2>\n      <input type=\"file\" name=\"avatar\" id=\"avatar\" />\n      <input type=\"file\" name=\"documents[]\" id=\"documents\" multiple />\n      <textarea name=\"bio\" id=\"bio\" rows={3} defaultValue=\"Default bio text here.\" />\n      <textarea name=\"notes\" id=\"notes\" rows={2} defaultValue=\"\" />\n\n      {/* HTML5 Input Types */}\n      <h2>HTML5 Input Types</h2>\n      <input type=\"hidden\" name=\"token\" id=\"token\" defaultValue=\"abc123\" />\n      <input type=\"number\" name=\"age\" id=\"age\" defaultValue=\"25\" />\n      <input type=\"number\" name=\"quantity\" id=\"quantity\" />\n      <input type=\"range\" name=\"volume\" id=\"volume\" min=\"0\" max=\"100\" defaultValue=\"50\" />\n      <input type=\"date\" name=\"birthdate\" id=\"birthdate\" defaultValue=\"1990-01-01\" />\n      <input type=\"time\" name=\"appointment\" id=\"appointment\" defaultValue=\"14:30\" />\n      <input type=\"color\" name=\"favorite_color\" id=\"favorite_color\" defaultValue=\"#ff0000\" />\n      <input type=\"url\" name=\"website\" id=\"website\" defaultValue=\"https://example.com\" />\n      <input type=\"tel\" name=\"phone\" id=\"phone\" defaultValue=\"+1234567890\" />\n      <input type=\"password\" name=\"password\" id=\"password\" defaultValue=\"secret123\" />\n\n      {/* Complex Nested Fields */}\n      <h2>Complex Nested Fields</h2>\n      <input type=\"text\" name=\"user[address][street]\" id=\"nested_street\" defaultValue=\"123 Main St\" />\n      <input type=\"text\" name=\"user[address][city]\" id=\"nested_city\" defaultValue=\"New York\" />\n      <input type=\"text\" name=\"items[0][name]\" id=\"item_0_name\" defaultValue=\"Item A\" />\n      <input type=\"number\" name=\"items[0][quantity]\" id=\"item_0_quantity\" defaultValue=\"5\" />\n      <input type=\"text\" name=\"items[1][name]\" id=\"item_1_name\" defaultValue=\"Item B\" />\n      <input type=\"number\" name=\"items[1][quantity]\" id=\"item_1_quantity\" defaultValue=\"10\" />\n\n      {/* Special Cases */}\n      <h2>Special Cases</h2>\n      <input type=\"text\" name=\"disabled_field\" id=\"disabled_field\" defaultValue=\"Ignore me\" disabled />\n      <input type=\"button\" name=\"button_input\" value=\"Click me\" />\n      <input type=\"submit\" name=\"submit_input\" value=\"Submit Form\" />\n      <input type=\"reset\" name=\"reset_input\" value=\"Reset Form\" />\n      <button type=\"reset\" name=\"reset_button\">\n        Reset Form\n      </button>\n\n      {/* Dotted & Array Notation */}\n      <h2>Dotted & Array Notation</h2>\n      <input type=\"text\" name=\"user.name\" id=\"user_name\" defaultValue=\"Default User\" />\n      <input type=\"text\" name=\"user.email\" id=\"user_email\" defaultValue=\"user@default.com\" />\n      <input type=\"text\" name=\"company.name\" id=\"company_name\" defaultValue=\"Default Corp\" />\n      <input type=\"text\" name=\"tags[]\" id=\"tag_0\" defaultValue=\"javascript\" />\n      <input type=\"text\" name=\"tags[]\" id=\"tag_1\" defaultValue=\"vue\" />\n      <input type=\"text\" name=\"tags[]\" id=\"tag_2\" defaultValue=\"inertia\" />\n\n      {/* Numeric Values */}\n      <h2>Numeric Values</h2>\n      <div>\n        <label>\n          <input type=\"radio\" name=\"rating\" id=\"rating_1\" value=\"1\" defaultChecked /> 1 Star\n        </label>\n        <label>\n          <input type=\"radio\" name=\"rating\" id=\"rating_2\" value=\"2\" /> 2 Stars\n        </label>\n        <label>\n          <input type=\"radio\" name=\"rating\" id=\"rating_3\" value=\"3\" /> 3 Stars\n        </label>\n      </div>\n      <div>\n        <label>\n          <input type=\"checkbox\" name=\"years[]\" id=\"years_2020\" value=\"2020\" defaultChecked /> 2020\n        </label>\n        <label>\n          <input type=\"checkbox\" name=\"years[]\" id=\"years_2021\" value=\"2021\" /> 2021\n        </label>\n        <label>\n          <input type=\"checkbox\" name=\"years[]\" id=\"years_2022\" value=\"2022\" defaultChecked /> 2022\n        </label>\n      </div>\n      <select name=\"version\" id=\"version\" defaultValue=\"1\">\n        <option value=\"1\">Version 1</option>\n        <option value=\"2\">Version 2</option>\n        <option value=\"3\">Version 3</option>\n      </select>\n      <select name=\"ports[]\" id=\"ports\" multiple defaultValue={['80', '443']}>\n        <option value=\"80\">Port 80</option>\n        <option value=\"443\">Port 443</option>\n        <option value=\"8080\">Port 8080</option>\n      </select>\n\n      {/* Submit button */}\n      <h2>Submit</h2>\n      <button type=\"submit\">Submit</button>\n    </Form>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/ResetAttributes/ResetOnError.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>Reset On Error Test</h1>\n\n      <Form method=\"post\" action=\"/form-component/reset-on-error\" resetOnError>\n        {({ errors }) => (\n          <>\n            <div>\n              <label htmlFor=\"name\">Name</label>\n              <input type=\"text\" name=\"name\" id=\"name\" defaultValue=\"John Doe\" />\n              {errors.name && <p id=\"error_name\">{errors.name}</p>}\n            </div>\n\n            <div>\n              <label htmlFor=\"email\">Email</label>\n              <input type=\"email\" name=\"email\" id=\"email\" defaultValue=\"john@doe.biz\" />\n              {errors.email && <p id=\"error_email\">{errors.email}</p>}\n            </div>\n\n            <button type=\"submit\">Submit</button>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/ResetAttributes/ResetOnErrorFields.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>Reset On Error (Specific Fields) Test</h1>\n\n      <Form method=\"post\" action=\"/form-component/reset-on-error-fields\" resetOnError={['name']}>\n        {({ errors }) => (\n          <>\n            <div>\n              <label htmlFor=\"name\">Name</label>\n              <input type=\"text\" name=\"name\" id=\"name\" defaultValue=\"John Doe\" />\n              {errors.name && <p id=\"error_name\">{errors.name}</p>}\n            </div>\n\n            <div>\n              <label htmlFor=\"email\">Email</label>\n              <input type=\"email\" name=\"email\" id=\"email\" defaultValue=\"john@doe.biz\" />\n              {errors.email && <p id=\"error_email\">{errors.email}</p>}\n            </div>\n\n            <button type=\"submit\">Submit</button>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccess.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>Reset On Success Test</h1>\n\n      <Form method=\"post\" action=\"/form-component/reset-on-success\" resetOnSuccess>\n        {({ errors }) => (\n          <>\n            <div>\n              <label htmlFor=\"name\">Name</label>\n              <input type=\"text\" name=\"name\" id=\"name\" defaultValue=\"John Doe\" />\n              {errors.name && <p id=\"error_name\">{errors.name}</p>}\n            </div>\n\n            <div>\n              <label htmlFor=\"email\">Email</label>\n              <input type=\"email\" name=\"email\" id=\"email\" defaultValue=\"john@doe.biz\" />\n              {errors.email && <p id=\"error_email\">{errors.email}</p>}\n            </div>\n\n            <button type=\"submit\">Submit</button>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccessFields.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>Reset On Success (Specific Fields) Test</h1>\n\n      <Form method=\"post\" action=\"/form-component/reset-on-success-fields\" resetOnSuccess={['name']}>\n        {({ errors }) => (\n          <>\n            <div>\n              <label htmlFor=\"name\">Name</label>\n              <input type=\"text\" name=\"name\" id=\"name\" defaultValue=\"John Doe\" />\n              {errors.name && <p id=\"error_name\">{errors.name}</p>}\n            </div>\n\n            <div>\n              <label htmlFor=\"email\">Email</label>\n              <input type=\"email\" name=\"email\" id=\"email\" defaultValue=\"john@doe.biz\" />\n              {errors.email && <p id=\"error_email\">{errors.email}</p>}\n            </div>\n\n            <button type=\"submit\">Submit</button>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/SetDefaultsOnSuccess.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>Set Defaults On Success Test</h1>\n\n      <Form method=\"post\" action=\"/form-component/set-defaults-on-success\" setDefaultsOnSuccess>\n        {({ errors, isDirty }) => (\n          <>\n            <p id=\"dirty-status\">{isDirty ? 'Form is dirty' : 'Form is clean'}</p>\n\n            <div>\n              <label htmlFor=\"name\">Name</label>\n              <input type=\"text\" name=\"name\" id=\"name\" defaultValue=\"John Doe\" />\n              {errors.name && <p id=\"error_name\">{errors.name}</p>}\n            </div>\n\n            <div>\n              <label htmlFor=\"email\">Email</label>\n              <input type=\"email\" name=\"email\" id=\"email\" defaultValue=\"john@doe.biz\" />\n              {errors.email && <p id=\"error_email\">{errors.email}</p>}\n            </div>\n\n            <button type=\"submit\">Submit</button>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/SubmitButton.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <Form action=\"/dump/post\" method=\"post\">\n      <h1>Submit Button Test</h1>\n\n      <input type=\"text\" name=\"name\" id=\"name\" defaultValue=\"John Doe\" />\n\n      <button type=\"submit\" name=\"action\" value=\"save\" id=\"save-button\">\n        Save\n      </button>\n      <button type=\"submit\" name=\"action\" value=\"draft\" id=\"draft-button\">\n        Save as Draft\n      </button>\n      <button type=\"submit\" id=\"no-name-button\">\n        Submit Without Name\n      </button>\n    </Form>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/SubmitComplete/Defaults.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>OnSubmitComplete Defaults Test</h1>\n\n      <Form method=\"post\" onSubmitComplete={(props) => props.defaults()}>\n        {({ errors, isDirty }) => (\n          <>\n            <div>\n              <p id=\"dirty-status\">{isDirty ? 'Form is dirty' : 'Form is clean'}</p>\n            </div>\n\n            <div>\n              <input type=\"text\" name=\"name\" id=\"name\" placeholder=\"Name\" defaultValue=\"John Doe\" />\n              {errors.name && <p id=\"error_name\">{errors.name}</p>}\n            </div>\n\n            <div>\n              <input type=\"email\" name=\"email\" id=\"email\" placeholder=\"Email\" defaultValue=\"john@doe.biz\" />\n              {errors.email && <p id=\"error_email\">{errors.email}</p>}\n            </div>\n\n            <div>\n              <button type=\"submit\">Submit</button>\n            </div>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/SubmitComplete/Redirect.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>Form Redirect Test</h1>\n\n      <Form method=\"post\" onSubmitComplete={(form) => form.reset('name')}>\n        {({ errors }) => (\n          <>\n            <div>\n              <input type=\"text\" name=\"name\" id=\"name\" placeholder=\"Name\" defaultValue=\"John Doe\" />\n              {errors.name && <p id=\"error_name\">{errors.name}</p>}\n            </div>\n\n            <div>\n              <button type=\"submit\">Submit</button>\n            </div>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/SubmitComplete/Reset.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>OnSubmitComplete Reset Test</h1>\n\n      <Form method=\"post\" onSubmitComplete={(props) => props.reset('name')}>\n        {({ errors }) => (\n          <>\n            <div>\n              <input type=\"text\" name=\"name\" id=\"name\" placeholder=\"Name\" defaultValue=\"John Doe\" />\n              {errors.name && <p id=\"error_name\">{errors.name}</p>}\n            </div>\n\n            <div>\n              <input type=\"email\" name=\"email\" id=\"email\" placeholder=\"Email\" defaultValue=\"john@doe.biz\" />\n              {errors.email && <p id=\"error_email\">{errors.email}</p>}\n            </div>\n\n            <div>\n              <button type=\"submit\">Submit</button>\n            </div>\n          </>\n        )}\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Transform.tsx",
    "content": "import type { FormDataConvertible } from '@inertiajs/core'\nimport { Form } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const [transformType, setTransformType] = useState('none')\n\n  const getTransform = () => {\n    switch (transformType) {\n      case 'uppercase':\n        return (data: Record<string, FormDataConvertible>) => ({\n          ...data,\n          name: typeof data.name === 'string' ? data.name.toUpperCase() : data.name,\n        })\n      case 'format':\n        return (data: Record<string, FormDataConvertible>) => ({\n          ...data,\n          fullName: `${data.firstName} ${data.lastName}`,\n        })\n      default:\n        return (data: Record<string, FormDataConvertible>) => data\n    }\n  }\n\n  return (\n    <div>\n      <h1>Transform Function</h1>\n\n      <div>\n        <button onClick={() => setTransformType('none')}>None</button>\n        <button onClick={() => setTransformType('uppercase')}>Uppercase</button>\n        <button onClick={() => setTransformType('format')}>Format</button>\n      </div>\n\n      <div>Current transform: {transformType}</div>\n\n      <Form action=\"/dump/post\" method=\"post\" transform={getTransform()}>\n        <div>\n          <input type=\"text\" name=\"name\" placeholder=\"Name\" defaultValue=\"John Doe\" />\n        </div>\n\n        <div>\n          <input type=\"text\" name=\"firstName\" placeholder=\"First Name\" defaultValue=\"John\" />\n        </div>\n\n        <div>\n          <input type=\"text\" name=\"lastName\" placeholder=\"Last Name\" defaultValue=\"Doe\" />\n        </div>\n\n        <div>\n          <button type=\"submit\">Submit with Transform</button>\n        </div>\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/UppercaseMethod.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <h1>Uppercase Method Test</h1>\n\n      {/* Test with uppercase POST */}\n      <Form action=\"/dump/post\" method=\"POST\">\n        <div>\n          <input type=\"text\" name=\"name\" placeholder=\"Name\" defaultValue=\"Test POST\" />\n        </div>\n        <button type=\"submit\">Submit POST</button>\n      </Form>\n\n      {/* Test with uppercase GET */}\n      <Form action=\"/dump/get\" method=\"GET\">\n        <div>\n          <input type=\"text\" name=\"query\" placeholder=\"Query\" defaultValue=\"Test GET\" />\n        </div>\n        <button type=\"submit\">Submit GET</button>\n      </Form>\n\n      {/* Test with uppercase PUT */}\n      <Form action=\"/dump/put\" method=\"PUT\">\n        <div>\n          <input type=\"text\" name=\"data\" placeholder=\"Data\" defaultValue=\"Test PUT\" />\n        </div>\n        <button type=\"submit\">Submit PUT</button>\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/ViewTransition.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <>\n      <Form\n        action=\"/form-component/view-transition\"\n        method=\"post\"\n        options={{\n          viewTransition: (viewTransition) => {\n            viewTransition.ready.then(() => console.log('ready'))\n            viewTransition.updateCallbackDone.then(() => console.log('updateCallbackDone'))\n            viewTransition.finished.then(() => console.log('finished'))\n          },\n        }}\n      >\n        <button type=\"submit\">Submit with View Transition</button>\n      </Form>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormComponent/Wayfinder.tsx",
    "content": "import { Form } from '@inertiajs/react'\n\nexport default () => {\n  const wayfinderUrl = (): {\n    url: string\n    method: 'post'\n  } => ({\n    url: '/dump/post',\n    method: 'post',\n  })\n\n  return (\n    <div>\n      <h1>Wayfinder Example</h1>\n\n      <Form action={wayfinderUrl()}>\n        <div>\n          <input type=\"text\" name=\"name\" placeholder=\"Name\" defaultValue=\"John Doe\" />\n        </div>\n\n        <div>\n          <input type=\"checkbox\" name=\"active\" value=\"true\" defaultChecked />\n          <label>Active</label>\n        </div>\n\n        <div>\n          <button type=\"submit\">Submit</button>\n        </div>\n      </Form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Data.tsx",
    "content": "import { useForm, usePage } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm({\n    name: 'foo',\n    handle: 'example',\n    remember: false,\n  })\n\n  const page = usePage()\n\n  const submit = () => {\n    form.post(page.url)\n  }\n\n  const submitAndReset = () => {\n    form.post('/form-helper/data/redirect-back', {\n      onSuccess: () => form.reset(),\n    })\n  }\n\n  const resetAll = () => {\n    form.reset()\n  }\n\n  const resetOne = () => {\n    form.reset('handle')\n  }\n\n  const reassign = () => {\n    form.setDefaults()\n  }\n\n  const reassignObject = () => {\n    form.setDefaults({ handle: 'updated handle', remember: true })\n  }\n\n  const reassignSingle = () => {\n    form.setDefaults('name', 'single value')\n  }\n\n  return (\n    <div>\n      <label>\n        Full Name\n        <input\n          type=\"text\"\n          id=\"name\"\n          name=\"name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          value={form.data.name}\n        />\n      </label>\n      {form.errors.name && <span className=\"name_error\">{form.errors.name}</span>}\n      <label>\n        Handle\n        <input\n          type=\"text\"\n          id=\"handle\"\n          name=\"handle\"\n          onChange={(e) => form.setData('handle', e.target.value)}\n          value={form.data.handle}\n        />\n      </label>\n      {form.errors.handle && <span className=\"handle_error\">{form.errors.handle}</span>}\n      <label>\n        Remember Me\n        <input\n          type=\"checkbox\"\n          id=\"remember\"\n          name=\"remember\"\n          onChange={(e) => form.setData('remember', e.target.checked)}\n          checked={form.data.remember}\n        />\n      </label>\n      {form.errors.remember && <span className=\"remember_error\">{form.errors.remember}</span>}\n\n      <button onClick={submit} className=\"submit\">\n        Submit form\n      </button>\n\n      <button onClick={submitAndReset} className=\"submit\">\n        Submit form and reset\n      </button>\n\n      <button onClick={resetAll} className=\"reset\">\n        Reset all data\n      </button>\n      <button onClick={resetOne} className=\"reset-one\">\n        Reset one field\n      </button>\n\n      <button onClick={reassign} className=\"reassign\">\n        Reassign current as defaults\n      </button>\n      <button onClick={reassignObject} className=\"reassign-object\">\n        Reassign default values\n      </button>\n      <button onClick={reassignSingle} className=\"reassign-single\">\n        Reassign single default\n      </button>\n\n      <span className=\"errors-status\">Form has {form.hasErrors ? '' : 'no '}errors</span>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Dirty.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm({ name: 'foo', foo: [] as string[] })\n\n  const submit = () => {\n    form.post('')\n  }\n\n  const defaults = () => {\n    form.setDefaults()\n  }\n\n  const dataAndDefaults = () => {\n    pushValue()\n    defaults()\n  }\n\n  const pushValue = () => {\n    form.setData('foo', [...form.data.foo, 'bar'])\n  }\n\n  const submitAndSetDefaults = () => {\n    form.post('/form-helper/dirty/redirect-back', {\n      onSuccess: () => form.setDefaults(),\n    })\n  }\n\n  const submitAndSetCustomDefaults = () => {\n    form.post('/form-helper/dirty/redirect-back', {\n      onSuccess: () => form.setDefaults({ name: 'Custom Default', foo: [] }),\n    })\n  }\n\n  return (\n    <div>\n      <div>Form is {form.isDirty ? 'dirty' : 'clean'}</div>\n      <label>\n        Full Name\n        <input\n          type=\"text\"\n          id=\"name\"\n          name=\"name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          value={form.data.name}\n        />\n      </label>\n\n      <button onClick={submit} className=\"submit\">\n        Submit form\n      </button>\n\n      <button onClick={defaults} className=\"defaults\">\n        Defaults\n      </button>\n\n      <button onClick={dataAndDefaults} className=\"data-and-defaults\">\n        Data and Defaults\n      </button>\n\n      <button onClick={pushValue}>Push Value</button>\n\n      <button onClick={submitAndSetDefaults} className=\"submit-and-set-defaults\">\n        Submit and setDefaults\n      </button>\n\n      <button onClick={submitAndSetCustomDefaults} className=\"submit-and-set-custom-defaults\">\n        Submit and setDefaults custom\n      </button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/EffectCount.tsx",
    "content": "import { useForm } from '@inertiajs/react'\nimport { useEffect, useState } from 'react'\n\nexport default () => {\n  const [count, setCount] = useState(0)\n  const [effectCount, setEffectCount] = useState(0)\n  const { data, setData, setDefaults, reset } = useForm({ count: 0, foo: 'bar' })\n\n  useEffect(() => {\n    setData('count', count)\n    setDefaults()\n    setEffectCount((e) => e + 1)\n  }, [count, setData, setDefaults])\n\n  return (\n    <div>\n      <p id=\"data-count\">Count: {count}</p>\n      <button onClick={() => setCount(count + 1)}>Increment</button>\n      <p id=\"form-data\">Form data: {JSON.stringify(data)}</p>\n      <button onClick={() => reset()}>Reset</button>\n      <p id=\"effect-count\">Effect count: {effectCount}</p>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/EmptyForm.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\ninterface FormData {\n  name: string\n  email: string\n}\n\nexport default () => {\n  const form = useForm<FormData>()\n\n  const submit = () => {\n    form.transform(() => ({\n      name: 'John Doe',\n      email: 'john@example.com',\n    }))\n    form.post('/dump/post')\n  }\n\n  return (\n    <div>\n      <button onClick={submit}>Submit</button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Errors.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm({ name: 'foo', handle: 'example', remember: false })\n\n  const submit = () => {\n    form.post('/form-helper/errors')\n  }\n\n  const clearErrors = () => {\n    form.clearErrors()\n  }\n\n  const clearError = () => {\n    form.clearErrors('handle')\n  }\n\n  const setErrors = () => {\n    form.setError({\n      name: 'Manually set Name error',\n      handle: 'Manually set Handle error',\n    })\n  }\n\n  const setError = () => {\n    form.setError('handle', 'Manually set Handle error')\n  }\n\n  const resetAndClearErrors = () => {\n    form.resetAndClearErrors()\n  }\n\n  const resetHandle = () => {\n    form.resetAndClearErrors('handle')\n  }\n\n  return (\n    <div>\n      <label>\n        Full Name\n        <input\n          type=\"text\"\n          id=\"name\"\n          name=\"name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          value={form.data.name}\n        />\n      </label>\n      {form.errors.name && <span className=\"name_error\">{form.errors.name}</span>}\n      <label>\n        Handle\n        <input\n          type=\"text\"\n          id=\"handle\"\n          name=\"handle\"\n          onChange={(e) => form.setData('handle', e.target.value)}\n          value={form.data.handle}\n        />\n      </label>\n      {form.errors.handle && <span className=\"handle_error\">{form.errors.handle}</span>}\n      <label>\n        Remember Me\n        <input\n          type=\"checkbox\"\n          id=\"remember\"\n          name=\"remember\"\n          onChange={(e) => form.setData('remember', e.target.checked)}\n          checked={form.data.remember}\n        />\n      </label>\n      {form.errors.remember && <span className=\"remember_error\">{form.errors.remember}</span>}\n\n      <button onClick={submit} className=\"submit\">\n        Submit form\n      </button>\n\n      <button onClick={clearErrors} className=\"clear\">\n        Clear all errors\n      </button>\n      <button onClick={clearError} className=\"clear-one\">\n        Clear one error\n      </button>\n      <button onClick={setErrors} className=\"set\">\n        Set errors\n      </button>\n      <button onClick={setError} className=\"set-one\">\n        Set one error\n      </button>\n      <button onClick={resetAndClearErrors} className=\"reset-all\">\n        Reset all\n      </button>\n      <button onClick={resetHandle} className=\"reset-handle\">\n        Reset handle\n      </button>\n\n      <span className=\"errors-status\">Form has {form.hasErrors ? '' : 'no '}errors</span>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/ErrorsClearOnResubmit.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm({\n    name: '',\n    handle: '',\n  })\n\n  return (\n    <div>\n      <label>\n        Name\n        <input\n          type=\"text\"\n          id=\"name\"\n          name=\"name\"\n          value={form.data.name}\n          onChange={(e) => form.setData('name', e.target.value)}\n        />\n      </label>\n      {form.errors.name && <span id=\"name-error\">{form.errors.name}</span>}\n\n      <label>\n        Handle\n        <input\n          type=\"text\"\n          id=\"handle\"\n          name=\"handle\"\n          value={form.data.handle}\n          onChange={(e) => form.setData('handle', e.target.value)}\n        />\n      </label>\n      {form.errors.handle && <span id=\"handle-error\">{form.errors.handle}</span>}\n\n      <button onClick={() => form.post('/form-helper/errors/clear-on-resubmit')} id=\"submit\">\n        Submit\n      </button>\n\n      <span className=\"errors-status\">Form has {form.hasErrors ? '' : 'no '}errors</span>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Events.tsx",
    "content": "import type { Errors, Page, PendingVisit } from '@inertiajs/core'\nimport { useForm, usePage } from '@inertiajs/react'\nimport type { AxiosProgressEvent, CancelTokenSource } from 'axios'\nimport { useEffect } from 'react'\n\ndeclare global {\n  interface Window {\n    events: string[]\n    data: Array<{ type: string; data: unknown; event: string | null }>\n  }\n}\n\nwindow.events = []\nwindow.data = []\n\nconst pushEvent = (message: string) => {\n  window.events.push(message)\n}\n\nconst pushData = (type: string, data: unknown) => {\n  const currentEvent = window.events[window.events.length - 1] ?? null\n\n  window.data.push({\n    type,\n    data,\n    event: currentEvent,\n  })\n}\n\nconst callbacks = (overrides = {}) => ({\n  onBefore: () => pushEvent('onBefore'),\n  onCancelToken: () => pushEvent('onCancelToken'),\n  onStart: () => pushEvent('onStart'),\n  onProgress: () => pushEvent('onProgress'),\n  onFinish: () => pushEvent('onFinish'),\n  onCancel: () => pushEvent('onCancel'),\n  onSuccess: () => pushEvent('onSuccess'),\n  onError: () => pushEvent('onError'),\n  ...overrides,\n})\n\nexport default () => {\n  const form = useForm({ name: 'foo', remember: false })\n\n  const page = usePage()\n\n  useEffect(() => {\n    pushData('processing', form.processing)\n  }, [form.processing])\n\n  useEffect(() => {\n    pushData('progress', form.progress)\n  }, [form.progress])\n\n  useEffect(() => {\n    pushData('errors', form.errors)\n  }, [form.errors])\n\n  useEffect(() => {\n    pushData('hasErrors', form.hasErrors)\n  }, [form.hasErrors])\n\n  const submit = () => {\n    form.post(page.url)\n  }\n\n  const successfulRequest = () => {\n    form.post(page.url, { ...callbacks() })\n  }\n\n  const onSuccessResetErrors = () => {\n    form.post('/form-helper/events/errors', {\n      onError: (errors: Errors) => {\n        pushEvent('onError')\n        form.post('/form-helper/events', {\n          ...callbacks({\n            onStart: () => {\n              pushEvent('onStart')\n              pushData('errors', errors)\n            },\n            onSuccess: () => {\n              pushEvent('onSuccess')\n              pushData('errors', form.errors)\n            },\n            onFinish: () => {\n              pushEvent('onFinish')\n              pushData('errors', form.errors)\n            },\n          }),\n        })\n      },\n    })\n  }\n\n  const errorsSetOnError = () => {\n    form.post('/form-helper/events/errors', callbacks())\n  }\n\n  const onBeforeVisit = () => {\n    form.post('/sleep', {\n      ...callbacks({\n        onBefore: (visit: PendingVisit) => {\n          pushEvent('onBefore')\n          pushData('visit', visit)\n        },\n      }),\n    })\n  }\n\n  const onBeforeVisitCancelled = () => {\n    form.post('/sleep', {\n      ...callbacks({\n        onBefore: () => {\n          pushEvent('onBefore')\n          return false\n        },\n      }),\n    })\n  }\n\n  const onStartVisit = () => {\n    form.post('/form-helper/events', {\n      ...callbacks({\n        onStart: (visit: PendingVisit) => {\n          pushEvent('onStart')\n          pushData('visit', visit)\n        },\n      }),\n    })\n  }\n\n  const onProgressVisit = () => {\n    form.transform((data) => {\n      return { ...data, file: new File(['foobar'], 'example.bin') }\n    })\n\n    form.post('/dump/post', {\n      ...callbacks({\n        onProgress: (event: AxiosProgressEvent) => {\n          pushEvent('onProgress')\n          pushData('progressEvent', event)\n        },\n      }),\n    })\n  }\n\n  const cancelledVisit = () => {\n    form.post('/sleep', {\n      ...callbacks({\n        onCancelToken: (token: CancelTokenSource) => {\n          pushEvent('onCancelToken')\n          setTimeout(() => {\n            pushEvent('CANCELLING!')\n            token.cancel()\n          }, 10)\n        },\n      }),\n    })\n  }\n\n  const onSuccessVisit = () => {\n    form.post('/dump/post', {\n      ...callbacks({\n        onSuccess: (page: Page) => {\n          pushEvent('onSuccess')\n          pushData('page', page)\n        },\n      }),\n    })\n  }\n\n  const onSuccessPromiseVisit = () => {\n    form.post('/dump/post', {\n      ...callbacks({\n        onSuccess: () => {\n          pushEvent('onSuccess')\n          setTimeout(() => pushEvent('onFinish should have been fired by now if Promise functionality did not work'), 5)\n          return new Promise((resolve) => setTimeout(resolve, 20))\n        },\n      }),\n    })\n  }\n\n  const onErrorVisit = () => {\n    form.post('/form-helper/events/errors', {\n      ...callbacks({\n        onError: (errors: Errors) => {\n          pushEvent('onError')\n          pushData('errors', errors)\n        },\n      }),\n    })\n  }\n\n  const onErrorPromiseVisit = () => {\n    form.post('/form-helper/events/errors', {\n      ...callbacks({\n        onError: () => {\n          pushEvent('onError')\n          setTimeout(() => pushEvent('onFinish should have been fired by now if Promise functionality did not work'), 5)\n          return new Promise((resolve) => setTimeout(resolve, 20))\n        },\n      }),\n    })\n  }\n\n  const onSuccessProcessing = () => {\n    form.post(page.url, callbacks())\n  }\n\n  const onSuccessResetValue = () => {\n    form.post(page.url, {\n      ...callbacks({\n        onSuccess: () => {\n          form.reset()\n        },\n      }),\n    })\n  }\n\n  const onErrorProcessing = () => {\n    form.post('/form-helper/events/errors', callbacks())\n  }\n\n  const onSuccessProgress = () => {\n    form.transform((data) => ({ ...data, file: new File(['foo'], 'example.bin') }))\n    form.post('/sleep', callbacks())\n  }\n\n  const onErrorProgress = () => {\n    form.transform((data) => ({\n      ...data,\n      file: new File(['foobar'], 'example.bin'),\n    }))\n    form.post('/form-helper/events/errors', callbacks())\n  }\n\n  const progressNoFiles = () => {\n    form.post(page.url, callbacks())\n  }\n\n  return (\n    <div>\n      <button onClick={submit} className=\"submit\">\n        Submit form\n      </button>\n\n      <button onClick={successfulRequest} className=\"successful-request\">\n        Successful request\n      </button>\n      <button onClick={cancelledVisit} className=\"cancel\">\n        Cancellable Visit\n      </button>\n\n      <button onClick={onBeforeVisit} className=\"before\">\n        onBefore\n      </button>\n      <button onClick={onBeforeVisitCancelled} className=\"before-cancel\">\n        onBefore cancellation\n      </button>\n      <button onClick={onStartVisit} className=\"start\">\n        onStart\n      </button>\n      <button onClick={onProgressVisit} className=\"progress\">\n        onProgress\n      </button>\n\n      <button onClick={onSuccessVisit} className=\"success\">\n        onSuccess\n      </button>\n      <button onClick={onSuccessProgress} className=\"success-progress\">\n        onSuccess progress property\n      </button>\n      <button onClick={onSuccessProcessing} className=\"success-processing\">\n        onSuccess resets processing\n      </button>\n      <button onClick={onSuccessResetErrors} className=\"success-reset-errors\">\n        onSuccess resets errors\n      </button>\n      <button onClick={onSuccessPromiseVisit} className=\"success-promise\">\n        onSuccess promise\n      </button>\n      <button onClick={onSuccessResetValue} className=\"success-reset-value\">\n        onSuccess resets value\n      </button>\n\n      <button onClick={onErrorVisit} className=\"error\">\n        onError\n      </button>\n      <button onClick={onErrorProgress} className=\"error-progress\">\n        onError progress property\n      </button>\n      <button onClick={onErrorProcessing} className=\"error-processing\">\n        onError resets processing\n      </button>\n      <button onClick={errorsSetOnError} className=\"errors-set-on-error\">\n        Errors set on error\n      </button>\n      <button onClick={onErrorPromiseVisit} className=\"error-promise\">\n        onError promise\n      </button>\n\n      <button onClick={progressNoFiles} className=\"no-progress\">\n        progress no files\n      </button>\n\n      <span className=\"success-status\">Form was {form.wasSuccessful ? '' : 'not '}successful</span>\n      <span className=\"recently-status\">Form was {form.recentlySuccessful ? '' : 'not '}recently successful</span>\n\n      <input\n        type=\"text\"\n        className=\"name-input\"\n        value={form.data.name}\n        onChange={(e) => form.setData('name', e.target.value)}\n      />\n      <input\n        type=\"checkbox\"\n        className=\"remember-input\"\n        checked={form.data.remember}\n        onChange={(e) => form.setData('remember', e.target.checked)}\n      />\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Methods.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm({ name: 'foo', remember: false })\n\n  const postForm = () => {\n    form.post('/dump/post')\n  }\n\n  const putForm = () => {\n    form.put('/dump/put')\n  }\n\n  const patchForm = () => {\n    form.patch('/dump/patch')\n  }\n\n  const deleteForm = () => {\n    form.delete('/dump/delete')\n  }\n\n  const submitForm = () => {\n    form.submit('post', '/dump/post')\n  }\n\n  const submitFormObject = () => {\n    form.submit({\n      url: '/dump/post',\n      method: 'post',\n    })\n  }\n\n  return (\n    <div>\n      <label>\n        Full Name\n        <input\n          type=\"text\"\n          id=\"name\"\n          name=\"name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          value={form.data.name}\n        />\n      </label>\n      <label>\n        Remember Me\n        <input\n          type=\"checkbox\"\n          id=\"remember\"\n          name=\"remember\"\n          onChange={(e) => form.setData('remember', e.target.checked)}\n          checked={form.data.remember}\n        />\n      </label>\n\n      <button onClick={postForm} className=\"post\">\n        POST form\n      </button>\n      <button onClick={putForm} className=\"put\">\n        PUT form\n      </button>\n      <button onClick={patchForm} className=\"patch\">\n        PATCH form\n      </button>\n      <button onClick={deleteForm} className=\"delete\">\n        DELETE form\n      </button>\n      <button onClick={submitForm} className=\"submit\">\n        SUBMIT form\n      </button>\n      <button onClick={submitFormObject} className=\"submit-object\">\n        SUBMIT OBJECT form\n      </button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Nested.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm({\n    name: 'foo',\n    address: {\n      street: '123 Main St',\n      city: 'New York',\n    },\n    organization: {\n      name: 'Inertia',\n      repo: {\n        name: 'inertiajs/inertia',\n        tags: ['v0.1', 'v0.2'],\n      },\n    },\n    checked: ['foo', 'bar'],\n  })\n\n  const submit = () => {\n    form.submit('post', '/dump/post')\n  }\n\n  return (\n    <div>\n      <label>\n        Full Name\n        <input\n          type=\"text\"\n          id=\"name\"\n          name=\"name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          value={form.data.name}\n        />\n      </label>\n      <label>\n        Street\n        <input\n          type=\"text\"\n          id=\"street\"\n          name=\"address.street\"\n          onChange={(e) => form.setData('address.street', e.target.value)}\n          value={form.data.address.street}\n        />\n      </label>\n      <label>\n        City\n        <input\n          type=\"text\"\n          id=\"city\"\n          name=\"address.city\"\n          onChange={(e) => form.setData('address.city', e.target.value)}\n          value={form.data.address.city}\n        />\n      </label>\n      <label>\n        Foo\n        <input\n          type=\"checkbox\"\n          id=\"foo\"\n          name=\"checked[]\"\n          value=\"foo\"\n          onChange={(e) =>\n            form.setData(\n              'checked',\n              e.target.checked\n                ? [...form.data.checked, e.target.value]\n                : form.data.checked.filter((item) => item !== e.target.value),\n            )\n          }\n          checked={form.data.checked.includes('foo')}\n        />\n      </label>\n      <label>\n        Bar\n        <input\n          type=\"checkbox\"\n          id=\"bar\"\n          name=\"checked[]\"\n          value=\"bar\"\n          onChange={(e) =>\n            form.setData(\n              'checked',\n              e.target.checked\n                ? [...form.data.checked, e.target.value]\n                : form.data.checked.filter((item) => item !== e.target.value),\n            )\n          }\n          checked={form.data.checked.includes('bar')}\n        />\n      </label>\n      <label>\n        Baz\n        <input\n          type=\"checkbox\"\n          id=\"baz\"\n          name=\"checked[]\"\n          value=\"baz\"\n          onChange={(e) =>\n            form.setData(\n              'checked',\n              e.target.checked\n                ? [...form.data.checked, e.target.value]\n                : form.data.checked.filter((item) => item !== e.target.value),\n            )\n          }\n          checked={form.data.checked.includes('baz')}\n        />\n      </label>\n      <label>\n        Organization Name\n        <input\n          type=\"text\"\n          id=\"organization-name\"\n          name=\"organization.name\"\n          onChange={(e) => form.setData('organization.name', e.target.value)}\n          value={form.data.organization.name}\n        />\n      </label>\n      <label>\n        Repository Name\n        <input\n          type=\"text\"\n          id=\"repo-name\"\n          name=\"organization.repo.name\"\n          onChange={(e) => form.setData('organization.repo.name', e.target.value)}\n          value={form.data.organization.repo.name}\n        />\n      </label>\n      Repository Tags\n      <label>\n        v0.1\n        <input\n          type=\"checkbox\"\n          id=\"tag-0\"\n          name=\"organization.repo.tags[]\"\n          value=\"v0.1\"\n          onChange={(e) =>\n            form.setData(\n              'organization.repo.tags',\n              e.target.checked\n                ? [...form.data.organization.repo.tags, e.target.value]\n                : form.data.organization.repo.tags.filter((item) => item !== e.target.value),\n            )\n          }\n          checked={form.data.organization.repo.tags.includes('v0.1')}\n        />\n      </label>\n      <label>\n        v0.2\n        <input\n          type=\"checkbox\"\n          id=\"tag-1\"\n          name=\"organization.repo.tags[]\"\n          value=\"v0.2\"\n          onChange={(e) =>\n            form.setData(\n              'organization.repo.tags',\n              e.target.checked\n                ? [...form.data.organization.repo.tags, e.target.value]\n                : form.data.organization.repo.tags.filter((item) => item !== e.target.value),\n            )\n          }\n          checked={form.data.organization.repo.tags.includes('v0.2')}\n        />\n      </label>\n      <label>\n        v0.3\n        <input\n          type=\"checkbox\"\n          id=\"tag-2\"\n          name=\"organization.repo.tags[]\"\n          value=\"v0.3\"\n          onChange={(e) =>\n            form.setData(\n              'organization.repo.tags',\n              e.target.checked\n                ? [...form.data.organization.repo.tags, e.target.value]\n                : form.data.organization.repo.tags.filter((item) => item !== e.target.value),\n            )\n          }\n          checked={form.data.organization.repo.tags.includes('v0.3')}\n        />\n      </label>\n      <button onClick={submit} className=\"submit\">\n        Submit form\n      </button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Precognition/BeforeValidation.tsx",
    "content": "import { useForm } from '@inertiajs/react'\nimport { isEqual } from 'lodash-es'\n\nexport default () => {\n  const form = useForm({\n    name: '',\n    email: '',\n  })\n    .withPrecognition('post', '/precognition/default')\n    .setValidationTimeout(100)\n\n  const handleBeforeValidation = (\n    newRequest: { data: Record<string, unknown> | null; touched: string[] },\n    oldRequest: { data: Record<string, unknown> | null; touched: string[] },\n  ) => {\n    const payloadIsCorrect =\n      isEqual(newRequest, { data: { name: 'block' }, touched: ['name'] }) &&\n      isEqual(oldRequest, { data: {}, touched: [] })\n\n    if (payloadIsCorrect && newRequest.data?.name === 'block') {\n      return false\n    }\n\n    return true\n  }\n\n  return (\n    <div>\n      <div>\n        <input\n          value={form.data.name}\n          name=\"name\"\n          placeholder=\"Name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          onBlur={() =>\n            form.validate('name', {\n              onBeforeValidation: handleBeforeValidation,\n            })\n          }\n        />\n        {form.invalid('name') && <p>{form.errors.name}</p>}\n        {form.valid('name') && <p>Name is valid!</p>}\n      </div>\n\n      <div>\n        <input\n          value={form.data.email}\n          name=\"email\"\n          placeholder=\"Email\"\n          onChange={(e) => form.setData('email', e.target.value)}\n          onBlur={() => form.validate('email')}\n        />\n        {form.invalid('email') && <p>{form.errors.email}</p>}\n        {form.valid('email') && <p>Email is valid!</p>}\n      </div>\n\n      {form.validating && <p>Validating...</p>}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Precognition/Callbacks.tsx",
    "content": "import { useForm } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const form = useForm({\n    name: '',\n    email: '',\n  })\n    .withPrecognition('post', '/precognition/default')\n    .setValidationTimeout(100)\n\n  const [successCalled, setSuccessCalled] = useState(false)\n  const [errorCalled, setErrorCalled] = useState(false)\n  const [finishCalled, setFinishCalled] = useState(false)\n\n  const handleValidate = () => {\n    setSuccessCalled(false)\n    setErrorCalled(false)\n    setFinishCalled(false)\n    form.validate({\n      onPrecognitionSuccess: () => {\n        setSuccessCalled(true)\n      },\n      onValidationError: () => {\n        setErrorCalled(true)\n      },\n      onFinish: () => {\n        setFinishCalled(true)\n      },\n    })\n  }\n\n  return (\n    <div>\n      <div>\n        <input\n          value={form.data.name}\n          name=\"name\"\n          placeholder=\"Name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          onBlur={() => form.touch('name')}\n        />\n        {form.invalid('name') && <p>{form.errors.name}</p>}\n        {form.valid('name') && <p>Name is valid!</p>}\n      </div>\n\n      {form.validating && <p>Validating...</p>}\n      {successCalled && <p>onPrecognitionSuccess called!</p>}\n      {errorCalled && <p>onValidationError called!</p>}\n      {finishCalled && <p>onFinish called!</p>}\n\n      <button type=\"button\" onClick={handleValidate}>\n        Validate\n      </button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Precognition/Cancel.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm({\n    name: '',\n  })\n    .withPrecognition('post', '/precognition/default?slow=1')\n    .setValidationTimeout(100)\n\n  return (\n    <div>\n      <div>\n        <input\n          id=\"auto-cancel-name-input\"\n          value={form.data.name}\n          name=\"name\"\n          placeholder=\"Name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          onBlur={() => form.validate('name')}\n        />\n        {form.invalid('name') && <p>{form.errors.name}</p>}\n        {form.valid('name') && <p>Name is valid!</p>}\n      </div>\n\n      {form.validating && <p>Validating...</p>}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Precognition/Compatibility.tsx",
    "content": "import { useForm } from '@inertiajs/react'\nimport { NamedInputEvent } from 'laravel-precognition'\n\nexport default () => {\n  const form = useForm({\n    name: '',\n    email: '',\n    company: '',\n  })\n    .withPrecognition('post', '/precognition/default')\n    .setValidationTimeout(100)\n\n  return (\n    <div>\n      <h1>Compatibility Test Page</h1>\n\n      <div>\n        <input\n          value={form.data.name}\n          name=\"name\"\n          placeholder=\"Name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          onBlur={() => form.validate('name')}\n        />\n        {form.invalid('name') && <p id=\"name-error\">{form.errors.name}</p>}\n        {form.valid('name') && <p id=\"name-valid\">Name is valid!</p>}\n      </div>\n\n      <div>\n        <input\n          value={form.data.email}\n          name=\"email\"\n          placeholder=\"Email\"\n          onChange={(e) => form.setData('email', e.target.value)}\n          onBlur={() => form.validate('email')}\n        />\n        {form.invalid('email') && <p id=\"email-error\">{form.errors.email}</p>}\n        {form.valid('email') && <p id=\"email-valid\">Email is valid!</p>}\n      </div>\n\n      <div>\n        <input\n          value={form.data.company}\n          name=\"company\"\n          placeholder=\"Company\"\n          onFocus={(e) => {\n            const event = e as any as NamedInputEvent // eslint-disable-line @typescript-eslint/no-explicit-any\n            form.forgetError(event)\n            form.touch(event)\n          }}\n          onChange={(e) => form.setData('company', e.target.value)}\n          onBlur={() => form.validate('company')}\n        />\n        {form.invalid('company') && <p id=\"company-error\">{form.errors.company}</p>}\n        {form.valid('company') && <p id=\"company-valid\">company is valid!</p>}\n      </div>\n\n      {form.validating && <p id=\"validating\">Validating...</p>}\n\n      {/* Test compatibility methods */}\n      <div style={{ marginTop: '20px' }}>\n        <button\n          type=\"button\"\n          id=\"test-setErrors\"\n          onClick={() =>\n            form.setErrors({ name: 'setErrors test', email: 'setErrors email test', company: 'setErrors company test' })\n          }\n        >\n          Test setErrors()\n        </button>\n\n        <button type=\"button\" id=\"test-forgetError\" onClick={() => form.forgetError('name')}>\n          Test forgetError()\n        </button>\n\n        <button type=\"button\" id=\"test-touch-array\" onClick={() => form.touch(['name', 'email'])}>\n          Test touch([])\n        </button>\n\n        <button type=\"button\" id=\"test-touch-spread\" onClick={() => form.touch('name', 'email')}>\n          Test touch(...args)\n        </button>\n      </div>\n\n      <div style={{ marginTop: '20px' }}>\n        <p id=\"touched-name\">Name touched: {form.touched('name') ? 'yes' : 'no'}</p>\n        <p id=\"touched-email\">Email touched: {form.touched('email') ? 'yes' : 'no'}</p>\n        <p id=\"touched-company\">Company touched: {form.touched('company') ? 'yes' : 'no'}</p>\n        <p id=\"touched-any\">Any touched: {form.touched() ? 'yes' : 'no'}</p>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Precognition/Default.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm({\n    name: '',\n    email: '',\n  })\n    .withPrecognition('post', '/precognition/default')\n    .setValidationTimeout(100)\n\n  return (\n    <div>\n      <div>\n        <input\n          value={form.data.name}\n          name=\"name\"\n          placeholder=\"Name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          onBlur={() => form.validate('name')}\n        />\n        {form.invalid('name') && <p>{form.errors.name}</p>}\n        {form.valid('name') && <p>Name is valid!</p>}\n      </div>\n\n      <div>\n        <input\n          value={form.data.email}\n          name=\"email\"\n          placeholder=\"Email\"\n          onChange={(e) => form.setData('email', e.target.value)}\n          onBlur={() => form.validate('email')}\n        />\n        {form.invalid('email') && <p>{form.errors.email}</p>}\n        {form.valid('email') && <p>Email is valid!</p>}\n      </div>\n\n      {form.validating && <p>Validating...</p>}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Precognition/DynamicArrayInputs.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm({\n    items: [] as Array<{ name: string }>,\n  })\n    .withPrecognition('post', '/precognition/dynamic-array-inputs')\n    .setValidationTimeout(100)\n\n  function addItem() {\n    form.setData('items', [...form.data.items, { name: '' }])\n  }\n\n  function updateItem(index: number, value: string) {\n    const items = [...form.data.items]\n    items[index] = { name: value }\n    form.setData('items', items)\n  }\n\n  return (\n    <div>\n      <button id=\"add-item\" onClick={addItem}>\n        Add Item\n      </button>\n\n      {form.data.items.map((item, idx) => (\n        <div key={idx}>\n          <input\n            value={item.name}\n            name={`items.${idx}.name`}\n            onChange={(e) => updateItem(idx, e.target.value)}\n            onBlur={() => form.validate(`items.${idx}.name`)}\n          />\n          {form.invalid(`items.${idx}.name`) && (\n            <p id={`items.${idx}.name-error`}>{form.errors[`items.${idx}.name`]}</p>\n          )}\n          {form.valid(`items.${idx}.name`) && <p>Valid!</p>}\n        </div>\n      ))}\n\n      {form.validating && <p>Validating...</p>}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Precognition/ErrorSync.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm({\n    name: '',\n    email: '',\n  })\n    .withPrecognition('post', '/precognition/error-sync')\n    .setValidationTimeout(100)\n\n  const handleSubmit = (e: React.FormEvent) => {\n    e.preventDefault()\n    form.submit()\n  }\n\n  return (\n    <div>\n      <h1>Precognition Error Sync Test (Form Helper)</h1>\n\n      <form onSubmit={handleSubmit}>\n        <div>\n          <input\n            value={form.data.name}\n            name=\"name\"\n            placeholder=\"Name\"\n            onChange={(e) => form.setData('name', e.target.value)}\n            onBlur={() => form.validate('name')}\n          />\n          {form.invalid('name') && <p id=\"name-error\">{form.errors.name}</p>}\n        </div>\n\n        <div>\n          <input\n            value={form.data.email}\n            name=\"email\"\n            placeholder=\"Email\"\n            onChange={(e) => form.setData('email', e.target.value)}\n            onBlur={() => form.validate('email')}\n          />\n          {form.invalid('email') && <p id=\"email-error\">{form.errors.email}</p>}\n        </div>\n\n        {form.validating && <p id=\"validating\">Validating...</p>}\n\n        <button type=\"submit\" id=\"submit-btn\">\n          Submit\n        </button>\n      </form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Precognition/Files.tsx",
    "content": "import { useForm } from '@inertiajs/react'\nimport { useEffect, useState } from 'react'\n\nexport default () => {\n  const form = useForm<{\n    name: string\n    avatar: File | null\n  }>({\n    name: '',\n    avatar: null,\n  })\n    .withPrecognition('post', '/precognition/files')\n    .setValidationTimeout(100)\n\n  const [validateFiles, setValidateFiles] = useState(false)\n\n  useEffect(() => {\n    if (validateFiles) {\n      form.validateFiles()\n    } else {\n      form.withoutFileValidation()\n    }\n  }, [form, validateFiles])\n\n  const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n    const file = e.target.files?.[0] || null\n    form.setData('avatar', file)\n  }\n\n  return (\n    <div>\n      <div>\n        <input\n          value={form.data.name}\n          name=\"name\"\n          placeholder=\"Name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          onBlur={() => form.validate('name')}\n        />\n        {form.invalid('name') && <p>{form.errors.name}</p>}\n        {form.valid('name') && <p>Name is valid!</p>}\n      </div>\n\n      <div>\n        <input type=\"file\" name=\"avatar\" id=\"avatar\" onChange={handleFileChange} />\n        {form.invalid('avatar') && <p>{form.errors.avatar}</p>}\n        {form.valid('avatar') && <p>Avatar is valid!</p>}\n      </div>\n\n      {form.validating && <p>Validating...</p>}\n\n      <button type=\"button\" onClick={() => setValidateFiles(!validateFiles)}>\n        Toggle Validate Files ({validateFiles ? 'enabled' : 'disabled'})\n      </button>\n\n      <button type=\"button\" onClick={() => form.validate({ only: ['name', 'avatar'] })}>\n        Validate Both\n      </button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Precognition/Headers.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm({\n    name: '',\n  })\n    .withPrecognition('post', '/precognition/headers')\n    .setValidationTimeout(100)\n\n  return (\n    <div>\n      <div>\n        <input\n          value={form.data.name}\n          name=\"name\"\n          placeholder=\"Name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          onBlur={() =>\n            form.validate('name', {\n              headers: { 'X-Custom-Header': 'custom-value' },\n            })\n          }\n        />\n        {form.invalid('name') && <p>{form.errors.name}</p>}\n        {form.valid('name') && <p>Name is valid!</p>}\n      </div>\n\n      {form.validating && <p>Validating...</p>}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Precognition/Instantiate.tsx",
    "content": "import { Method, UrlMethodPair } from '@inertiajs/core'\nimport { useForm } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const wayfinderUrl = (): UrlMethodPair => ({\n    url: '/precognition/default',\n    method: 'post',\n  })\n\n  const [form, setForm] = useState<keyof typeof forms>('default')\n  const data = () => ({ name: 'a' })\n\n  const forms = {\n    // Forms that use the new withPrecognition() method\n    default: useForm(data()).withPrecognition('post', '/precognition/default'),\n    dynamic: useForm(data()).withPrecognition(\n      () => 'post',\n      () => '/precognition/default',\n    ),\n    wayfinder: useForm(data()).withPrecognition(wayfinderUrl()),\n    dynamicWayfinder: useForm(data()).withPrecognition(() => wayfinderUrl()),\n\n    // Forms that use the original useForm() parameters from the 0.x Precognition implementation\n    legacy: useForm('post', '/precognition/default', data()),\n    legacyDynamic: useForm(\n      () => 'post' as Method,\n      () => '/precognition/default',\n      data(),\n    ),\n    legacyWayfinder: useForm(wayfinderUrl(), data()),\n    legacyDynamicWayfinder: useForm(() => wayfinderUrl(), data()),\n  }\n\n  const validateForm = (formName: keyof typeof forms) => {\n    forms[formName].touch('name')\n    forms[formName].validate()\n  }\n\n  const submitWithoutArgs = (formName: keyof typeof forms) => {\n    forms[formName].submit()\n  }\n\n  const submitWithArgs = (formName: keyof typeof forms) => {\n    forms[formName].submit('patch', '/dump/patch')\n  }\n\n  const submitWithMethod = (formName: keyof typeof forms) => {\n    forms[formName].put('/dump/put')\n  }\n\n  const submitWithWayfinder = (formName: keyof typeof forms) => {\n    forms[formName].submit({ url: '/dump/post', method: 'post' })\n  }\n\n  return (\n    <div>\n      <select value={form} onChange={(e) => setForm(e.target.value as keyof typeof forms)}>\n        <option value=\"default\">withPrecognition()</option>\n        <option value=\"dynamic\">withPrecognition() dynamic</option>\n        <option value=\"wayfinder\">withPrecognition() Wayfinder</option>\n        <option value=\"dynamicWayfinder\">withPrecognition() dynamic Wayfinder</option>\n        <option value=\"legacy\">useForm() legacy</option>\n        <option value=\"legacyDynamic\">useForm() legacy dynamic</option>\n        <option value=\"legacyWayfinder\">useForm() legacy Wayfinder</option>\n        <option value=\"legacyDynamicWayfinder\">useForm() legacy dynamic Wayfinder</option>\n      </select>\n\n      <button onClick={() => validateForm(form)}>Validate</button>\n      <button onClick={() => submitWithoutArgs(form)}>Submit without args</button>\n      <button onClick={() => submitWithArgs(form)}>Submit with args</button>\n      <button onClick={() => submitWithMethod(form)}>Submit with method</button>\n      <button onClick={() => submitWithWayfinder(form)}>Submit with Wayfinder</button>\n\n      {forms[form].validating && <p>Validating...</p>}\n      {forms[form].errors.name && <p>{forms[form].errors.name}</p>}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Precognition/Methods.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm({\n    name: '',\n    email: '',\n  })\n    .withPrecognition('post', '/precognition/default')\n    .setValidationTimeout(100)\n\n  return (\n    <div>\n      <div>\n        <input\n          name=\"name\"\n          value={form.data.name}\n          placeholder=\"Name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          onBlur={() => form.touch('name')}\n        />\n        {form.invalid('name') && <p>{form.errors.name}</p>}\n      </div>\n\n      <div>\n        <input\n          name=\"email\"\n          value={form.data.email}\n          placeholder=\"Email\"\n          onChange={(e) => form.setData('email', e.target.value)}\n          onBlur={() => form.touch('email')}\n        />\n        {form.invalid('email') && <p>{form.errors.email}</p>}\n      </div>\n\n      {form.validating && <p>Validating...</p>}\n\n      <p id=\"name-touched\">{form.touched('name') ? 'Name is touched' : 'Name is not touched'}</p>\n      <p id=\"email-touched\">{form.touched('email') ? 'Email is touched' : 'Email is not touched'}</p>\n      <p id=\"any-touched\">{form.touched() ? 'Form has touched fields' : 'Form has no touched fields'}</p>\n\n      <button type=\"button\" onClick={() => form.validate()}>\n        Validate All Touched\n      </button>\n      <button type=\"button\" onClick={() => form.validate('name')}>\n        Validate Name\n      </button>\n      <button type=\"button\" onClick={() => form.validate({ only: ['name', 'email'] })}>\n        Validate Name and Email\n      </button>\n      <button type=\"button\" onClick={() => form.touch('name', 'email')}>\n        Touch Name and Email\n      </button>\n      <button\n        type=\"button\"\n        onClick={() => {\n          form.touch('name')\n          form.touch('name')\n        }}\n      >\n        Touch Name Twice\n      </button>\n      <button type=\"button\" onClick={() => form.reset()}>\n        Reset All\n      </button>\n      <button type=\"button\" onClick={() => form.reset('name')}>\n        Reset Name\n      </button>\n      <button type=\"button\" onClick={() => form.reset('name', 'email')}>\n        Reset Name and Email\n      </button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Precognition/Transform.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm({\n    name: '',\n  })\n    .withPrecognition('post', '/precognition/default')\n    .setValidationTimeout(100)\n\n  form.transform((data) => ({ name: String(data.name || '').repeat(2) }))\n\n  return (\n    <div>\n      <div>\n        <input\n          value={form.data.name}\n          name=\"name\"\n          placeholder=\"Name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          onBlur={() => form.validate('name')}\n        />\n        {form.invalid('name') && <p>{form.errors.name}</p>}\n        {form.valid('name') && <p>Name is valid!</p>}\n      </div>\n\n      {form.validating && <p>Validating...</p>}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Precognition/TransformKeys.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\nexport default () => {\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  const form: any = useForm({\n    document: {\n      customer: { email: '' },\n    },\n  })\n    .withPrecognition('post', '/precognition/transform-keys')\n    .setValidationTimeout(100)\n\n  form.transform((data: { document: { customer: { email: string } } }) => ({ ...data.document }))\n\n  return (\n    <div>\n      <div>\n        <input\n          id=\"email-input\"\n          value={form.data.document.customer.email}\n          name=\"customer.email\"\n          placeholder=\"Email\"\n          onChange={(e: React.ChangeEvent<HTMLInputElement>) => form.setData('document.customer.email', e.target.value)}\n          onBlur={() => form.validate('customer.email')}\n        />\n        {form.invalid('customer.email') && <p>{form.errors['customer.email']}</p>}\n        {form.valid('customer.email') && <p>Email is valid!</p>}\n      </div>\n\n      {form.validating && <p>Validating...</p>}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Precognition/WithAllErrors.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm({\n    name: '',\n    email: '',\n  })\n    .withPrecognition('post', '/precognition/with-all-errors')\n    .setValidationTimeout(100)\n    .withAllErrors()\n\n  return (\n    <div>\n      <div>\n        <input\n          value={form.data.name}\n          name=\"name\"\n          placeholder=\"Name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          onBlur={() => form.validate('name')}\n        />\n        {form.invalid('name') && (\n          <div>\n            {Array.isArray(form.errors.name) ? (\n              form.errors.name.map((error, index) => (\n                <p key={index} id={`name-error-${index}`}>\n                  {error}\n                </p>\n              ))\n            ) : (\n              <p id=\"name-error-0\">{form.errors.name}</p>\n            )}\n          </div>\n        )}\n        {form.valid('name') && <p>Name is valid!</p>}\n      </div>\n\n      <div>\n        <input\n          value={form.data.email}\n          name=\"email\"\n          placeholder=\"Email\"\n          onChange={(e) => form.setData('email', e.target.value)}\n          onBlur={() => form.validate('email')}\n        />\n        {form.invalid('email') && (\n          <div>\n            {Array.isArray(form.errors.email) ? (\n              form.errors.email.map((error, index) => (\n                <p key={index} id={`email-error-${index}`}>\n                  {error}\n                </p>\n              ))\n            ) : (\n              <p id=\"email-error-0\">{form.errors.email}</p>\n            )}\n          </div>\n        )}\n        {form.valid('email') && <p>Email is valid!</p>}\n      </div>\n\n      {form.validating && <p>Validating...</p>}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Precognition/WithAllErrorsConfig.tsx",
    "content": "import { config, useForm } from '@inertiajs/react'\n\nexport default () => {\n  // Set global config for withAllErrors (no .withAllErrors() call on the form)\n  config.set('form.withAllErrors', true)\n\n  const form = useForm({\n    name: '',\n    email: '',\n  })\n    .withPrecognition('post', '/precognition/with-all-errors')\n    .setValidationTimeout(100)\n\n  return (\n    <div>\n      <div>\n        <input\n          value={form.data.name}\n          name=\"name\"\n          placeholder=\"Name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          onBlur={() => form.validate('name')}\n        />\n        {form.invalid('name') && (\n          <div>\n            {Array.isArray(form.errors.name) ? (\n              form.errors.name.map((error, index) => (\n                <p key={index} id={`name-error-${index}`}>\n                  {error}\n                </p>\n              ))\n            ) : (\n              <p id=\"name-error-0\">{form.errors.name}</p>\n            )}\n          </div>\n        )}\n        {form.valid('name') && <p>Name is valid!</p>}\n      </div>\n\n      <div>\n        <input\n          value={form.data.email}\n          name=\"email\"\n          placeholder=\"Email\"\n          onChange={(e) => form.setData('email', e.target.value)}\n          onBlur={() => form.validate('email')}\n        />\n        {form.invalid('email') && (\n          <div>\n            {Array.isArray(form.errors.email) ? (\n              form.errors.email.map((error, index) => (\n                <p key={index} id={`email-error-${index}`}>\n                  {error}\n                </p>\n              ))\n            ) : (\n              <p id=\"email-error-0\">{form.errors.email}</p>\n            )}\n          </div>\n        )}\n        {form.valid('email') && <p>Email is valid!</p>}\n      </div>\n\n      {form.validating && <p>Validating...</p>}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Precognition/WithoutAllErrors.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm({\n    name: '',\n    email: '',\n  })\n    .withPrecognition('post', '/precognition/with-all-errors')\n    .setValidationTimeout(100)\n\n  return (\n    <div>\n      <div>\n        <input\n          value={form.data.name}\n          name=\"name\"\n          placeholder=\"Name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          onBlur={() => form.validate('name')}\n        />\n        {form.invalid('name') && <p>{form.errors.name}</p>}\n        {form.valid('name') && <p>Name is valid!</p>}\n      </div>\n\n      <div>\n        <input\n          value={form.data.email}\n          name=\"email\"\n          placeholder=\"Email\"\n          onChange={(e) => form.setData('email', e.target.value)}\n          onBlur={() => form.validate('email')}\n        />\n        {form.invalid('email') && <p>{form.errors.email}</p>}\n        {form.valid('email') && <p>Email is valid!</p>}\n      </div>\n\n      {form.validating && <p>Validating...</p>}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/RememberEdit.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\ninterface User {\n  id: number\n  name: string\n  email: string\n}\n\nexport default ({ user }: { user: User }) => {\n  const form = useForm('EditUserForm', {\n    name: user.name,\n    email: user.email,\n  })\n\n  return (\n    <div>\n      <h1>Edit User {user.id}</h1>\n      <form>\n        <div>\n          <label>Name:</label>\n          <input type=\"text\" value={form.data.name} onChange={(e) => form.setData('name', e.target.value)} />\n        </div>\n        <div>\n          <label>Email:</label>\n          <input type=\"email\" value={form.data.email} onChange={(e) => form.setData('email', e.target.value)} />\n        </div>\n      </form>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/RememberIndex.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\ninterface User {\n  id: number\n  name: string\n  email: string\n}\n\nexport default ({ users }: { users: User[] }) => {\n  return (\n    <div>\n      <h1>Users Index</h1>\n      <ul>\n        {users.map((user) => (\n          <li key={user.id}>\n            <Link href={`/remember/users/${user.id}/edit`}>Edit {user.name}</Link>\n          </li>\n        ))}\n      </ul>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/Transform.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm({ name: 'foo', remember: false })\n\n  const postForm = () => {\n    form.transform((data) => ({ ...data, name: 'bar' }))\n    form.post('/dump/post')\n  }\n\n  const putForm = () => {\n    form.transform((data) => ({ ...data, name: 'baz' }))\n    form.put('/dump/put')\n  }\n\n  const patchForm = () => {\n    form.transform((data) => ({ ...data, name: 'foo' }))\n    form.patch('/dump/patch')\n  }\n\n  const deleteForm = () => {\n    form.transform((data) => ({ ...data, name: 'bar' }))\n    form.delete('/dump/delete')\n  }\n\n  return (\n    <div>\n      <label>\n        Full Name\n        <input\n          type=\"text\"\n          id=\"name\"\n          name=\"name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          value={form.data.name}\n        />\n      </label>\n      <label>\n        Remember Me\n        <input\n          type=\"checkbox\"\n          id=\"remember\"\n          name=\"remember\"\n          onChange={(e) => form.setData('remember', e.target.checked)}\n          checked={form.data.remember}\n        />\n      </label>\n\n      <button onClick={postForm} className=\"post\">\n        POST form\n      </button>\n      <button onClick={putForm} className=\"put\">\n        PUT form\n      </button>\n      <button onClick={patchForm} className=\"patch\">\n        PATCH form\n      </button>\n      <button onClick={deleteForm} className=\"delete\">\n        DELETE form\n      </button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/TypeScript/Any.tsx",
    "content": "// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/react'\n\nexport default function Any() {\n  const form = useForm<{ name: any }>({ name: null }) // eslint-disable-line @typescript-eslint/no-explicit-any\n\n  form.setData('name', 0)\n  form.setData('name', 'test')\n  form.setData('name', true)\n  form.setData('name', null)\n  form.setData('name', {\n    key: 'value',\n  })\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/TypeScript/Child.tsx",
    "content": "// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport type { InertiaFormProps } from '@inertiajs/react'\n\ninterface ChildProps {\n  form: InertiaFormProps<{\n    name: string\n    email?: string\n  }>\n}\n\nexport default function Child({ form }: ChildProps) {\n  return (\n    <div>\n      <p>Name: {form.data.name}</p>\n      <p>Email: {form.data.email}</p>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/TypeScript/CircularlReferences.tsx",
    "content": "// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/react'\n\ntype SubData = {\n  foo: string\n  items?: SubData[]\n}\n\ntype Data = {\n  items: SubData[]\n}\n\nexport default function Any() {\n  const form = useForm<Data>({\n    items: [],\n  })\n\n  form.setData('items', [])\n  form.setData('items', [\n    {\n      foo: 'bar',\n      items: [\n        {\n          foo: 'baz',\n          items: [\n            {\n              foo: 'qux',\n            },\n          ],\n        },\n      ],\n    },\n  ])\n\n  // @ts-expect-error - items should be an array of SubData\n  form.setData('items', {})\n  // @ts-expect-error - foo should be a string\n  form.setData('items', [{ foo: 123 }])\n  // @ts-expect-error - items should be an array of SubData\n  form.setData('items', [{ foo: 'bar', items: {} }])\n  // @ts-expect-error - foo should be a string\n  form.setData('items', [{ foo: 'bar', items: [{ foo: 123 }] }])\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/TypeScript/Data.tsx",
    "content": "// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/react'\n\ntype FormData = {\n  name: string\n  company: { name: string }\n  users: { name: string }[]\n}\n\nconst defaultData = {\n  name: '',\n  company: { name: '' },\n  users: [],\n}\n\nexport default function Data() {\n  const form = useForm<FormData>(defaultData)\n  form.data.name = 'John Doe'\n  form.data.company.name = 'Acme Corp'\n  form.data.users = [{ name: 'Jane Doe' }]\n  // @ts-expect-error - A form has no email field\n  form.data.email = 'john@example.com'\n  // @ts-expect-error - A company has no street field\n  form.data.company.street = '123 Main St'\n  // @ts-expect-error - A company has no street field\n  form.data.company = { name: 'Acme Corp', street: '123 Main St' }\n  // @ts-expect-error - A form has no email field\n  form.data.users = [{ name: 'Jane Doe', email: 'jane@example.com' }]\n\n  return null\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/TypeScript/DynamicInputName.tsx",
    "content": "// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/react'\n\ninterface ClientForm {\n  name: string\n  [key: string]: any // eslint-disable-line @typescript-eslint/no-explicit-any\n}\n\nexport default function DynamicInputName() {\n  const { data, setData } = useForm<ClientForm>({\n    name: '',\n  })\n\n  const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {\n    const { name, value } = e.target as HTMLInputElement\n    setData(name, value)\n  }\n\n  return <input name=\"name\" type=\"text\" value={data.name} onChange={handleChange} />\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/TypeScript/Errors.tsx",
    "content": "// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/react'\n\ntype FormData = {\n  name: string\n  company: { name: string }\n  users: { name: string }[]\n}\n\nconst defaultData = {\n  name: '',\n  company: { name: '' },\n  users: [],\n}\n\nexport default function Errors() {\n  const form = useForm<FormData>(defaultData)\n\n  // Get Errors\n  console.log(form.errors.name)\n  console.log(form.errors['company.name'])\n\n  // Clear Errors\n  form.clearErrors('name')\n  form.clearErrors('company')\n  form.clearErrors('company.name')\n  form.clearErrors('users')\n  form.clearErrors('users.0')\n  form.clearErrors('users.0.name')\n\n  // Reset and Clear Errors\n  form.resetAndClearErrors('name')\n  form.resetAndClearErrors('company')\n  form.resetAndClearErrors('company.name')\n  form.resetAndClearErrors('users')\n  form.resetAndClearErrors('users.0')\n  form.resetAndClearErrors('users.0.name')\n\n  // Set error by key\n  form.setError('name', 'Validation error')\n  form.setError('company', 'Validation error')\n  form.setError('company.name', 'Validation error')\n  form.setError('users', 'Validation error')\n  form.setError('users.0', 'Validation error')\n  form.setError('users.0.name', 'Validation error')\n\n  // Set error by object\n  form.setError({ name: 'Validation error' })\n  form.setError({ company: 'Validation error' })\n  form.setError({ 'company.name': 'Validation error' })\n  form.setError({ users: 'Validation error' })\n  form.setError({ 'users.0': 'Validation error' })\n  form.setError({ 'users.0.name': 'Validation error' })\n\n  // @ts-expect-error - Form has no email field\n  console.log(form.errors.email)\n  // @ts-expect-error - Company has no email field\n  console.log(form.errors['company.email'])\n\n  // @ts-expect-error - Form has no email field\n  form.clearErrors('email')\n  // @ts-expect-error - Form has no email field\n  form.resetAndClearErrors('email')\n  // @ts-expect-error - Form has no email field\n  form.setError('email', 'Validation error')\n  // @ts-expect-error - Form has no email field\n  form.setError({ email: 'Validation error' })\n\n  // @ts-expect-error - Company has no email field\n  form.clearErrors('company.email')\n  // @ts-expect-error - Company has no email field\n  form.resetAndClearErrors('company.email')\n  // @ts-expect-error - Company has no email field\n  form.setError('company.email', 'Validation error')\n  // @ts-expect-error - Company has no email field\n  form.setError({ 'company.email': 'Validation error' })\n\n  // @ts-expect-error - A user has no email field\n  form.clearErrors('users.0.email')\n  // @ts-expect-error - A user has no email field\n  form.resetAndClearErrors('users.0.email')\n  // @ts-expect-error - A user has no email field\n  form.setError('users.0.email', 'Validation error')\n  // @ts-expect-error - A user has no email field\n  form.setError({ 'users.0.email': 'Validation error' })\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/TypeScript/Generic.tsx",
    "content": "// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport type { FormDataConvertible } from '@inertiajs/core'\nimport type { InertiaFormProps } from '@inertiajs/react'\n\ninterface GenericProps<TFormData extends Record<string, FormDataConvertible>> {\n  form: InertiaFormProps<TFormData>\n}\n\nexport default function Generic<TFormData extends Record<string, FormDataConvertible>>({\n  form,\n}: GenericProps<TFormData>) {\n  console.log(form)\n  return <div>{/* Generic form component */}</div>\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/TypeScript/Nullable.tsx",
    "content": "// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/react'\n\nexport default function Nullable() {\n  useForm<{ object: { x: number } | null }>({\n    object: null,\n  })\n\n  useForm<{ object: { x: number } | null }>({\n    object: { x: 1 },\n  })\n\n  return <div></div>\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/TypeScript/NullableNestedObject.tsx",
    "content": "// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/react'\n\ninterface FormData {\n  foo: null | {\n    bar: string\n  }\n}\n\nexport default function NullableNestedObject() {\n  const form = useForm<FormData>({\n    foo: null,\n  })\n\n  console.log(form.errors['foo.bar'])\n\n  return <div></div>\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/TypeScript/OptionalProps.tsx",
    "content": "// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/react'\n\ninterface LoginData {\n  username: string\n  password: string\n  remember: boolean\n}\n\nexport default function OptionalProps({ user }: { user?: { username: string } }) {\n  useForm<LoginData>({\n    username: user?.username ?? '',\n    password: '',\n    remember: true,\n  })\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/TypeScript/Parent.tsx",
    "content": "// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/react'\nimport Child from './Child'\n\nexport default function Parent() {\n  const form = useForm({\n    name: 'foo',\n    remember: false,\n  })\n\n  return (\n    <div>\n      <Child form={form} />\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/TypeScript/Precognition.tsx",
    "content": "// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/react'\n\nexport default () => {\n  const defaultForm = useForm({})\n  const rememberForm = useForm('id', {})\n\n  // @ts-expect-error - No Precognition...\n  defaultForm.validate()\n  // @ts-expect-error - No Precognition...\n  rememberForm.validate()\n\n  const precognitionForm = useForm({ name: '', company: '' }).withPrecognition('post', '/precognition/default')\n  const originalPrecognitionForm = useForm('post', '/', {})\n\n  precognitionForm.validate()\n  originalPrecognitionForm.validate()\n\n  precognitionForm.validate('name')\n  precognitionForm.validate({ only: ['name'] })\n  precognitionForm.touch('name')\n  precognitionForm.touch('name', 'company')\n  precognitionForm.touched()\n  precognitionForm.touched('name')\n  precognitionForm.invalid('name')\n  precognitionForm.valid('name')\n\n  // @ts-expect-error - Field does not exist\n  precognitionForm.validate('email')\n  // @ts-expect-error - Field does not exist\n  precognitionForm.validate({ only: ['email'] })\n  // @ts-expect-error - Field does not exist\n  precognitionForm.touch('email')\n  // @ts-expect-error - Field does not exist\n  precognitionForm.touched('email')\n  // @ts-expect-error - Field does not exist\n  precognitionForm.invalid('email')\n  // @ts-expect-error - Field does not exist\n  precognitionForm.valid('email')\n\n  const nestedForm = useForm({ user: { name: '', company: '' } }).withPrecognition('post', '/precognition/nested')\n\n  nestedForm.validate('user.name')\n  nestedForm.validate({ only: ['user.name'] })\n  nestedForm.valid('user.name')\n  nestedForm.invalid('user.name')\n\n  // @ts-expect-error - Field does not exist\n  nestedForm.validate('user.email')\n  // @ts-expect-error - Field does not exist\n  nestedForm.validate({ only: ['user.email'] })\n  // @ts-expect-error - Field does not exist\n  nestedForm.valid('user.email')\n  // @ts-expect-error - Field does not exist\n  nestedForm.invalid('user.email')\n\n  // Wildcard path support (PrecognitionPath)\n  const wildcardForm = useForm({\n    users: [] as Array<{ name: string; email: string }>,\n    profile: { age: 0, city: '' },\n    company: { name: '', addresses: [] as string[] },\n    nested: { companies: [] as Array<{ name: string; addresses: string[] }> },\n  }).withPrecognition('post', '/precognition/wildcard')\n\n  // Valid array field paths\n  wildcardForm.validate('users')\n  wildcardForm.validate('users.*')\n  wildcardForm.validate('users.*.name')\n  wildcardForm.validate('users.*.email')\n  wildcardForm.validate('users.*.*')\n\n  // Valid object field paths\n  wildcardForm.validate('profile')\n  wildcardForm.validate('profile.*')\n  wildcardForm.validate('profile.age')\n\n  // Valid nested paths\n  wildcardForm.validate('company')\n  wildcardForm.validate('company.addresses')\n  wildcardForm.validate('nested')\n  wildcardForm.validate('nested.companies')\n  wildcardForm.validate('nested.companies.*')\n  wildcardForm.validate('nested.companies.*.name')\n  wildcardForm.validate('nested.companies.*.addresses')\n  wildcardForm.validate('nested.companies.*.*')\n\n  // @ts-expect-error - nonexistent property in array items\n  wildcardForm.validate('users.*.unknown')\n  // @ts-expect-error - missing wildcard for array access\n  wildcardForm.validate('users.email')\n  // @ts-expect-error - invalid deep nesting\n  wildcardForm.validate('profile.age.foo')\n  // @ts-expect-error - field does not exist\n  wildcardForm.validate('nonexistent')\n  // @ts-expect-error - no such field\n  wildcardForm.validate('profile.country')\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/FormHelper/TypeScript/ValidationKey.tsx",
    "content": "// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport type { FormDataConvertible } from '@inertiajs/core'\nimport type { InertiaFormProps } from '@inertiajs/react'\n\nconst validation = <T extends Record<string, FormDataConvertible>>(errors: () => InertiaFormProps<T>['errors']) => {\n  type Key = keyof ReturnType<typeof errors>\n\n  const filterAndMap = (key: Key) => {\n    const err = errors()\n\n    return (\n      Object.keys(err).filter((k) => typeof key === 'string' && k.startsWith(key)) as [keyof ReturnType<typeof errors>]\n    ).map((k) => err[k])\n  }\n\n  const unique = (key: Key) => {\n    return filterAndMap(key).filter((error, index, self) => self.indexOf(error) === index)\n  }\n\n  return { filterAndMap, unique }\n}\n\nexport default function ValidationKey() {\n  validation(() => ({ name: 'Validation error' }))\n\n  return <div>{/* ValidationKey component */}</div>\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Head/Conditional.tsx",
    "content": "import { Head } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const [showDescription, setShowDescription] = useState(true)\n  const [showKeywords, setShowKeywords] = useState(false)\n\n  const toggleDescription = () => {\n    setShowDescription(!showDescription)\n  }\n\n  const toggleKeywords = () => {\n    setShowKeywords(!showKeywords)\n  }\n\n  return (\n    <>\n      <Head title=\"Conditional Rendering\">\n        {showDescription && (\n          <meta name=\"description\" content=\"This description is conditionally rendered\" head-key=\"description\" />\n        )}\n        {showKeywords && <meta name=\"keywords\" content=\"vue, test, conditional\" head-key=\"keywords\" />}\n        <meta name=\"always-present\" content=\"This is always here\" />\n      </Head>\n\n      <div>\n        <h1>Conditional Head Rendering</h1>\n        <button id=\"toggle-description\" onClick={toggleDescription}>\n          {showDescription ? 'Hide' : 'Show'} Description\n        </button>\n        <button id=\"toggle-keywords\" onClick={toggleKeywords}>\n          {showKeywords ? 'Hide' : 'Show'} Keywords\n        </button>\n        <p>Description visible: {showDescription.toString()}</p>\n        <p>Keywords visible: {showKeywords.toString()}</p>\n      </div>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Head/Dataset.tsx",
    "content": "import { config, Head } from '@inertiajs/react'\n\nexport default () => {\n  config.set('future.useDataInertiaHeadAttribute', true)\n\n  return (\n    <>\n      <Head title=\"Test Head Component\">\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n      </Head>\n\n      <h1 style={{ fontSize: '40px' }}>Head Component</h1>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Head/Mixed.tsx",
    "content": "import { Head, Link } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <>\n      <Head title=\"Multiple Elements Test\">\n        <meta charSet=\"utf-8\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n        <meta name=\"description\" content=\"Testing multiple head elements\" />\n        <meta name=\"keywords\" content=\"test, vue, inertia\" />\n        <meta property=\"og:title\" content=\"Open Graph Title\" />\n        <meta property=\"og:description\" content=\"Open Graph Description\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n        <link rel=\"stylesheet\" href=\"/custom.css\" />\n        <link rel=\"canonical\" href=\"https://example.com/page\" />\n      </Head>\n\n      <div>\n        <h1>Multiple Head Elements</h1>\n        <p>Check the document head for multiple elements</p>\n        <Link id=\"navigate-away\" href=\"/\">\n          Go Home\n        </Link>\n        <Link id=\"navigate-back\" href=\"/head/mixed\">\n          Back to Mixed\n        </Link>\n      </div>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Head/Reactive.tsx",
    "content": "import { Head } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const [title, setTitle] = useState('Initial Title')\n  const [description, setDescription] = useState('Initial description')\n\n  const updateMeta = () => {\n    setTitle('Updated Title')\n    setDescription('Updated description')\n  }\n\n  return (\n    <>\n      <Head title={title}>\n        <meta name=\"description\" content={description} head-key=\"description\" />\n        <meta name=\"author\" content=\"Test Author\" />\n      </Head>\n\n      <div>\n        <h1>Dynamic Head Updates</h1>\n        <button id=\"update-meta\" onClick={updateMeta}>\n          Update Meta\n        </button>\n        <p>Current title: {title}</p>\n        <p>Current description: {description}</p>\n      </div>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Head/WithTitle.tsx",
    "content": "import { Head } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <>\n      <Head>\n        {/* Title as a child element instead of prop */}\n        <title>Title from Children</title>\n        <meta name=\"description\" content=\"Title set via children, not prop\" />\n      </Head>\n\n      <div>\n        <h1>Title in Children</h1>\n        <p>Tests title element as a child instead of using title prop</p>\n      </div>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Head/WithoutTitle.tsx",
    "content": "import { Head } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <>\n      <Head>\n        {/* Head with no title prop */}\n        <meta name=\"test\" content=\"no title provided\" />\n      </Head>\n\n      <div>\n        <h1>Head without Title Prop</h1>\n        <p>Tests that Head works without a title prop</p>\n      </div>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Head.tsx",
    "content": "import { Head } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <>\n      <Head title=\"Test Head Component\">\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n        <meta name=\"description\" content='This is an \"escape\" example' />\n        <meta name=\"undefined\" content={undefined} />\n        {/* @ts-expect-error - The content attribute must be a string, we support passing other types for backwards compatibility */}\n        <meta name=\"number\" content={0} />\n        {/* @ts-expect-error - same as above */}\n        <meta name=\"boolean\" content={true} />\n        {/* @ts-expect-error - same as above */}\n        <meta name=\"false\" content={false} />\n        {/* @ts-expect-error - same as above */}\n        <meta name=\"null\" content={null} />\n        {/* @ts-expect-error - same as above */}\n        <meta name=\"float\" content={3.14} />\n        <meta name=\"xss\" content=\"<script>alert('xss')</script>\" />\n        <meta name=\"ampersand\" content=\"Laravel & Inertia\" />\n        <meta name=\"unicode\" content=\"Hélló! 🎉\" />\n      </Head>\n\n      <h1 style={{ fontSize: '40px' }}>Head Component</h1>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/History/Page.tsx",
    "content": "import { Link, router } from '@inertiajs/react'\n\nexport default ({ pageNumber, multiByte }: { pageNumber: string; multiByte: string }) => {\n  const clearHistory = () => {\n    router.clearHistory()\n  }\n\n  return (\n    <>\n      <Link href=\"/history/1\">Page 1</Link>\n      <Link href=\"/history/2\">Page 2</Link>\n      <Link href=\"/history/3\">Page 3</Link>\n      <Link href=\"/history/4\">Page 4</Link>\n      <Link href=\"/history/5\">Page 5</Link>\n\n      <button onClick={clearHistory}>Clear History</button>\n\n      <div>This is page {pageNumber}.</div>\n      <div>Multi byte character: {multiByte}</div>\n\n      <div style={{ height: '5000px' }}></div>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/History/Version.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <>\n      <Link href=\"/history/version/1\">Page 1</Link>\n      <Link href=\"/history/version/2\">Page 2</Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/HistoryQuota/Page.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default ({ pageNumber, largeData }: { pageNumber: number; largeData: string }) => {\n  return (\n    <div>\n      <h1>History Quota Test - Page {pageNumber}</h1>\n      <p>Data size: {largeData?.length?.toLocaleString()} bytes</p>\n\n      <div style={{ marginTop: 20 }}>\n        {Array.from({ length: 20 }, (_, i) => i + 1).map((n) => (\n          <Link key={n} href={`/history-quota/${n}`} style={{ marginRight: 10 }}>\n            Page {n}\n          </Link>\n        ))}\n      </div>\n\n      <div style={{ height: 5000 }}></div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/HistoryThrottle.tsx",
    "content": "import { Link, router } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default function HistoryThrottle() {\n  const [callCount, setCallCount] = useState(0)\n\n  const triggerRapidStateUpdates = () => {\n    for (let i = 0; i < 120; i++) {\n      setCallCount(i + 1)\n      router.remember({ value: i }, `key-${i}`)\n    }\n  }\n\n  return (\n    <div>\n      <h1>History Throttle Test</h1>\n      <p id=\"call-count\">State updates: {callCount}</p>\n      <button id=\"trigger\" onClick={triggerRapidStateUpdates}>\n        Trigger Rapid State Updates\n      </button>\n      <Link id=\"home-link\" href=\"/\">\n        Go Home\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Home.tsx",
    "content": "import { Head, Link, router } from '@inertiajs/react'\n\nexport default (props: { example: string }) => {\n  const visitsMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/method')\n  }\n\n  const visitsReplace = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('/visits/replace')\n  }\n\n  const redirect = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.post('/redirect')\n  }\n\n  const redirectExternal = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.post('/redirect-external')\n  }\n\n  // window._inertia_page_key = getCurrentInstance().uid\n  window._inertia_props = props\n  // window._plugin_global_props = getCurrentInstance().appContext.config.globalProperties\n\n  return (\n    <>\n      <Head title=\"Home\" />\n\n      <div>\n        <span className=\"text\">This is the Test App Entrypoint page</span>\n\n        <Link href=\"/links/method\" className=\"links-method\">\n          Basic Links\n        </Link>\n\n        <Link href=\"/links/replace\" className=\"links-replace\">\n          'Replace' Links\n        </Link>\n\n        <Link href=\"/links/as-component\" className=\"links-as-component\">\n          As Component\n        </Link>\n\n        <Link href=\"/links/as-element\" className=\"links-as-component\">\n          As Element\n        </Link>\n\n        <a href=\"#\" onClick={visitsMethod} className=\"visits-method\">\n          Manual basic visits\n        </a>\n\n        <a href=\"#\" onClick={visitsReplace} className=\"visits-replace\">\n          Manual 'Replace' visits\n        </a>\n\n        <Link href=\"/redirect\" method=\"post\" className=\"links-redirect\">\n          Internal Redirect Link\n        </Link>\n        <a href=\"#\" onClick={redirect} className=\"visits-redirect\">\n          Manual Redirect visit\n        </a>\n\n        <Link href=\"/redirect-external\" method=\"post\" className=\"links-redirect-external\">\n          External Redirect Link\n        </Link>\n\n        <a href=\"#\" onClick={redirectExternal} className=\"visits-redirect-external\">\n          Manual External Redirect visit\n        </a>\n\n        <Link id=\"navigate-back\" href=\"/head/mixed\">\n          Go to Mixed Head\n        </Link>\n      </div>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/CustomElement.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  return (\n    <InfiniteScroll\n      data=\"users\"\n      as=\"section\"\n      data-testid=\"infinite-scroll-container\"\n      loading={() => <div style={{ textAlign: 'center', padding: '20px' }}>Loading...</div>}\n    >\n      {users.data.map((user) => (\n        <UserCard key={user.id} user={user} />\n      ))}\n    </InfiniteScroll>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/CustomTriggersRef.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport { useRef } from 'react'\nimport { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  const tableHeader = useRef<HTMLTableSectionElement>(null)\n  const tableFooter = useRef<HTMLTableSectionElement>(null)\n  const tableBody = useRef<HTMLTableSectionElement>(null)\n\n  return (\n    <div style={{ padding: '20px' }}>\n      <h1>Custom Triggers with Refs Test</h1>\n\n      <InfiniteScroll data=\"users\" startElement={tableHeader} endElement={tableFooter} itemsElement={tableBody}>\n        {({ loadingPrevious, loadingNext }) => (\n          <>\n            <div\n              style={{\n                height: '300px',\n                width: '100%',\n                textAlign: 'center',\n                lineHeight: '300px',\n                border: '1px solid #ccc',\n              }}\n            >\n              Spacer\n            </div>\n\n            <table style={{ width: '100%', borderCollapse: 'collapse' }}>\n              <thead ref={tableHeader} style={{ padding: '10px' }}>\n                <tr>\n                  <th style={{ padding: '12px', border: '1px solid #ccc' }}>ID</th>\n                  <th style={{ padding: '12px', border: '1px solid #ccc' }}>Name</th>\n                </tr>\n              </thead>\n\n              <tbody ref={tableBody}>\n                {users.data.map((user) => (\n                  <tr key={user.id} data-user-id={user.id}>\n                    <td style={{ padding: '80px 12px', border: '1px solid #ccc' }}>{user.id}</td>\n                    <td style={{ padding: '80px 12px', border: '1px solid #ccc' }}>{user.name}</td>\n                  </tr>\n                ))}\n                {(loadingPrevious || loadingNext) && (\n                  <tr>\n                    <td colSpan={2} style={{ padding: '12px', border: '1px solid #ccc', textAlign: 'center' }}>\n                      Loading...\n                    </td>\n                  </tr>\n                )}\n              </tbody>\n\n              <tfoot ref={tableFooter} style={{ background: '#fdf2e8', padding: '10px' }}>\n                <tr>\n                  <td colSpan={2} style={{ padding: '12px', border: '1px solid #ccc', textAlign: 'center' }}>\n                    Table Footer - Triggers when this comes into view\n                  </td>\n                </tr>\n              </tfoot>\n            </table>\n\n            <div\n              style={{\n                height: '300px',\n                width: '100%',\n                textAlign: 'center',\n                lineHeight: '300px',\n                border: '1px solid #ccc',\n              }}\n            >\n              Spacer\n            </div>\n          </>\n        )}\n      </InfiniteScroll>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/CustomTriggersRefObject.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport { useRef } from 'react'\nimport { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  const tableHeader = useRef<HTMLTableSectionElement>(null)\n  const tableFooter = useRef<HTMLTableSectionElement>(null)\n  const tableBody = useRef<HTMLTableSectionElement>(null)\n\n  return (\n    <div style={{ padding: '20px' }}>\n      <h1>Custom Triggers with React Ref Objects Test</h1>\n\n      <InfiniteScroll data=\"users\" startElement={tableHeader} endElement={tableFooter} itemsElement={tableBody}>\n        {({ loadingPrevious, loadingNext }) => (\n          <>\n            <div\n              style={{\n                height: '300px',\n                width: '100%',\n                textAlign: 'center',\n                lineHeight: '300px',\n                border: '1px solid #ccc',\n              }}\n            >\n              Spacer\n            </div>\n\n            <table style={{ width: '100%', borderCollapse: 'collapse' }}>\n              <thead ref={tableHeader} style={{ padding: '10px' }}>\n                <tr>\n                  <th style={{ padding: '12px', border: '1px solid #ccc' }}>ID</th>\n                  <th style={{ padding: '12px', border: '1px solid #ccc' }}>Name</th>\n                </tr>\n              </thead>\n\n              <tbody ref={tableBody}>\n                {users.data.map((user) => (\n                  <tr key={user.id} data-user-id={user.id}>\n                    <td style={{ padding: '80px 12px', border: '1px solid #ccc' }}>{user.id}</td>\n                    <td style={{ padding: '80px 12px', border: '1px solid #ccc' }}>{user.name}</td>\n                  </tr>\n                ))}\n                {(loadingPrevious || loadingNext) && (\n                  <tr>\n                    <td colSpan={2} style={{ padding: '12px', border: '1px solid #ccc', textAlign: 'center' }}>\n                      Loading...\n                    </td>\n                  </tr>\n                )}\n              </tbody>\n\n              <tfoot ref={tableFooter} style={{ background: '#fdf2e8', padding: '10px' }}>\n                <tr>\n                  <td colSpan={2} style={{ padding: '12px', border: '1px solid #ccc', textAlign: 'center' }}>\n                    Table Footer - Triggers when this comes into view\n                  </td>\n                </tr>\n              </tfoot>\n            </table>\n\n            <div\n              style={{\n                height: '300px',\n                width: '100%',\n                textAlign: 'center',\n                lineHeight: '300px',\n                border: '1px solid #ccc',\n              }}\n            >\n              Spacer\n            </div>\n          </>\n        )}\n      </InfiniteScroll>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/CustomTriggersSelector.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  return (\n    <div style={{ padding: '20px' }}>\n      <h1>Custom Triggers with Selectors Test</h1>\n\n      <InfiniteScroll data=\"users\" itemsElement=\"#table-body\" startElement=\"#table-header\" endElement=\"#table-footer\">\n        {({ loadingPrevious, loadingNext }) => (\n          <>\n            <div\n              style={{\n                height: '300px',\n                width: '100%',\n                textAlign: 'center',\n                lineHeight: '300px',\n                border: '1px solid #ccc',\n              }}\n            >\n              Spacer\n            </div>\n\n            <table style={{ width: '100%', borderCollapse: 'collapse' }}>\n              <thead id=\"table-header\" style={{ padding: '12px' }}>\n                <tr>\n                  <th style={{ padding: '12px', border: '1px solid #ccc' }}>ID</th>\n                  <th style={{ padding: '12px', border: '1px solid #ccc' }}>Name</th>\n                </tr>\n              </thead>\n\n              <tbody id=\"table-body\">\n                {users.data.map((user) => (\n                  <tr key={user.id} data-user-id={user.id}>\n                    <td style={{ padding: '80px 12px', border: '1px solid #ccc' }}>{user.id}</td>\n                    <td style={{ padding: '80px 12px', border: '1px solid #ccc' }}>{user.name}</td>\n                  </tr>\n                ))}\n\n                {(loadingPrevious || loadingNext) && (\n                  <tr>\n                    <td colSpan={2} style={{ padding: '12px', border: '1px solid #ccc', textAlign: 'center' }}>\n                      Loading...\n                    </td>\n                  </tr>\n                )}\n              </tbody>\n\n              <tfoot id=\"table-footer\" style={{ padding: '12px' }}>\n                <tr>\n                  <td colSpan={2} style={{ padding: '12px', border: '1px solid #ccc', textAlign: 'center' }}>\n                    Table Footer - Triggers when this comes into view\n                  </td>\n                </tr>\n              </tfoot>\n            </table>\n\n            <div\n              style={{\n                height: '300px',\n                width: '100%',\n                textAlign: 'center',\n                lineHeight: '300px',\n                border: '1px solid #ccc',\n              }}\n            >\n              Spacer\n            </div>\n          </>\n        )}\n      </InfiniteScroll>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/DataTable.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  return (\n    <InfiniteScroll data=\"users\" itemsElement=\"tbody\">\n      {({ loadingPrevious, loadingNext }) => (\n        <table style={{ width: '100%', borderCollapse: 'collapse' }}>\n          <thead>\n            <tr>\n              <th style={{ padding: '8px', border: '1px solid #ccc' }}>ID</th>\n              <th style={{ padding: '8px', border: '1px solid #ccc' }}>Name</th>\n            </tr>\n          </thead>\n\n          <tbody>\n            {users.data.map((user) => (\n              <tr key={user.id} data-user-id={user.id}>\n                <td style={{ padding: '8px', border: '1px solid #ccc' }}>{user.id}</td>\n                <td style={{ padding: '8px', border: '1px solid #ccc' }}>{user.name}</td>\n              </tr>\n            ))}\n          </tbody>\n\n          <tfoot>\n            {(loadingPrevious || loadingNext) && (\n              <tr>\n                <td colSpan={2} style={{ padding: '8px', border: '1px solid #ccc', textAlign: 'center' }}>\n                  Loading...\n                </td>\n              </tr>\n            )}\n          </tfoot>\n        </table>\n      )}\n    </InfiniteScroll>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/Deferred.tsx",
    "content": "import { Deferred, InfiniteScroll, usePage } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\nconst Users = () => {\n  const { users } = usePage<{ users: { data: User[] } }>().props\n\n  return (\n    <InfiniteScroll\n      data=\"users\"\n      style={{ display: 'grid', gap: '20px' }}\n      manual\n      previous={({ loading, fetch, hasMore }) => (\n        <>\n          <p>Has more previous items: {hasMore.toString()}</p>\n          <button onClick={fetch}>{loading ? 'Loading previous items...' : 'Load previous items'}</button>\n        </>\n      )}\n      next={({ loading, fetch, hasMore }) => (\n        <>\n          <p>Has more next items: {hasMore.toString()}</p>\n          <button onClick={fetch}>{loading ? 'Loading next items...' : 'Load next items'}</button>\n        </>\n      )}\n    >\n      {users.data.map((user) => (\n        <UserCard key={user.id} user={user} />\n      ))}\n    </InfiniteScroll>\n  )\n}\n\nexport default () => {\n  return (\n    <Deferred data=\"users\" fallback={<div>Loading deferred scroll prop...</div>}>\n      <Users />\n    </Deferred>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/DualContainers.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\ninterface Props {\n  users1: { data: User[] }\n  users2: { data: User[] }\n}\n\nexport default ({ users1, users2 }: Props) => {\n  return (\n    <div style={{ padding: '20px' }}>\n      <div style={{ display: 'flex', gap: '20px' }}>\n        {/* First scroll container */}\n        <div style={{ flex: 1 }}>\n          <h2>Users1 Container</h2>\n          <div\n            data-testid=\"scroll-container-1\"\n            style={{\n              height: '400px',\n              width: '100%',\n              border: '2px solid #3b82f6',\n              overflowY: 'auto',\n              background: '#f0f9ff',\n              padding: '10px',\n            }}\n          >\n            <InfiniteScroll\n              data=\"users1\"\n              style={{ display: 'grid', gap: '10px' }}\n              loading={() => (\n                <div style={{ textAlign: 'center', padding: '20px', color: '#3b82f6' }}>Loading more users1...</div>\n              )}\n            >\n              {users1.data.map((user) => (\n                <UserCard key={user.id} user={user} />\n              ))}\n            </InfiniteScroll>\n          </div>\n        </div>\n\n        {/* Second scroll container */}\n        <div style={{ flex: 1 }}>\n          <h2>Users2 Container</h2>\n          <div\n            data-testid=\"scroll-container-2\"\n            style={{\n              height: '400px',\n              width: '100%',\n              border: '2px solid #ef4444',\n              overflowY: 'auto',\n              background: '#fef2f2',\n              padding: '10px',\n            }}\n          >\n            <InfiniteScroll\n              data=\"users2\"\n              style={{ display: 'grid', gap: '10px' }}\n              loading={() => (\n                <div style={{ textAlign: 'center', padding: '20px', color: '#ef4444' }}>Loading more users2...</div>\n              )}\n            >\n              {users2.data.map((user) => (\n                <UserCard key={user.id} user={user} />\n              ))}\n            </InfiniteScroll>\n          </div>\n        </div>\n      </div>\n\n      <p style={{ marginTop: '20px' }}>Content below the scroll containers to verify page doesn't scroll.</p>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/DualSibling.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\ninterface Props {\n  users1: { data: User[] }\n  users2: { data: User[] }\n}\n\nexport default ({ users1, users2 }: Props) => {\n  return (\n    <div style={{ padding: '20px' }}>\n      <h1>Dual Sibling InfiniteScroll</h1>\n      <p style={{ marginBottom: '20px' }}>Two InfiniteScroll components side by side, sharing the window scroll</p>\n\n      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '40px' }}>\n        <div>\n          <h2>Users 1</h2>\n          <InfiniteScroll\n            data=\"users1\"\n            style={{ display: 'grid', gap: '20px' }}\n            manual\n            next={({ loading, fetch }) => (\n              <div style={{ textAlign: 'center', padding: '20px' }}>\n                <button onClick={fetch} disabled={loading}>\n                  {loading ? 'Loading...' : 'Load More Users 1'}\n                </button>\n              </div>\n            )}\n          >\n            {users1.data.map((user) => (\n              <UserCard key={user.id} user={user} />\n            ))}\n          </InfiniteScroll>\n        </div>\n\n        <div>\n          <h2>Users 2</h2>\n          <InfiniteScroll\n            data=\"users2\"\n            style={{ display: 'grid', gap: '20px' }}\n            manual\n            next={({ loading, fetch }) => (\n              <div style={{ textAlign: 'center', padding: '20px' }}>\n                <button onClick={fetch} disabled={loading}>\n                  {loading ? 'Loading...' : 'Load More Users 2'}\n                </button>\n              </div>\n            )}\n          >\n            {users2.data.map((user) => (\n              <UserCard key={user.id} user={user} />\n            ))}\n          </InfiniteScroll>\n        </div>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/Empty.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  return (\n    <div>\n      <h1>Empty Dataset Test</h1>\n      <InfiniteScroll\n        data=\"users\"\n        style={{ display: 'grid', gap: '20px' }}\n        loading={() => <div style={{ textAlign: 'center', padding: '20px' }}>Loading...</div>}\n      >\n        {users.data.map((user) => (\n          <UserCard key={user.id} user={user} />\n        ))}\n\n        {users.data.length === 0 && (\n          <div style={{ textAlign: 'center', padding: '40px', color: '#666' }}>No users found.</div>\n        )}\n      </InfiniteScroll>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/Filtering.tsx",
    "content": "import { InfiniteScroll, Link, useForm } from '@inertiajs/react'\nimport { debounce } from 'lodash-es'\nimport { useEffect, useMemo } from 'react'\nimport UserCard, { User } from './UserCard'\n\ninterface Props {\n  users: { data: User[] }\n  preserveState: boolean\n  filter?: string\n  search?: string\n}\n\nexport default ({ users, preserveState, filter, search }: Props) => {\n  const { data, setData, get } = useForm({\n    filter: undefined,\n    page: undefined,\n    search: search,\n  })\n\n  const debouncedSearch = useMemo(\n    () =>\n      debounce(() => {\n        get(\n          '',\n          preserveState\n            ? {\n                preserveState: true,\n                replace: true,\n                only: ['users', 'search', 'filter'],\n                reset: ['users'],\n              }\n            : {\n                replace: true,\n              },\n        )\n      }, 250),\n    [get, preserveState],\n  )\n\n  useEffect(() => {\n    if (data.search !== search) {\n      debouncedSearch()\n    }\n  }, [data.search, search, debouncedSearch])\n\n  const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n    setData('search', e.target.value)\n  }\n\n  return (\n    <div>\n      <div style={{ marginBottom: '20px', display: 'flex', gap: '10px' }}>\n        <Link href=\"\">No Filter</Link>\n        <Link href=\"?filter=a-m\">A-M</Link>\n        <Link href=\"?filter=n-z\">N-Z</Link>\n        <div>Current filter: {filter || 'none'}</div>\n        <div>Current search: {search || 'none'}</div>\n        <input value={data.search || ''} onChange={handleSearchChange} placeholder=\"Search...\" />\n      </div>\n\n      <InfiniteScroll\n        data=\"users\"\n        style={{ display: 'grid', gap: '20px' }}\n        loading={() => <div style={{ textAlign: 'center', padding: '20px' }}>Loading...</div>}\n      >\n        {users.data.map((user) => (\n          <UserCard key={user.id} user={user} />\n        ))}\n      </InfiniteScroll>\n\n      <div style={{ marginTop: '20px', display: 'flex', gap: '10px' }}>\n        <Link href=\"\">No Filter</Link>\n        <Link href=\"?filter=a-m\">A-M</Link>\n        <Link href=\"?filter=n-z\">N-Z</Link>\n        <div>Current filter: {filter || 'none'}</div>\n        <div>Current search: {search || 'none'}</div>\n        <input value={data.search || ''} onChange={handleSearchChange} placeholder=\"Search...\" />\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/FilteringManual.tsx",
    "content": "import { InfiniteScroll, useForm } from '@inertiajs/react'\nimport { debounce } from 'lodash-es'\nimport { useEffect, useMemo } from 'react'\nimport UserCard, { User } from './UserCard'\n\ninterface Props {\n  users: { data: User[] }\n  search?: string\n}\n\nexport default ({ users, search }: Props) => {\n  const { data, setData, get } = useForm({\n    search: search,\n  })\n\n  const debouncedSearch = useMemo(\n    () =>\n      debounce(() => {\n        get('', {\n          preserveState: true,\n          replace: true,\n          only: ['users', 'search'],\n          reset: ['users'],\n        })\n      }, 250),\n    [get],\n  )\n\n  useEffect(() => {\n    if (data.search !== search) {\n      debouncedSearch()\n    }\n  }, [data.search, search, debouncedSearch])\n\n  const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n    setData('search', e.target.value)\n  }\n\n  return (\n    <div>\n      <div style={{ marginBottom: '20px', display: 'flex', gap: '10px' }}>\n        <div>Current search: {search || 'none'}</div>\n        <input value={data.search || ''} onChange={handleSearchChange} placeholder=\"Search...\" />\n      </div>\n\n      <InfiniteScroll\n        data=\"users\"\n        style={{ display: 'grid', gap: '20px' }}\n        manual\n        previous={({ loading, fetch, hasMore }) => (\n          <>\n            <p>Has more previous items: {hasMore.toString()}</p>\n            <button onClick={fetch}>{loading ? 'Loading previous items...' : 'Load previous items'}</button>\n          </>\n        )}\n        next={({ loading, fetch, hasMore }) => (\n          <>\n            <p>Has more next items: {hasMore.toString()}</p>\n            <button onClick={fetch}>{loading ? 'Loading next items...' : 'Load next items'}</button>\n          </>\n        )}\n      >\n        {users.data.map((user) => (\n          <UserCard key={user.id} user={user} />\n        ))}\n      </InfiniteScroll>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/FilteringReset.tsx",
    "content": "import { InfiniteScroll, useForm } from '@inertiajs/react'\nimport { debounce } from 'lodash-es'\nimport { useEffect, useMemo } from 'react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users, search }: { users: { data: User[] }; search?: string }) => {\n  const { data, setData, get } = useForm({\n    search: search,\n  })\n\n  const debouncedSearch = useMemo(\n    () =>\n      debounce(() => {\n        get('', {\n          preserveState: true,\n          replace: true,\n          only: ['users', 'search'],\n          reset: ['users'],\n        })\n      }, 250),\n    [get],\n  )\n\n  useEffect(() => {\n    if (data.search !== search) {\n      debouncedSearch()\n    }\n  }, [data.search, search, debouncedSearch])\n\n  const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n    setData('search', e.target.value)\n  }\n\n  return (\n    <div>\n      <div style={{ marginBottom: '20px', display: 'flex', gap: '10px' }}>\n        <div>Current search: {search || 'none'}</div>\n        <input value={data.search || ''} onChange={handleSearchChange} placeholder=\"Search...\" />\n      </div>\n\n      <InfiniteScroll\n        data=\"users\"\n        buffer={2000}\n        style={{ display: 'grid', gap: '20px' }}\n        loading={() => <div style={{ textAlign: 'center', padding: '20px' }}>Loading...</div>}\n      >\n        {users.data.map((user) => (\n          <UserCard key={user.id} user={user} />\n        ))}\n      </InfiniteScroll>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/Grid.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  return (\n    <InfiniteScroll\n      data=\"users\"\n      style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: '20px' }}\n      loading={() => (\n        <div style={{ gridColumn: '1 / -1', textAlign: 'center', padding: '20px' }}>Loading more users...</div>\n      )}\n    >\n      {() => users.data.map((user) => <UserCard key={user.id} user={user} />)}\n    </InfiniteScroll>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/HorizontalScroll.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  return (\n    <div style={{ height: '120px', overflowX: 'scroll', display: 'flex', width: '100vw' }}>\n      <InfiniteScroll\n        data=\"users\"\n        style={{ display: 'flex', gap: '20px', height: '120px' }}\n        loading={() => (\n          <div\n            style={{\n              minWidth: '150px',\n              height: '100px',\n              display: 'flex',\n              alignItems: 'center',\n              justifyContent: 'center',\n              border: '1px dashed #ccc',\n              marginLeft: '20px',\n              marginRight: '20px',\n            }}\n          >\n            Loading...\n          </div>\n        )}\n      >\n        {users.data.map((user) => (\n          <div\n            key={user.id}\n            data-user-id={user.id}\n            style={{\n              minWidth: '200px',\n              height: '100px',\n              border: '1px solid #ccc',\n              backgroundColor: '#f5f5f5',\n              display: 'flex',\n              alignItems: 'center',\n              justifyContent: 'center',\n              flex: 'none',\n            }}\n          >\n            {user.name}\n          </div>\n        ))}\n      </InfiniteScroll>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/InfiniteScrollWithLink.tsx",
    "content": "import { InfiniteScroll, Link } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  return (\n    <div>\n      <Link href=\"/infinite-scroll\">Go back to Links</Link>\n      <InfiniteScroll\n        data=\"users\"\n        style={{ display: 'grid', gap: '20px' }}\n        loading={() => <div style={{ textAlign: 'center', padding: '20px' }}>Loading...</div>}\n      >\n        {users.data.map((user) => (\n          <UserCard key={user.id} user={user} />\n        ))}\n      </InfiniteScroll>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/InvisibleFirstChild.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  return (\n    <div>\n      <h1>Infinite Scroll with Invisible First Child</h1>\n\n      <InfiniteScroll\n        data=\"users\"\n        style={{ display: 'grid', gap: '20px' }}\n        loading={() => <div style={{ textAlign: 'center', padding: '20px' }}>Loading...</div>}\n      >\n        <div style={{ display: 'none' }}>Hidden first element</div>\n\n        {users.data.map((user) => (\n          <UserCard key={user.id} user={user} />\n        ))}\n      </InfiniteScroll>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/Links.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <Link href=\"/infinite-scroll-with-link\">Go to InfiniteScrollWithLink</Link>\n      <Link href=\"/infinite-scroll-with-link\" prefetch>\n        Go to InfiniteScrollWithLink (Prefetch)\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/Manual.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  return (\n    <InfiniteScroll\n      data=\"users\"\n      style={{ display: 'grid', gap: '20px' }}\n      manual\n      previous={({ loading, fetch, hasMore }) => (\n        <>\n          <p>Has more previous items: {hasMore.toString()}</p>\n          <button onClick={fetch}>{loading ? 'Loading previous items...' : 'Load previous items'}</button>\n        </>\n      )}\n      next={({ loading, fetch, hasMore }) => (\n        <>\n          <p>Has more next items: {hasMore.toString()}</p>\n          <button onClick={fetch}>{loading ? 'Loading next items...' : 'Load next items'}</button>\n        </>\n      )}\n    >\n      {users.data.map((user) => (\n        <UserCard key={user.id} user={user} />\n      ))}\n    </InfiniteScroll>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/ManualAfter.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  return (\n    <InfiniteScroll\n      data=\"users\"\n      style={{ display: 'grid', gap: '20px' }}\n      manualAfter={2}\n      next={({ fetch, manualMode, loading }) => (\n        <>\n          {loading && <p>Loading...</p>}\n\n          <p>Manual mode: {manualMode.toString()}</p>\n\n          {manualMode && <button onClick={fetch}>Load next items...</button>}\n        </>\n      )}\n    >\n      {users.data.map((user) => (\n        <UserCard key={user.id} user={user} />\n      ))}\n    </InfiniteScroll>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/OverflowX.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  return (\n    <div style={{ overflowX: 'hidden' }}>\n      <InfiniteScroll data=\"users\">\n        {users.data.map((user) => (\n          <div key={user.id} data-user-id={user.id}>\n            <div>{user.name}</div>\n          </div>\n        ))}\n      </InfiniteScroll>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/PreserveUrl.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  return (\n    <InfiniteScroll\n      data=\"users\"\n      preserveUrl={true}\n      style={{ display: 'grid', gap: '20px' }}\n      loading={() => <div style={{ textAlign: 'center', padding: '20px' }}>Loading...</div>}\n    >\n      {users.data.map((user) => (\n        <UserCard key={user.id} user={user} />\n      ))}\n    </InfiniteScroll>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/ProgrammaticRef.tsx",
    "content": "import { InfiniteScrollRef } from '@inertiajs/core'\nimport { InfiniteScroll } from '@inertiajs/react'\nimport { useCallback, useEffect, useState } from 'react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  const [infRef, setInfRef] = useState<InfiniteScrollRef | null>(null)\n  const [hasPrevious, setHasMoreBefore] = useState(false)\n  const [hasNext, setHasMoreAfter] = useState(false)\n\n  const updateStates = useCallback(() => {\n    setHasMoreBefore(infRef?.hasPrevious() || false)\n    setHasMoreAfter(infRef?.hasNext() || false)\n  }, [infRef])\n\n  const fetchNext = () => {\n    if (infRef) {\n      infRef.fetchNext({ onFinish: updateStates })\n    }\n  }\n\n  const fetchPrevious = () => {\n    if (infRef) {\n      infRef.fetchPrevious({ onFinish: updateStates })\n    }\n  }\n\n  useEffect(() => {\n    updateStates()\n  }, [infRef, updateStates])\n\n  return (\n    <div>\n      <h1>Programmatic Ref Test</h1>\n\n      <div style={{ marginBottom: '20px' }}>\n        <p>Has more previous items: {hasPrevious.toString()}</p>\n        <p>Has more next items: {hasNext.toString()}</p>\n\n        <div style={{ display: 'flex', gap: '10px', margin: '10px 0' }}>\n          <button onClick={fetchPrevious}>Load Previous (Ref)</button>\n          <button onClick={fetchNext}>Load Next (Ref)</button>\n        </div>\n      </div>\n\n      <InfiniteScroll\n        ref={setInfRef}\n        data=\"users\"\n        style={{ display: 'grid', gap: '20px' }}\n        manual\n        loading={() => <div style={{ textAlign: 'center', padding: '20px' }}>Loading...</div>}\n      >\n        {users.data.map((user) => (\n          <UserCard key={user.id} user={user} />\n        ))}\n      </InfiniteScroll>\n\n      <p>Total items on page: {users.data.length}</p>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/ReloadUnrelated.tsx",
    "content": "import { InfiniteScroll, router } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users, time }: { users: { data: User[] }; time: number }) => {\n  const reloadTime = () => {\n    router.reload({ only: ['time'] })\n  }\n\n  return (\n    <div>\n      <div>\n        <button onClick={reloadTime} id=\"reload-button\">\n          Reload Time\n        </button>\n        <span id=\"time-display\"> Current time: {time}</span>\n      </div>\n\n      <InfiniteScroll data=\"users\">\n        {users.data.map((user) => (\n          <UserCard key={user.id} user={user} />\n        ))}\n      </InfiniteScroll>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/RememberState.tsx",
    "content": "import { InfiniteScroll, Link, router } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  function prependUser(id: number) {\n    router.prependToProp('users.data', { id, name: `User ${id}` })\n  }\n\n  return (\n    <>\n      <div style={{ marginBottom: '40px', padding: '20px', borderTop: '2px solid #ccc' }}>\n        <div style={{ marginBottom: '20px' }}>\n          <button onClick={() => prependUser(0)} style={{ marginRight: '10px' }}>\n            Prepend User '0'\n          </button>\n          <button onClick={() => prependUser(-1)} style={{ marginRight: '10px' }}>\n            Prepend User '-1'\n          </button>\n        </div>\n        <Link href=\"/home\">Go Home</Link>\n      </div>\n\n      <InfiniteScroll\n        data=\"users\"\n        style={{ display: 'grid', gap: '20px' }}\n        manualAfter={2}\n        next={({ fetch, manualMode, loading }) => (\n          <>\n            {loading && <p>Loading...</p>}\n\n            <p>Manual mode: {manualMode.toString()}</p>\n\n            {manualMode && <button onClick={fetch}>Load next items...</button>}\n          </>\n        )}\n      >\n        {users.data.map((user) => (\n          <UserCard key={user.id} user={user} />\n        ))}\n      </InfiniteScroll>\n\n      <div style={{ marginTop: '40px', padding: '20px', borderTop: '2px solid #ccc' }}>\n        <Link href=\"/home\">Go to Home</Link>\n      </div>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/Reverse.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport { useMemo } from 'react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  const reversedUsers = useMemo(() => [...users.data].reverse(), [users.data])\n\n  return (\n    <InfiniteScroll\n      data=\"users\"\n      style={{ display: 'grid', gap: '20px' }}\n      reverse\n      autoScroll={false}\n      loading={() => <div style={{ textAlign: 'center', padding: '20px' }}>Loading...</div>}\n    >\n      {reversedUsers.map((user) => (\n        <UserCard key={user.id} user={user} />\n      ))}\n    </InfiniteScroll>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/ReverseShortContent.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport { useMemo } from 'react'\n\nexport default ({ users }: { users: { data: { id: number; name: string }[] } }) => {\n  const reversedUsers = useMemo(() => [...users.data].reverse(), [users.data])\n\n  return (\n    <div style={{ display: 'flex', flexDirection: 'column', height: '100vh' }}>\n      <div style={{ padding: '10px', borderBottom: '1px solid #ccc', flexShrink: 0 }}>Header</div>\n\n      <div data-testid=\"scroll-container\" style={{ flex: 1, overflowY: 'auto' }}>\n        <InfiniteScroll\n          data=\"users\"\n          style={{ display: 'grid', gap: '4px', padding: '20px' }}\n          reverse\n          loading={() => <div style={{ textAlign: 'center', padding: '10px' }}>Loading...</div>}\n        >\n          {reversedUsers.map((user) => (\n            <div\n              key={user.id}\n              data-user-id={user.id}\n              style={{ padding: '4px 8px', border: '1px solid #ddd', fontSize: '13px' }}\n            >\n              {user.name}\n            </div>\n          ))}\n        </InfiniteScroll>\n      </div>\n\n      <div style={{ padding: '10px', borderTop: '1px solid #ccc', flexShrink: 0 }}>Footer</div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/ScrollContainer.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  return (\n    <div style={{ padding: '20px' }}>\n      <h1>Infinite Scroll in Container</h1>\n      <p>This component scrolls within a fixed-height container, not the full page.</p>\n\n      {/* Fixed height scrollable container */}\n      <div\n        data-testid=\"scroll-container\"\n        style={{\n          height: '400px',\n          width: '100%',\n          border: '2px solid #ccc',\n          overflowY: 'auto',\n          background: '#f9f9f9',\n          padding: '10px',\n        }}\n      >\n        <InfiniteScroll\n          data=\"users\"\n          style={{ display: 'grid', gap: '10px' }}\n          loading={() => (\n            <div style={{ textAlign: 'center', padding: '20px', color: '#666' }}>Loading more users...</div>\n          )}\n        >\n          {users.data.map((user) => (\n            <UserCard key={user.id} user={user} />\n          ))}\n        </InfiniteScroll>\n      </div>\n\n      <p style={{ marginTop: '20px' }}>Content below the scroll container to verify page doesn't scroll.</p>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/ShortContent.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  return (\n    <InfiniteScroll data=\"users\" itemsElement=\"tbody\">\n      {() => (\n        <table style={{ width: '100%', borderCollapse: 'collapse' }}>\n          <tbody>\n            {users.data.map((user) => (\n              <tr key={user.id} data-user-id={user.id}>\n                <td style={{ padding: '10px', border: '1px solid #ccc' }}>{user.id}</td>\n                <td style={{ padding: '10px', border: '1px solid #ccc' }}>{user.name}</td>\n              </tr>\n            ))}\n          </tbody>\n        </table>\n      )}\n    </InfiniteScroll>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/Toggles.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport { useState } from 'react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  const [manual, setManual] = useState(false)\n  const [preserveUrl, setPreserveUrl] = useState(false)\n  const [triggerMode, setTriggerMode] = useState<'onlyPrevious' | 'onlyNext' | 'both'>('onlyNext')\n\n  return (\n    <div>\n      <div style={{ display: 'flex', gap: '10px' }}>\n        <p>\n          <label>\n            <input type=\"checkbox\" checked={manual} onChange={(e) => setManual(e.target.checked)} />\n            Manual mode: {manual.toString()}\n          </label>\n        </p>\n\n        <p>\n          <label>\n            <input type=\"checkbox\" checked={preserveUrl} onChange={(e) => setPreserveUrl(e.target.checked)} />\n            Preserve URL: {preserveUrl.toString()}\n          </label>\n        </p>\n\n        <p>\n          <label>\n            Trigger mode: {triggerMode}\n            <select\n              value={triggerMode}\n              onChange={(e) => setTriggerMode(e.target.value as 'onlyPrevious' | 'onlyNext' | 'both')}\n            >\n              <option value=\"onlyPrevious\">onlyPrevious</option>\n              <option value=\"onlyNext\">onlyNext</option>\n              <option value=\"both\">both</option>\n            </select>\n          </label>\n        </p>\n      </div>\n\n      <InfiniteScroll\n        data=\"users\"\n        style={{ display: 'grid', gap: '20px' }}\n        manual={manual}\n        preserveUrl={preserveUrl}\n        onlyNext={triggerMode === 'onlyNext'}\n        onlyPrevious={triggerMode === 'onlyPrevious'}\n        loading={<div style={{ textAlign: 'center', padding: '20px' }}>Loading...</div>}\n      >\n        {users.data.map((user) => (\n          <UserCard key={user.id} user={user} />\n        ))}\n      </InfiniteScroll>\n\n      <p>Total items on page: {users.data.length}</p>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/TriggerBoth.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  return (\n    <InfiniteScroll\n      data=\"users\"\n      style={{ display: 'grid', gap: '20px' }}\n      loading={() => <div style={{ textAlign: 'center', padding: '20px' }}>Loading...</div>}\n    >\n      {users.data.map((user) => (\n        <UserCard key={user.id} user={user} />\n      ))}\n    </InfiniteScroll>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/TriggerEndBuffer.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  return (\n    <InfiniteScroll\n      data=\"users\"\n      buffer={200}\n      onlyNext\n      style={{ display: 'grid', gap: '20px' }}\n      loading={() => <div style={{ textAlign: 'center', padding: '20px' }}>Loading...</div>}\n    >\n      {users.data.map((user) => (\n        <UserCard key={user.id} user={user} />\n      ))}\n    </InfiniteScroll>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/TriggerStartBuffer.tsx",
    "content": "import { InfiniteScroll } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  return (\n    <InfiniteScroll\n      data=\"users\"\n      buffer={200}\n      onlyPrevious\n      style={{ display: 'grid', gap: '20px' }}\n      loading={() => <div style={{ textAlign: 'center', padding: '20px' }}>Loading...</div>}\n    >\n      {users.data.map((user) => (\n        <UserCard key={user.id} user={user} />\n      ))}\n    </InfiniteScroll>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/UpdateQueryString.tsx",
    "content": "import { InfiniteScroll, usePage } from '@inertiajs/react'\nimport UserCard, { User } from './UserCard'\n\nexport default ({ users }: { users: { data: User[] } }) => {\n  const page = usePage()\n\n  window.testing = {\n    ...(window.testing || {}),\n    get pageUrl() {\n      return page.url\n    },\n  }\n\n  return (\n    <InfiniteScroll\n      data=\"users\"\n      style={{ display: 'grid', gap: '20px' }}\n      loading={() => <div style={{ textAlign: 'center', padding: '20px' }}>Loading...</div>}\n    >\n      {users.data.map((user) => (\n        <UserCard key={user.id} user={user} />\n      ))}\n    </InfiniteScroll>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/InfiniteScroll/UserCard.tsx",
    "content": "export interface User {\n  id: number\n  name: string\n}\n\nexport default ({ user }: { user: User }) => {\n  return (\n    <div\n      data-user-id={user.id}\n      style={{\n        height: '15vh',\n        border: '1px solid #ccc',\n        backgroundColor: `rgba(150,150,150,${user.id / 40})`,\n        color: 'green',\n        display: 'flex',\n        alignItems: 'center',\n        justifyContent: 'center',\n      }}\n    >\n      {user.name}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/AsComponent.tsx",
    "content": "import { Link } from '@inertiajs/react'\nimport { useRef } from 'react'\n\ndeclare global {\n  interface Window {\n    componentEvents: Array<{ eventName: string; data: unknown; timestamp: number }>\n  }\n}\n\nwindow.componentEvents = []\n\nconst CustomButton = ({ children, ...props }: { children: React.ReactNode; [key: string]: unknown }) => (\n  <button\n    {...props}\n    style={{\n      backgroundColor: 'blue',\n      color: 'white',\n      padding: '10px',\n    }}\n  >\n    {children}\n  </button>\n)\n\nexport default ({ page }: { page: number }) => {\n  const state = useRef(crypto.randomUUID())\n\n  const trackEvent = (eventName: string, data: unknown = null) => {\n    window.componentEvents.push({ eventName, data, timestamp: Date.now() })\n  }\n\n  return (\n    <div>\n      <h1>Link Custom Component - Page {page}</h1>\n      <p id=\"state\">State: {state.current}</p>\n      <Link as={CustomButton} href=\"/dump/get\" className=\"get\">\n        GET Custom Component\n      </Link>\n      <Link as={CustomButton} method=\"post\" href=\"/dump/post\" className=\"post\">\n        POST Custom Component\n      </Link>\n      <Link as={CustomButton} method=\"post\" href=\"/dump/post\" data={{ test: 'data' }} className=\"data\">\n        Custom Component with Data\n      </Link>\n      <Link as={CustomButton} href=\"/dump/get\" headers={{ 'X-Test': 'header' }} className=\"headers\">\n        Custom Component with Headers\n      </Link>\n      <Link as={CustomButton} href=\"/links/as-component/2\" preserveState={true} className=\"preserve\">\n        Custom Component with Preserve State\n      </Link>\n      <Link as={CustomButton} href=\"/links/as-component/3\" replace={true} className=\"replace\">\n        Custom Component with Replace\n      </Link>\n      <Link\n        as={CustomButton}\n        href=\"/dump/get\"\n        onStart={(event) => trackEvent('onStart', event)}\n        onFinish={(event) => trackEvent('onFinish', event)}\n        onSuccess={(page) => trackEvent('onSuccess', page)}\n        className=\"events\"\n      >\n        Custom Component with Events\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/AsElement.tsx",
    "content": "import { Link } from '@inertiajs/react'\nimport { useRef } from 'react'\n\ndeclare global {\n  interface Window {\n    componentEvents: Array<{ eventName: string; data: unknown; timestamp: number }>\n  }\n}\n\nwindow.componentEvents = []\n\nexport default ({ page }: { page: number }) => {\n  const state = useRef(crypto.randomUUID())\n\n  const trackEvent = (eventName: string, data: unknown = null) => {\n    window.componentEvents.push({ eventName, data, timestamp: Date.now() })\n  }\n\n  return (\n    <div>\n      <h1>Link Custom Element - Page {page}</h1>\n      <p id=\"state\">State: {state.current}</p>\n      <Link\n        as=\"div\"\n        href=\"/dump/get\"\n        className=\"get\"\n        style={{ backgroundColor: 'blue', color: 'white', padding: '10px' }}\n      >\n        GET Custom Element\n      </Link>\n      <Link as=\"div\" method=\"post\" href=\"/dump/post\" className=\"post\">\n        POST Custom Element\n      </Link>\n      <Link as=\"div\" method=\"post\" href=\"/dump/post\" data={{ test: 'data' }} className=\"data\">\n        Custom Element with Data\n      </Link>\n      <Link as=\"div\" href=\"/dump/get\" headers={{ 'X-Test': 'header' }} className=\"headers\">\n        Custom Element with Headers\n      </Link>\n      <Link as=\"div\" href=\"/links/as-element/2\" preserveState={true} className=\"preserve\">\n        Custom Element with Preserve State\n      </Link>\n      <Link as=\"div\" href=\"/links/as-element/3\" replace={true} className=\"replace\">\n        Custom Element with Replace\n      </Link>\n      <Link\n        as=\"div\"\n        href=\"/dump/get\"\n        onStart={(event) => trackEvent('onStart', event)}\n        onFinish={(event) => trackEvent('onFinish', event)}\n        onSuccess={(page) => trackEvent('onSuccess', page)}\n        className=\"events\"\n      >\n        Custom Element with Events\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/AsWarning.tsx",
    "content": "import type { Method } from '@inertiajs/core'\nimport { Link } from '@inertiajs/react'\n\nexport default ({ method }: { method: Method }) => {\n  return (\n    <div>\n      <span className=\"text\">This is the links page that demonstrates inertia-links with an 'as' warning</span>\n\n      <Link method={method} href=\"/example\" className=\"get\">\n        {method} Link\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/AsWarningFalse.tsx",
    "content": "import type { Method } from '@inertiajs/core'\nimport { Link } from '@inertiajs/react'\n\nexport default ({ method }: { method: Method }) => {\n  return (\n    <div>\n      <span className=\"text\">This is the links page that demonstrates inertia-links without the 'as' warning</span>\n\n      <Link method={method} href=\"/example\" className=\"get\" as=\"button\">\n        {method} button Link\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/AutomaticCancellation.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <span className=\"text\">This is the links page that demonstrates that only one visit can be active at a time</span>\n      <Link\n        href=\"/sleep\"\n        className=\"visit\"\n        onCancel={() => console.log('cancelled')}\n        onStart={() => console.log('started')}\n      >\n        Link\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/CancelSyncRequest.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default ({ page }: { page: string }) => {\n  return (\n    <>\n      <h1 style={{ fontSize: '40px' }}>Page {page}</h1>\n\n      <Link href=\"/links/cancel-sync-request/1\">Go to Page 1</Link>\n      <Link href=\"/links/cancel-sync-request/2\">Go to Page 2</Link>\n      <Link href=\"/links/cancel-sync-request/3\">Go to Page 3</Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/Data/AutoConverted.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default () => {\n  const linkData = { file: new File([], 'example.jpg'), foo: 'bar' }\n\n  return (\n    <div>\n      <span className=\"text\">\n        This is the links page that demonstrates the automatic conversion of plain objects to form-data\n      </span>\n\n      <Link method=\"get\" href=\"/dump/get\" data={linkData} className=\"get\">\n        GET Link\n      </Link>\n      <Link as=\"button\" method=\"post\" href=\"/dump/post\" data={linkData} className=\"post\">\n        POST Link\n      </Link>\n      <Link as=\"button\" method=\"put\" href=\"/dump/put\" data={linkData} className=\"put\">\n        PUT Link\n      </Link>\n      <Link as=\"button\" method=\"patch\" href=\"/dump/patch\" data={linkData} className=\"patch\">\n        PATCH Link\n      </Link>\n      <Link as=\"button\" method=\"delete\" href=\"/dump/delete\" data={linkData} className=\"delete\">\n        DELETE Link\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/Data/FormData.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nconst linkData = new FormData()\n\nlinkData.append('bar', 'baz')\n\nexport default () => {\n  return (\n    <div>\n      <span className=\"text\">This is the links page that demonstrates passing data through FormData objects</span>\n\n      <Link method=\"get\" href=\"/dump/get\" data={linkData} className=\"get\">\n        GET Link\n      </Link>\n      <Link as=\"button\" method=\"post\" href=\"/dump/post\" data={linkData} className=\"post\">\n        POST Link\n      </Link>\n      <Link as=\"button\" method=\"put\" href=\"/dump/put\" data={linkData} className=\"put\">\n        PUT Link\n      </Link>\n      <Link as=\"button\" method=\"patch\" href=\"/dump/patch\" data={linkData} className=\"patch\">\n        PATCH Link\n      </Link>\n      <Link as=\"button\" method=\"delete\" href=\"/dump/delete\" data={linkData} className=\"delete\">\n        DELETE Link\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/Data/Object.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <span className=\"text\">This is the links page that demonstrates passing data through plain objects</span>\n\n      <Link method=\"get\" href=\"/dump/get\" data={{ foo: 'get' }} className=\"get\">\n        GET Link\n      </Link>\n      <Link as=\"button\" method=\"post\" href=\"/dump/post\" data={{ bar: 'post' }} className=\"post\">\n        POST Link\n      </Link>\n      <Link as=\"button\" method=\"put\" href=\"/dump/put\" data={{ baz: 'put' }} className=\"put\">\n        PUT Link\n      </Link>\n      <Link as=\"button\" method=\"patch\" href=\"/dump/patch\" data={{ foo: 'patch' }} className=\"patch\">\n        PATCH Link\n      </Link>\n      <Link as=\"button\" method=\"delete\" href=\"/dump/delete\" data={{ bar: 'delete' }} className=\"delete\">\n        DELETE Link\n      </Link>\n\n      <Link href=\"/dump/get\" data={{ a: ['b', 'c'] }} className=\"qsaf-default\">\n        QSAF Defaults\n      </Link>\n      <Link href=\"/dump/get\" data={{ a: ['b', 'c'] }} queryStringArrayFormat=\"indices\" className=\"qsaf-indices\">\n        QSAF Indices\n      </Link>\n      <Link href=\"/dump/get\" data={{ a: ['b', 'c'] }} queryStringArrayFormat=\"brackets\" className=\"qsaf-brackets\">\n        QSAF Brackets\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/DataLoading.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default () => (\n  <div>\n    <Link href=\"/sleep\" className=\"get\">\n      First\n    </Link>\n    <Link href=\"/sleep\" className=\"get\">\n      Second\n    </Link>\n  </div>\n)\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/Headers.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <span className=\"text\">This is the links page that demonstrates passing custom headers</span>\n      <Link href=\"/dump/get\" className=\"default\">\n        Standard visit Link\n      </Link>\n\n      <Link method=\"get\" href=\"/dump/get\" headers={{ foo: 'bar' }} className=\"custom\">\n        GET Link\n      </Link>\n      <Link\n        as=\"button\"\n        method=\"post\"\n        href=\"/dump/post\"\n        headers={{ bar: 'baz', 'X-Requested-With': 'custom' }}\n        className=\"overridden\"\n      >\n        POST Link\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/Location.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <span className=\"text\">This is the links page that demonstrates location visits inertia-links</span>\n\n      <Link href=\"/location\" replace className=\"example\">\n        Location visit\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/Method.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <span className=\"text\">This is the links page that demonstrates inertia-link methods</span>\n\n      <Link method=\"get\" href=\"/dump/get\" className=\"get\">\n        GET Link\n      </Link>\n      <Link as=\"button\" method=\"post\" href=\"/dump/post\" className=\"post\">\n        POST Link\n      </Link>\n      <Link as=\"button\" method=\"put\" href=\"/dump/put\" className=\"put\">\n        PUT Link\n      </Link>\n      <Link as=\"button\" method=\"patch\" href=\"/dump/patch\" className=\"patch\">\n        PATCH Link\n      </Link>\n      <Link as=\"button\" method=\"delete\" href=\"/dump/delete\" className=\"delete\">\n        DELETE Link\n      </Link>\n      <Link as=\"button\" href={{ url: '/dump/post', method: 'post' }}>\n        OBJECT Link\n      </Link>\n      <Link as=\"button\" href={{ url: '/dump/post', method: 'post' }} method=\"put\">\n        OBJECT METHOD OVERRIDE Link\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/PartialReloads.tsx",
    "content": "import { Link } from '@inertiajs/react'\nexport default ({\n  foo = 0,\n  bar,\n  baz,\n  headers,\n}: {\n  foo?: number\n  bar: number\n  baz: number\n  headers: Record<string, string>\n}) => {\n  window._inertia_props = { foo, bar, baz, headers }\n\n  return (\n    <div>\n      <span className=\"text\">This is the links page that demonstrates partial reloads</span>\n      <span className=\"foo-text\">Foo is now {foo}</span>\n      <span className=\"bar-text\">Bar is now {bar}</span>\n      <span className=\"baz-text\">Baz is now {baz}</span>\n      <pre className=\"headers\">{JSON.stringify(headers, null, 2)}</pre>\n\n      <Link href=\"/links/partial-reloads\" data={{ foo }} className=\"all\">\n        Update All\n      </Link>\n      <Link href=\"/links/partial-reloads\" only={['headers', 'foo', 'bar']} data={{ foo }} className=\"foo-bar\">\n        Only foo + bar\n      </Link>\n      <Link href=\"/links/partial-reloads\" only={['headers', 'baz']} data={{ foo }} className=\"baz\">\n        Only baz\n      </Link>\n      <Link href=\"/links/partial-reloads\" except={['foo', 'bar']} data={{ foo }} className=\"except-foo-bar\">\n        Except foo + bar\n      </Link>\n      <Link href=\"/links/partial-reloads\" except={['baz']} data={{ foo }} className=\"except-baz\">\n        Except baz\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/PathTraversal.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <Link href=\"../\">Up one level</Link>\n      <Link href=\"../../method\">Up two levels and open method</Link>\n      <Link href=\"../../../\">Up three levels</Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/PreserveScroll.tsx",
    "content": "import WithScrollRegion from '@/Layouts/WithScrollRegion.jsx'\nimport type { Page } from '@inertiajs/core'\nimport { Link } from '@inertiajs/react'\n\nconst PreserveScroll = ({ foo = 'default' }: { foo?: string }) => {\n  const preserveCallback = (page: Page) => {\n    console.log(JSON.stringify(page))\n    return true\n  }\n  const preserveCallbackFalse = (page: Page) => {\n    console.log(JSON.stringify(page))\n    return false\n  }\n\n  return (\n    <div style={{ height: '800px', width: '600px' }}>\n      <span className=\"text\">This is the links page that demonstrates scroll preservation with scroll regions</span>\n      <span className=\"foo\">Foo is now {foo}</span>\n\n      <Link\n        href=\"/links/preserve-scroll-page-two\"\n        preserveScroll\n        data={{ foo: 'baz' }}\n        data-testid=\"preserve\"\n        className=\"preserve\"\n      >\n        Preserve Scroll\n      </Link>\n      <Link href=\"/links/preserve-scroll-page-two\" data={{ foo: 'bar' }} data-testid=\"reset\" className=\"reset\">\n        Reset Scroll\n      </Link>\n\n      <Link\n        href=\"/links/preserve-scroll-page-two\"\n        preserveScroll={preserveCallback}\n        data={{ foo: 'baz' }}\n        data-testid=\"preserve-callback\"\n        className=\"preserve-callback\"\n      >\n        Preserve Scroll (Callback)\n      </Link>\n      <Link\n        href=\"/links/preserve-scroll-page-two\"\n        preserveScroll={preserveCallbackFalse}\n        data={{ foo: 'foo' }}\n        data-testid=\"reset-callback\"\n        className=\"reset-callback\"\n      >\n        Reset Scroll (Callback)\n      </Link>\n\n      <a href=\"/non-inertia\" className=\"off-site\">\n        Off-site link\n      </a>\n\n      <Link href=\"/article\" data-testid=\"article\" className=\"article\">\n        Article\n      </Link>\n    </div>\n  )\n}\n\nPreserveScroll.layout = (page: React.ReactNode) => <WithScrollRegion children={page} />\n\nexport default PreserveScroll\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/PreserveScrollFalse.tsx",
    "content": "import WithoutScrollRegion from '@/Layouts/WithoutScrollRegion.jsx'\nimport type { Page } from '@inertiajs/core'\nimport { Link } from '@inertiajs/react'\n\nconst PreserveScrollFalse = ({ foo = 'default' }: { foo?: string }) => {\n  const preserveCallback = (page: Page) => {\n    console.log(JSON.stringify(page))\n    return true\n  }\n\n  const preserveCallbackFalse = (page: Page) => {\n    console.log(JSON.stringify(page))\n    return false\n  }\n\n  return (\n    <div style={{ height: '800px', width: '600px' }}>\n      <span className=\"text\">This is the links page that demonstrates scroll preservation without scroll regions</span>\n      <span className=\"foo\">Foo is now {foo}</span>\n\n      <Link href=\"/links/preserve-scroll-false-page-two\" preserve-scroll data={{ foo: 'baz' }} className=\"preserve\">\n        Preserve Scroll\n      </Link>\n      <Link href=\"/links/preserve-scroll-false-page-two\" data={{ foo: 'bar' }} className=\"reset\">\n        Reset Scroll\n      </Link>\n\n      <Link\n        href=\"/links/preserve-scroll-false-page-two\"\n        preserveScroll={preserveCallback}\n        data={{ foo: 'baz' }}\n        className=\"preserve-callback\"\n      >\n        Preserve Scroll (Callback)\n      </Link>\n      <Link\n        href=\"/links/preserve-scroll-false-page-two\"\n        preserveScroll={preserveCallbackFalse}\n        data={{ foo: 'foo' }}\n        className=\"reset-callback\"\n      >\n        Reset Scroll (Callback)\n      </Link>\n\n      <a href=\"/non-inertia\" className=\"off-site\">\n        Off-site link\n      </a>\n    </div>\n  )\n}\n\nPreserveScrollFalse.layout = (page: React.ReactNode) => <WithoutScrollRegion children={page} />\n\nexport default PreserveScrollFalse\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/PreserveState.tsx",
    "content": "import WithoutScrollRegion from '@/Layouts/WithoutScrollRegion.jsx'\nimport type { Page } from '@inertiajs/core'\nimport { Link } from '@inertiajs/react'\nimport { useId } from 'react'\n\nconst PreserveState = ({ foo = 'default' }: { foo?: string }) => {\n  const preserveCallback = (page: Page) => {\n    alert(page)\n    return true\n  }\n\n  const preserveCallbackFalse = (page: Page) => {\n    alert(page)\n    return false\n  }\n\n  window._inertia_page_key = useId()\n\n  return (\n    <div>\n      <span className=\"text\">This is the links page that demonstrates preserve state on Links</span>\n      <span className=\"foo\">Foo is now {foo}</span>\n      <label>\n        Example Field\n        <input type=\"text\" name=\"example-field\" className=\"field\" />\n      </label>\n\n      <Link href=\"/links/preserve-state-page-two\" preserveState data={{ foo: 'bar' }} className=\"preserve\">\n        [State] Preserve: true\n      </Link>\n      <Link\n        href=\"/links/preserve-state-page-two\"\n        preserveState={false}\n        data={{ foo: 'baz' }}\n        className=\"preserve-false\"\n      >\n        [State] Preserve: false\n      </Link>\n\n      <Link\n        href=\"/links/preserve-state-page-two\"\n        preserveState={preserveCallback}\n        data={{ foo: 'callback-bar' }}\n        className=\"preserve-callback\"\n      >\n        [State] Preserve Callback: true\n      </Link>\n      <Link\n        href=\"/links/preserve-state-page-two\"\n        preserveState={preserveCallbackFalse}\n        data={{ foo: 'callback-baz' }}\n        className=\"preserve-callback-false\"\n      >\n        [State] Preserve Callback: false\n      </Link>\n    </div>\n  )\n}\n\nPreserveState.layout = (page: React.ReactNode) => <WithoutScrollRegion children={page} />\n\nexport default PreserveState\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/PreserveUrl.tsx",
    "content": "import { Link, router } from '@inertiajs/react'\n\ninterface PreserveUrlProps {\n  foo?: string\n  items?: {\n    data: string[]\n    next_page_url?: string\n  }\n}\n\nconst PreserveUrl = ({ foo = 'default', items }: PreserveUrlProps) => {\n  const loadMore = () => {\n    if (items?.next_page_url) {\n      router.visit(items.next_page_url, {\n        only: ['items'],\n        preserveState: true,\n        preserveScroll: true,\n        preserveUrl: true,\n      })\n    }\n  }\n\n  return (\n    <div>\n      <span className=\"text\">This is the links page that demonstrates preserve url on Links</span>\n      <span className=\"foo\">Foo is now {foo}</span>\n\n      <Link href=\"/links/preserve-url-page-two\" preserveUrl data={{ foo: 'bar' }} className=\"preserve\">\n        [URL] Preserve: true\n      </Link>\n      <Link href=\"/links/preserve-url-page-two\" preserveUrl={false} data={{ foo: 'baz' }} className=\"preserve-false\">\n        [URL] Preserve: false\n      </Link>\n\n      {items && (\n        <div className=\"items-section\">\n          <div className=\"items\">\n            {items.data.map((item) => (\n              <div key={item} className=\"item\">\n                {item}\n              </div>\n            ))}\n          </div>\n\n          <span className=\"items-loaded\">Items loaded: {items.data.length}</span>\n          <span className=\"has-next-page\">{items.next_page_url ? 'true' : 'false'}</span>\n\n          {items.next_page_url && (\n            <Link\n              href={items.next_page_url}\n              only={['items']}\n              preserveState\n              preserveScroll\n              preserveUrl\n              className=\"load-more\"\n            >\n              Load More\n            </Link>\n          )}\n\n          {items.next_page_url && (\n            <button onClick={loadMore} className=\"load-more-router\">\n              Load More Router\n            </button>\n          )}\n        </div>\n      )}\n    </div>\n  )\n}\n\nexport default PreserveUrl\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/PropUpdate.tsx",
    "content": "import { Link } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const [href, setHref] = useState('/sleep')\n\n  return (\n    <div>\n      <button onClick={() => setHref('/something-else')}>Change URL</button>\n      <Link href={href} className=\"get\">\n        The Link\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/Reactivity.tsx",
    "content": "import type { CacheForOption, LinkPrefetchOption, Method } from '@inertiajs/core'\nimport { Link } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const [method, setMethod] = useState<Method>('get')\n  const [href, setHref] = useState('/dump/get')\n  const [data, setData] = useState({ foo: 'bar' })\n  const [headers, setHeaders] = useState({ 'X-Custom-Header': 'value' })\n  const [prefetch, setPrefetch] = useState<boolean | LinkPrefetchOption>(false)\n  const [cacheFor, setCacheFor] = useState<CacheForOption>(0)\n\n  const change = () => {\n    setMethod('post')\n    setHref('/dump/post')\n    setData({ foo: 'baz' })\n    setHeaders({ 'X-Custom-Header': 'new-value' })\n  }\n\n  const enablePrefetch = () => {\n    setPrefetch('hover')\n    setCacheFor('1s')\n  }\n\n  return (\n    <div>\n      <span className=\"text\">\n        This page demonstrates reactivity in Inertia links. Click the button to change the link properties.\n      </span>\n\n      <Link method={method} href={href} data={data} headers={headers}>\n        Submit\n      </Link>\n\n      <button onClick={change}>Change Link Props</button>\n\n      <Link href=\"/dump/get\" prefetch={prefetch} cacheFor={cacheFor}>\n        Prefetch Link\n      </Link>\n\n      <button onClick={enablePrefetch}>Enable Prefetch (1s cache)</button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/Replace.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <span className=\"text\">This is the links page that demonstrates replace on Links</span>\n\n      <Link href=\"/dump/get\" replace className=\"replace\">\n        [State] Replace: true\n      </Link>\n      <Link href=\"/dump/get\" replace={false} className=\"replace-false\">\n        [State] Replace: false\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/ScrollRegionList.tsx",
    "content": "import WithScrollRegion from '@/Layouts/WithScrollRegion.jsx'\nimport { VisitHelperOptions } from '@inertiajs/core'\nimport { router } from '@inertiajs/react'\n\nconst ScrollRegionList = ({ user_id }: { user_id?: number }) => {\n  const navigate = (id: number, options: VisitHelperOptions = {}) => {\n    router.get(`/links/scroll-region-list/user/${id}`, {}, options)\n  }\n\n  const users = Array.from({ length: 10 }, (_, i) => ({ id: i + 1, name: `User ${i + 1}` }))\n\n  return (\n    <div>\n      <span className=\"text\">Scrollable list with scroll region</span>\n      <div className=\"user-text\">Clicked user: {user_id || 'none'}</div>\n\n      {users.map((user) => (\n        <div key={user.id} style={{ padding: '20px', borderBottom: '1px solid #ccc' }}>\n          <div style={{ marginBottom: '10px', width: '500px' }}>{user.name}</div>\n          <button onClick={() => navigate(user.id)}>Default</button>\n          <button onClick={() => navigate(user.id, { preserveScroll: true })}>Preserve True</button>\n          <button onClick={() => navigate(user.id, { preserveScroll: false })}>Preserve False</button>\n        </div>\n      ))}\n    </div>\n  )\n}\n\nScrollRegionList.layout = (page: React.ReactNode) => <WithScrollRegion children={page} />\n\nexport default ScrollRegionList\n"
  },
  {
    "path": "packages/react/test-app/Pages/Links/UrlFragments.tsx",
    "content": "import { Link } from '@inertiajs/react'\nimport { useEffect, useState } from 'react'\n\nexport default () => {\n  const [documentScrollTop, setDocumentScrollTop] = useState(0)\n  const [documentScrollLeft, setDocumentScrollLeft] = useState(0)\n\n  useEffect(() => {\n    document.addEventListener('scroll', handleScrollEvent)\n  })\n\n  const handleScrollEvent = () => {\n    setDocumentScrollTop(document.documentElement.scrollTop)\n    setDocumentScrollLeft(document.documentElement.scrollLeft)\n  }\n\n  return (\n    <div>\n      <span className=\"text\">This is the links page that demonstrates url fragment behaviour</span>\n      <div style={{ width: '200vw', height: '200vh', marginTop: '50vh' }}>\n        <button onClick={handleScrollEvent}>Update scroll positions</button>\n        {/* prettier-ignore */}\n        <div className=\"document-position\">\n          Document scroll position is {documentScrollLeft} & {documentScrollTop}\n        </div>\n        <Link href=\"/links/url-fragments#target\" className=\"basic\">\n          Basic link\n        </Link>\n        <Link href=\"#target\" className=\"fragment\">\n          Fragment link\n        </Link>\n        <Link href=\"/links/url-fragments#non-existent-fragment\" className=\"non-existent-fragment\">\n          Non-existent fragment link\n        </Link>\n\n        <div id=\"target\">This is the element with id 'target'</div>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/MatchPropsOnKey.tsx",
    "content": "import { router } from '@inertiajs/react'\nimport { useState } from 'react'\n\ninterface FooItem {\n  name: string\n}\n\ninterface FooProps {\n  page: number\n  data: FooItem[]\n  companies: FooItem[]\n  teams: FooItem[]\n  per_page: number\n  meta: {\n    label: string\n  }\n}\n\ninterface PageProps {\n  bar: number[]\n  foo: FooProps\n  baz: number[]\n}\n\nexport default ({ bar, foo, baz }: PageProps) => {\n  const [page, setPage] = useState(foo.page)\n\n  const reloadIt = () => {\n    router.visit('/match-props-on-key', {\n      data: {\n        page,\n      },\n      only: ['foo', 'baz'],\n      onSuccess(page) {\n        setPage((page.props as unknown as PageProps).foo.page)\n      },\n    })\n  }\n\n  const getFresh = () => {\n    setPage(0)\n    router.visit('/match-props-on-key', {\n      reset: ['foo', 'baz'],\n    })\n  }\n\n  return (\n    <>\n      <div>bar count is {bar.length}</div>\n      <div>baz count is {baz.length}</div>\n      <div>foo.data count is {foo.data.length}</div>\n      <div>first foo.data name is {foo.data[0].name}</div>\n      <div>last foo.data name is {foo.data[foo.data.length - 1].name}</div>\n      <div>foo.companies count is {foo.companies.length}</div>\n      <div>first foo.companies name is {foo.companies[0].name}</div>\n      <div>last foo.companies name is {foo.companies[foo.companies.length - 1].name}</div>\n      <div>foo.teams count is {foo.teams.length}</div>\n      <div>first foo.teams name is {foo.teams[0].name}</div>\n      <div>last foo.teams name is {foo.teams[foo.teams.length - 1].name}</div>\n      <div>foo.page is {foo.page}</div>\n      <div>foo.per_page is {foo.per_page}</div>\n      <div>foo.meta.label is {foo.meta.label}</div>\n      <button onClick={reloadIt}>Reload</button>\n      <button onClick={getFresh}>Get Fresh</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/MergeNestedProps.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default ({\n  users,\n}: {\n  users: { data: { id: number; name: string }[]; meta: { page: number; perPage: number } }\n}) => {\n  const loadMore = () => {\n    router.reload({\n      only: ['users'],\n      data: { page: users.meta.page + 1 },\n    })\n  }\n\n  return (\n    <div>\n      <p id=\"users\">{users.data.map((user) => user.name).join(', ')}</p>\n      <p id=\"meta\">\n        Page: {users.meta.page}, Per Page: {users.meta.perPage}\n      </p>\n      <button onClick={loadMore}>Load More</button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/MergeProps.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default ({ bar, foo }: { bar: number[]; foo: number[] }) => {\n  const reloadIt = () => {\n    router.reload({\n      only: ['foo'],\n    })\n  }\n\n  const getFresh = () => {\n    router.reload({\n      reset: ['foo'],\n    })\n  }\n\n  return (\n    <>\n      <div>bar count is {bar.length}</div>\n      <div>foo count is {foo.length}</div>\n      <button onClick={reloadIt}>Reload</button>\n      <button onClick={getFresh}>Get Fresh</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/NavigateNonInertia.tsx",
    "content": "export default () => {\n  function navigate(e: React.MouseEvent) {\n    e.preventDefault()\n    window.history.replaceState({ foo: {} }, '')\n    window.location.href = '/non-inertia'\n  }\n\n  return (\n    <div>\n      <h1>Navigate Non-Inertia</h1>\n      <p>\n        <a href=\"/non-inertia\" onClick={navigate}>\n          Go to non-Inertia page\n        </a>\n      </p>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/NetworkError.tsx",
    "content": "import { router } from '@inertiajs/react'\nimport { useEffect, useState } from 'react'\n\nexport default () => {\n  const [error, setError] = useState(false)\n\n  useEffect(() => {\n    return router.on('exception', () => {\n      setError(true)\n      return false\n    })\n  }, [])\n\n  function makeRequest() {\n    setError(false)\n    router.get('/network-error')\n  }\n\n  return (\n    <div>\n      <h1>Network Error</h1>\n      {error && <div id=\"network-error\">Network error occurred</div>}\n      <button id=\"make-request\" onClick={makeRequest}>\n        Make Request\n      </button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/ClientSideVisit.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default ({ foo, bar }: { foo: string; bar: string }) => {\n  const pushWithoutPreserving = () => {\n    router.push({\n      url: '/once-props/client-side-visit',\n      component: 'OnceProps/ClientSideVisit',\n      props: { bar: 'bar-updated' },\n    })\n  }\n\n  const pushWithOnceProps = () => {\n    router.push({\n      url: '/once-props/client-side-visit',\n      component: 'OnceProps/ClientSideVisit',\n      props: (currentProps, onceProps) => ({ ...onceProps, bar: 'bar-updated' }),\n    })\n  }\n\n  return (\n    <>\n      <p id=\"foo\">Foo: {foo}</p>\n      <p id=\"bar\">Bar: {bar}</p>\n      <button onClick={pushWithoutPreserving}>Push without preserving</button>\n      <button onClick={pushWithOnceProps}>Push with once props</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/CustomKeyPageA.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default ({ userPermissions, bar }: { userPermissions: string; bar: string }) => {\n  return (\n    <>\n      <p id=\"permissions\">Permissions: {userPermissions}</p>\n      <p id=\"bar\">Bar: {bar}</p>\n      <Link href=\"/once-props/custom-key/b\">Go to Custom Key Page B</Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/CustomKeyPageB.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default ({ permissions, bar }: { permissions: string; bar: string }) => {\n  return (\n    <>\n      <p id=\"permissions\">Permissions: {permissions}</p>\n      <p id=\"bar\">Bar: {bar}</p>\n      <Link href=\"/once-props/custom-key/a\">Go to Custom Key Page A</Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/DeferredPageA.tsx",
    "content": "import { Deferred, Link, usePage } from '@inertiajs/react'\n\nconst Foo = () => {\n  const { foo } = usePage<{ foo?: { text: string } }>().props\n\n  return <>{foo?.text}</>\n}\n\nexport default ({ bar }: { bar: string }) => {\n  return (\n    <>\n      <Deferred data=\"foo\" fallback={<div>Loading foo...</div>}>\n        <p id=\"foo\">\n          Foo: <Foo />\n        </p>\n      </Deferred>\n\n      <p id=\"bar\">Bar: {bar}</p>\n\n      <Link href=\"/once-props/deferred/b\">Go to Deferred Page B</Link>\n      <Link href=\"/once-props/deferred/c\" prefetch=\"mount\">\n        Go to Deferred Page C\n      </Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/DeferredPageB.tsx",
    "content": "import { Deferred, Link, usePage } from '@inertiajs/react'\n\nconst Foo = () => {\n  const { foo } = usePage<{ foo?: { text: string } }>().props\n\n  return <>{foo?.text}</>\n}\n\nexport default ({ bar }: { bar: string }) => {\n  return (\n    <>\n      <Deferred data=\"foo\" fallback={<div>Loading foo...</div>}>\n        <p id=\"foo\">\n          Foo: <Foo />\n        </p>\n      </Deferred>\n\n      <p id=\"bar\">Bar: {bar}</p>\n\n      <Link href=\"/once-props/deferred/a\">Go to Deferred Page A</Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/DeferredPageC.tsx",
    "content": "import { Deferred, Link, usePage } from '@inertiajs/react'\n\nconst Foo = () => {\n  const { foo } = usePage<{ foo?: { text: string } }>().props\n\n  return <>{foo?.text}</>\n}\n\nexport default ({ bar }: { bar: string }) => {\n  return (\n    <>\n      <Deferred data=\"foo\" fallback={<div>Loading foo...</div>}>\n        <p id=\"foo\">\n          Foo: <Foo />\n        </p>\n      </Deferred>\n\n      <p id=\"bar\">Bar: {bar}</p>\n\n      <Link href=\"/once-props/deferred/a\">Go to Deferred Page A</Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/MergePageA.tsx",
    "content": "import { Link, router } from '@inertiajs/react'\n\nexport default ({ items, bar }: { items: string[]; bar: string }) => {\n  return (\n    <>\n      <p id=\"items\">Items count: {items.length}</p>\n      <p id=\"bar\">Bar: {bar}</p>\n      <Link href=\"/once-props/merge/b\">Go to Merge Page B</Link>\n      <button onClick={() => router.reload({ only: ['items'] })}>Load more items</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/MergePageB.tsx",
    "content": "import { Link, router } from '@inertiajs/react'\n\nexport default ({ items, bar }: { items: string[]; bar: string }) => {\n  return (\n    <>\n      <p id=\"items\">Items count: {items.length}</p>\n      <p id=\"bar\">Bar: {bar}</p>\n      <Link href=\"/once-props/merge/a\">Go to Merge Page A</Link>\n      <button onClick={() => router.reload({ only: ['items'] })}>Load more items</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/OptionalPageA.tsx",
    "content": "import { Link, router } from '@inertiajs/react'\n\nexport default ({ foo, bar }: { foo?: string; bar: string }) => {\n  return (\n    <>\n      <p id=\"foo\">Foo: {foo ?? 'not loaded'}</p>\n      <p id=\"bar\">Bar: {bar}</p>\n      <Link href=\"/once-props/optional/b\">Go to Optional Page B</Link>\n      <button onClick={() => router.reload({ only: ['foo'] })}>Load foo</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/OptionalPageB.tsx",
    "content": "import { Link, router } from '@inertiajs/react'\n\nexport default ({ foo, bar }: { foo?: string; bar: string }) => {\n  return (\n    <>\n      <p id=\"foo\">Foo: {foo ?? 'not loaded'}</p>\n      <p id=\"bar\">Bar: {bar}</p>\n      <Link href=\"/once-props/optional/a\">Go to Optional Page A</Link>\n      <button onClick={() => router.reload({ only: ['foo'] })}>Load foo</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/PageA.tsx",
    "content": "import { Link, router } from '@inertiajs/react'\n\nexport default ({ foo, bar }: { foo: string; bar: string }) => {\n  return (\n    <>\n      <p id=\"foo\">Foo: {foo}</p>\n      <p id=\"bar\">Bar: {bar}</p>\n      <Link href=\"/once-props/page-b\">Go to Page B</Link>\n      <Link href=\"/once-props/page-c\">Go to Page C</Link>\n      <Link href=\"/once-props/page-d\" prefetch=\"mount\">\n        Go to Page D\n      </Link>\n      <Link href=\"/once-props/page-e\" prefetch=\"mount\" cacheFor={1000}>\n        Go to Page E (short cache)\n      </Link>\n      <button onClick={() => router.reload({ only: ['foo'] })}>Reload (only foo)</button>\n      <button onClick={() => router.replaceProp('foo', 'replaced-foo')}>Replace foo</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/PageB.tsx",
    "content": "import { Link, router } from '@inertiajs/react'\n\nexport default ({ foo, bar }: { foo: string; bar: string }) => {\n  return (\n    <>\n      <p id=\"foo\">Foo: {foo}</p>\n      <p id=\"bar\">Bar: {bar}</p>\n      <Link href=\"/once-props/page-a\">Go to Page A</Link>\n      <button onClick={() => router.reload({ only: ['foo'] })}>Reload (only foo)</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/PageC.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <>\n      <Link href=\"/once-props/page-a\">Go to Page A</Link>\n      <Link href=\"/once-props/page-b\">Go to Page B</Link>\n      <Link href=\"/once-props/page-d\" prefetch=\"mount\">\n        Go to Page D\n      </Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/PageD.tsx",
    "content": "export default ({ foo, bar }: { foo: string; bar: string }) => {\n  return (\n    <>\n      <p id=\"foo\">Foo: {foo}</p>\n      <p id=\"bar\">Bar: {bar}</p>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/PageE.tsx",
    "content": "export default ({ foo, bar }: { foo: string; bar: string }) => {\n  return (\n    <>\n      <p id=\"foo\">Foo: {foo}</p>\n      <p id=\"bar\">Bar: {bar}</p>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/PartialReloadA.tsx",
    "content": "import { Link, router } from '@inertiajs/react'\n\nexport default ({ foo, bar }: { foo: string; bar: string }) => {\n  return (\n    <>\n      <p id=\"foo\">Foo: {foo}</p>\n      <p id=\"bar\">Bar: {bar}</p>\n      <Link href=\"/once-props/partial-reload/b\">Go to Partial Reload B</Link>\n      <button onClick={() => router.reload({ only: ['foo'] })}>Reload (only foo)</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/PartialReloadB.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default ({ foo, bar }: { foo: string; bar: string }) => {\n  return (\n    <>\n      <p id=\"foo\">Foo: {foo}</p>\n      <p id=\"bar\">Bar: {bar}</p>\n      <Link href=\"/once-props/partial-reload/a\">Go to Partial Reload A</Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/SlowDeferredPageA.tsx",
    "content": "import { Deferred, Link, usePage } from '@inertiajs/react'\n\nconst Foo = () => {\n  const { foo } = usePage<{ foo?: string }>().props\n\n  return <>{foo}</>\n}\n\nexport default ({ bar }: { bar: string }) => {\n  return (\n    <>\n      <Deferred data=\"foo\" fallback={<div id=\"foo-loading\">Loading foo...</div>}>\n        <p id=\"foo\">\n          Foo: <Foo />\n        </p>\n      </Deferred>\n\n      <p id=\"bar\">Bar: {bar}</p>\n\n      <Link href=\"/once-props/slow-deferred/b\">Go to Page B</Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/SlowDeferredPageB.tsx",
    "content": "import { Deferred, Link, usePage } from '@inertiajs/react'\n\nconst Foo = () => {\n  const { foo } = usePage<{ foo?: string }>().props\n\n  return <>{foo}</>\n}\n\nexport default ({ bar }: { bar: string }) => {\n  return (\n    <>\n      <Deferred data=\"foo\" fallback={<div id=\"foo-loading\">Loading foo...</div>}>\n        <p id=\"foo\">\n          Foo: <Foo />\n        </p>\n      </Deferred>\n\n      <p id=\"bar\">Bar: {bar}</p>\n\n      <Link href=\"/once-props/slow-deferred/a\">Go to Page A</Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/TtlPageA.tsx",
    "content": "import { Link, router } from '@inertiajs/react'\n\nexport default ({ foo, bar }: { foo: string; bar: string }) => {\n  return (\n    <>\n      <p id=\"foo\">Foo: {foo}</p>\n      <p id=\"bar\">Bar: {bar}</p>\n      <Link href=\"/once-props/ttl/b\">Go to TTL Page B</Link>\n      <Link href=\"/once-props/ttl/c\" prefetch=\"mount\">\n        Go to TTL Page C\n      </Link>\n      <button onClick={() => router.reload({ only: ['foo'] })}>Reload foo</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/TtlPageB.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default ({ foo, bar }: { foo: string; bar: string }) => {\n  return (\n    <>\n      <p id=\"foo\">Foo: {foo}</p>\n      <p id=\"bar\">Bar: {bar}</p>\n      <Link href=\"/once-props/ttl/a\">Go to TTL Page A</Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/OnceProps/TtlPageC.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default ({ foo, bar }: { foo: string; bar: string }) => {\n  return (\n    <>\n      <p id=\"foo\">Foo: {foo}</p>\n      <p id=\"bar\">Bar: {bar}</p>\n      <Link href=\"/once-props/ttl/a\">Go to TTL Page A</Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageA.tsx",
    "content": "import NestedLayout from '@/Layouts/NestedLayout.jsx'\nimport SiteLayout from '@/Layouts/SiteLayout.jsx'\nimport { Link } from '@inertiajs/react'\n\nconst PageA = () => {\n  return (\n    <div>\n      <span className=\"text\">Nested Persistent Layout - Page A</span>\n      <Link href=\"/persistent-layouts/render-function/nested/page-b\">Page B</Link>\n    </div>\n  )\n}\n\nPageA.layout = (page: React.ReactNode) => {\n  return (\n    <SiteLayout>\n      <NestedLayout children={page} />\n    </SiteLayout>\n  )\n}\n\nexport default PageA\n"
  },
  {
    "path": "packages/react/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageB.tsx",
    "content": "import NestedLayout from '@/Layouts/NestedLayout.jsx'\nimport SiteLayout from '@/Layouts/SiteLayout.jsx'\nimport { Link } from '@inertiajs/react'\n\nconst PageB = () => {\n  return (\n    <div>\n      <span className=\"text\">Nested Persistent Layout - Page B</span>\n      <Link href=\"/persistent-layouts/render-function/nested/page-a\">Page A</Link>\n    </div>\n  )\n}\n\nPageB.layout = (page: React.ReactNode) => {\n  return (\n    <SiteLayout>\n      <NestedLayout children={page} />\n    </SiteLayout>\n  )\n}\n\nexport default PageB\n"
  },
  {
    "path": "packages/react/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageA.tsx",
    "content": "import SiteLayout from '@/Layouts/SiteLayout'\nimport { Link } from '@inertiajs/react'\n\nconst PageA = () => {\n  return (\n    <div>\n      <span className=\"text\">Simple Persistent Layout - Page A</span>\n      <Link href=\"/persistent-layouts/render-function/simple/page-b\">Page B</Link>\n    </div>\n  )\n}\n\nPageA.layout = (page: React.ReactNode) => <SiteLayout children={page} />\n\nexport default PageA\n"
  },
  {
    "path": "packages/react/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageB.tsx",
    "content": "import SiteLayout from '@/Layouts/SiteLayout.jsx'\nimport { Link } from '@inertiajs/react'\n\nconst PageB = () => {\n  return (\n    <div>\n      <span className=\"text\">Simple Persistent Layout - Page B</span>\n      <Link href=\"/persistent-layouts/render-function/simple/page-a\">Page A</Link>\n    </div>\n  )\n}\n\nPageB.layout = (page: React.ReactNode) => <SiteLayout children={page} />\n\nexport default PageB\n"
  },
  {
    "path": "packages/react/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.tsx",
    "content": "import NestedLayout from '@/Layouts/NestedLayout.jsx'\nimport SiteLayout from '@/Layouts/SiteLayout.jsx'\nimport { Link, usePage } from '@inertiajs/react'\n\nconst PageA = () => {\n  window._inertia_page_props = usePage().props\n\n  return (\n    <div>\n      <span className=\"text\">Nested Persistent Layout - Page A</span>\n      <Link href=\"/persistent-layouts/shorthand/nested/page-b\">Page B</Link>\n    </div>\n  )\n}\n\nPageA.layout = (page: React.ReactNode) => {\n  return (\n    <SiteLayout>\n      <NestedLayout children={page} />\n    </SiteLayout>\n  )\n}\n\nexport default PageA\n"
  },
  {
    "path": "packages/react/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.tsx",
    "content": "import NestedLayout from '@/Layouts/NestedLayout.jsx'\nimport SiteLayout from '@/Layouts/SiteLayout.jsx'\nimport { Link, usePage } from '@inertiajs/react'\n\nconst PageB = () => {\n  window._inertia_page_props = usePage().props\n\n  return (\n    <div>\n      <span className=\"text\">Nested Persistent Layout - Page B</span>\n      <Link href=\"/persistent-layouts/shorthand/nested/page-a\">Page A</Link>\n    </div>\n  )\n}\n\nPageB.layout = (page: React.ReactNode) => {\n  return (\n    <SiteLayout>\n      <NestedLayout children={page} />\n    </SiteLayout>\n  )\n}\n\nexport default PageB\n"
  },
  {
    "path": "packages/react/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.tsx",
    "content": "import SiteLayout from '@/Layouts/SiteLayout'\nimport { Link, usePage } from '@inertiajs/react'\n\nconst PageA = () => {\n  window._inertia_page_props = usePage().props\n\n  return (\n    <div>\n      <span className=\"text\">Simple Persistent Layout - Page A</span>\n      <Link href=\"/persistent-layouts/shorthand/simple/page-b\">Page B</Link>\n    </div>\n  )\n}\n\nPageA.layout = (page: React.ReactNode) => <SiteLayout children={page} />\n\nexport default PageA\n"
  },
  {
    "path": "packages/react/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.tsx",
    "content": "import SiteLayout from '@/Layouts/SiteLayout.jsx'\nimport { Link, usePage } from '@inertiajs/react'\n\nconst PageB = () => {\n  window._inertia_page_props = usePage().props\n\n  return (\n    <div>\n      <span className=\"text\">Simple Persistent Layout - Page B</span>\n      <Link href=\"/persistent-layouts/shorthand/simple/page-a\">Page A</Link>\n    </div>\n  )\n}\n\nPageB.layout = (page: React.ReactNode) => <SiteLayout children={page} />\n\nexport default PageB\n"
  },
  {
    "path": "packages/react/test-app/Pages/Poll/Hook.tsx",
    "content": "import { Link, usePoll } from '@inertiajs/react'\n\nexport default () => {\n  usePoll(500, {\n    only: ['custom_prop'],\n    onFinish() {\n      console.log('hook poll finished')\n    },\n  })\n\n  return <Link href=\"/\">Home</Link>\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Poll/HookManual.tsx",
    "content": "import { usePoll } from '@inertiajs/react'\n\nexport default () => {\n  const { start, stop } = usePoll(\n    500,\n    {\n      only: ['custom_prop'],\n      onFinish() {\n        console.log('hook poll finished')\n      },\n    },\n    {\n      autoStart: false,\n    },\n  )\n\n  return (\n    <>\n      <button onClick={start}>Start</button>\n      <button onClick={stop}>Stop</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Poll/RouterManual.tsx",
    "content": "import { router } from '@inertiajs/react'\nimport { useRef } from 'react'\n\nexport default () => {\n  const pollRef = useRef(\n    router.poll(\n      500,\n      {\n        only: ['custom_prop'],\n        onFinish() {\n          console.log('hook poll finished')\n        },\n      },\n      {\n        autoStart: false,\n      },\n    ),\n  )\n\n  return (\n    <>\n      <button onClick={pollRef.current.start}>Start</button>\n      <button onClick={pollRef.current.stop}>Stop</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Poll/UnchangedData.tsx",
    "content": "import { usePoll } from '@inertiajs/react'\nimport { useLayoutEffect, useState } from 'react'\n\nexport default () => {\n  const [replaceStateCalls, setReplaceStateCalls] = useState(0)\n  const [pollsFinished, setPollsFinished] = useState(0)\n\n  useLayoutEffect(() => {\n    const original = window.history.replaceState.bind(window.history)\n    window.history.replaceState = function (...args) {\n      setReplaceStateCalls((c) => c + 1)\n      return original(...args)\n    }\n  }, [])\n\n  usePoll(500, {\n    only: ['custom_prop'],\n    onFinish: () => setPollsFinished((c) => c + 1),\n  })\n\n  return (\n    <div>\n      <p>\n        replaceState calls: <span className=\"replaceStateCalls\">{replaceStateCalls}</span>\n      </p>\n      <p>\n        polls finished: <span className=\"pollsFinished\">{pollsFinished}</span>\n      </p>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Prefetch/AfterError.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default function AfterError() {\n  const prefetchPage = () => {\n    router.prefetch('/prefetch/swr/1', { method: 'get' }, { cacheFor: 5000 })\n  }\n\n  const visitPage = () => {\n    router.visit('/prefetch/swr/1')\n  }\n\n  const prefetchNonInertia = () => {\n    router.prefetch('/non-inertia', { method: 'get' }, { cacheFor: 5000 })\n  }\n\n  const visitNonInertia = () => {\n    router.visit('/non-inertia')\n  }\n\n  return (\n    <div>\n      <button onClick={prefetchPage}>Prefetch Page</button>\n      <button onClick={visitPage}>Visit Page</button>\n      <button onClick={prefetchNonInertia}>Prefetch Non-Inertia</button>\n      <button onClick={visitNonInertia}>Visit Non-Inertia</button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Prefetch/Form.tsx",
    "content": "import { Link, useForm } from '@inertiajs/react'\n\nexport default ({ randomValue }: { randomValue: number }) => {\n  const { post } = useForm({})\n\n  const submitToSame = () => {\n    post('/prefetch/form')\n  }\n\n  const submitToOther = () => {\n    post('/prefetch/redirect-back')\n  }\n\n  return (\n    <div>\n      <p>\n        Random Value: <span className=\"random-value\">{randomValue}</span>\n      </p>\n      <button onClick={submitToSame}>Submit to Same URL</button>\n      <button onClick={submitToOther}>Submit to Other URL</button>\n      <Link href=\"/prefetch/test-page\">Back to Test Page</Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Prefetch/Page.tsx",
    "content": "import Prefetch from '@/Layouts/Prefetch'\n\nconst Page = ({ pageNumber, lastLoaded }: { pageNumber: string; lastLoaded: number }) => {\n  return (\n    <div>\n      <div>This is page {pageNumber}</div>\n      <div>\n        Last loaded at <span id=\"last-loaded\">{lastLoaded}</span>\n      </div>\n    </div>\n  )\n}\n\nPage.layout = (page: React.ReactNode) => <Prefetch children={page} />\n\nexport default Page\n"
  },
  {
    "path": "packages/react/test-app/Pages/Prefetch/PreserveState.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default ({ page, timestamp }: { page: number; timestamp: number }) => {\n  const prefetchPage2 = () => {\n    router.prefetch('/prefetch/preserve-state', { method: 'get', data: { page: 2 } }, { cacheFor: '30s' })\n  }\n\n  const loadPage2WithoutPreserveState = () => {\n    router.get('/prefetch/preserve-state', { page: 2 }, { preserveState: false })\n  }\n\n  const loadPage2WithPreserveState = () => {\n    router.get('/prefetch/preserve-state', { page: 2 }, { preserveState: true })\n  }\n\n  return (\n    <div>\n      <div>Current Page: {page}</div>\n      <div>Timestamp: {timestamp}</div>\n\n      <h3>Prefetch:</h3>\n      <button onClick={prefetchPage2}>Prefetch Page 2</button>\n\n      <h3>Load (should use cache if prefetched):</h3>\n      <button onClick={loadPage2WithoutPreserveState}>Load Page 2 (preserveState: false)</button>\n      <button onClick={loadPage2WithPreserveState}>Load Page 2 (preserveState: true)</button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Prefetch/SWR.tsx",
    "content": "import SWRLayout from '@/Layouts/SWR'\n\nconst SWR = ({ pageNumber, lastLoaded }: { pageNumber: string; lastLoaded: number }) => {\n  return (\n    <div>\n      <div>This is page {pageNumber}</div>\n      <div>\n        Last loaded at <span id=\"last-loaded\">{lastLoaded}</span>\n      </div>\n    </div>\n  )\n}\n\nSWR.layout = (page: React.ReactNode) => <SWRLayout children={page} />\n\nexport default SWR\n"
  },
  {
    "path": "packages/react/test-app/Pages/Prefetch/Tags.tsx",
    "content": "import { Link, router, useForm } from '@inertiajs/react'\n\nexport default ({ pageNumber, lastLoaded, propType }: { pageNumber: number; lastLoaded: number; propType: string }) => {\n  const form = useForm({\n    name: '',\n  })\n\n  const flushUserTags = () => {\n    router.flushByCacheTags(propType === 'string' ? 'user' : ['user'])\n  }\n\n  const flushUserProductTags = () => {\n    router.flushByCacheTags(['user', 'product'])\n  }\n\n  const programmaticPrefetch = () => {\n    router.prefetch('/prefetch/tags/2', { method: 'get' }, { cacheTags: propType === 'string' ? 'user' : ['user'] })\n    router.prefetch(\n      '/prefetch/tags/3',\n      { method: 'get' },\n      { cacheFor: '1m', cacheTags: propType === 'string' ? 'product' : ['product'] },\n    )\n    router.prefetch(\n      '/prefetch/tags/6',\n      { method: 'get' },\n      { cacheFor: '1m' }, // No tags (untagged)\n    )\n  }\n\n  const submitWithUserInvalidation = (e: React.MouseEvent) => {\n    e.preventDefault()\n    form.post('/dump/post', {\n      invalidateCacheTags: propType === 'string' ? 'user' : ['user'],\n    })\n  }\n\n  return (\n    <div>\n      <div id=\"links\">\n        <Link href=\"/prefetch/tags/1\" prefetch=\"hover\" cacheTags={['user', 'profile']}>\n          User Page 1\n        </Link>\n        <Link href=\"/prefetch/tags/2\" prefetch=\"hover\" cacheTags={['user', 'settings']}>\n          User Page 2\n        </Link>\n        <Link href=\"/prefetch/tags/3\" prefetch=\"hover\" cacheTags={['product', 'catalog']}>\n          Product Page 3\n        </Link>\n        <Link href=\"/prefetch/tags/4\" prefetch=\"hover\" cacheTags={['product', 'details']}>\n          Product Page 4\n        </Link>\n        <Link href=\"/prefetch/tags/5\" prefetch=\"hover\" cacheTags={propType === 'string' ? 'admin' : ['admin']}>\n          Admin Page 5\n        </Link>\n        <Link href=\"/prefetch/tags/6\" prefetch=\"hover\">\n          Untagged Page 6\n        </Link>\n      </div>\n      <div id=\"controls\">\n        <button id=\"flush-user\" onClick={flushUserTags}>\n          Flush User Tags\n        </button>\n        <button id=\"flush-user-product\" onClick={flushUserProductTags}>\n          Flush User + Product Tags\n        </button>\n        <button id=\"programmatic-prefetch\" onClick={programmaticPrefetch}>\n          Programmatic Prefetch\n        </button>\n      </div>\n\n      <div id=\"form-section\">\n        <h3>Form Test</h3>\n        <form onSubmit={(e) => e.preventDefault()}>\n          <input\n            id=\"form-name\"\n            value={form.data.name}\n            onChange={(e) => form.setData('name', e.target.value)}\n            type=\"text\"\n            placeholder=\"Enter name\"\n          />\n          <button id=\"submit-invalidate-user\" onClick={submitWithUserInvalidation}>\n            Submit (Invalidate User)\n          </button>\n        </form>\n      </div>\n\n      <div>\n        <div>This is tags page {pageNumber}</div>\n        <div>\n          Last loaded at <span id=\"last-loaded\">{lastLoaded}</span>\n        </div>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Prefetch/TestPage.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div>\n      <Link href=\"/prefetch/form\" prefetch>\n        Go to Prefetch Form\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Prefetch/Wayfinder.tsx",
    "content": "import { router } from '@inertiajs/react'\nimport { useCallback, useEffect, useState } from 'react'\n\nexport default function Wayfinder() {\n  const [isPrefetched, setIsPrefetched] = useState(false)\n  const [isPrefetching, setIsPrefetching] = useState(false)\n\n  const wayfinderUrl = (): {\n    url: string\n    method: 'get'\n  } => ({\n    url: '/prefetch/swr/4',\n    method: 'get',\n  })\n\n  const checkStatus = useCallback(() => {\n    setIsPrefetched(!!router.getCached(wayfinderUrl()))\n    setIsPrefetching(!!router.getPrefetching(wayfinderUrl()))\n  }, [])\n\n  const testPrefetch = () => {\n    router.prefetch(wayfinderUrl(), {\n      onPrefetching: () => {\n        setIsPrefetching(true)\n      },\n      onPrefetched: () => {\n        setIsPrefetching(false)\n        setTimeout(checkStatus)\n      },\n    })\n  }\n\n  const testFlush = () => {\n    router.flush(wayfinderUrl())\n    checkStatus()\n  }\n\n  const flushAll = () => {\n    router.flushAll()\n    checkStatus()\n  }\n\n  useEffect(() => {\n    checkStatus()\n  }, [checkStatus])\n\n  return (\n    <div>\n      <p>\n        Is Prefetched: <span id=\"is-prefetched\">{isPrefetched.toString()}</span>\n      </p>\n      <p>\n        Is Prefetching: <span id=\"is-prefetching\">{isPrefetching.toString()}</span>\n      </p>\n\n      <button onClick={testPrefetch} id=\"test-prefetch\">\n        Test prefetch\n      </button>\n      <button onClick={testFlush} id=\"test-flush\">\n        Test flush\n      </button>\n      <button onClick={flushAll} id=\"flush-all\">\n        Flush all\n      </button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/PreserveEqualProps.tsx",
    "content": "import { config, Link } from '@inertiajs/react'\nimport { useEffect, useState } from 'react'\n\nexport default ({ nestedA, nestedB }: { nestedA: { count: number }; nestedB: { date: number } }) => {\n  const [effectACount, setEffectACount] = useState(0)\n  const [effectBCount, setEffectBCount] = useState(0)\n\n  useEffect(() => {\n    setEffectACount((count) => count + 1)\n  }, [nestedA])\n\n  useEffect(() => {\n    setEffectBCount((count) => count + 1)\n  }, [nestedB])\n\n  function enable() {\n    config.set('future.preserveEqualProps', true)\n  }\n\n  return (\n    <div>\n      <h1>Preserve Equal Props</h1>\n      <p id=\"count-a\">Count A: {nestedA.count}</p>\n      <p id=\"date-b\">Date B: {nestedB.date}</p>\n      <p id=\"effect-a\">Effect A Count: {effectACount}</p>\n      <p id=\"effect-b\">Effect B Count: {effectBCount}</p>\n      <Link method=\"post\" href=\"/preserve-equal-props/back\">\n        Submit and redirect back\n      </Link>\n      <button onClick={enable}>Enable</button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Progress.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default ({ pageNumber }: { pageNumber: string }) => {\n  return (\n    <>\n      <h1>Page {pageNumber}</h1>\n      <Link href=\"/progress/1\">Page 1</Link>\n      <Link href=\"/progress/2\">Page 2</Link>\n      <Link prefetch href=\"/progress/3\">\n        Page 3\n      </Link>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/ProgressComponent.tsx",
    "content": "import { progress } from '@inertiajs/react'\nimport { useState } from 'react'\n\ndeclare global {\n  interface Window {\n    progressTests: unknown[]\n  }\n}\n\nwindow.progressTests = []\n\nexport default () => {\n  const [logs, setLogs] = useState<string[]>([])\n\n  const log = (...args: unknown[]) => {\n    const message = args.join(' ')\n    window.progressTests.push(...args)\n    setLogs((prevLogs) => [...prevLogs, message])\n  }\n\n  const testStart = () => {\n    progress.start()\n    log('started')\n  }\n\n  const testSet25 = () => {\n    progress.set(0.25)\n    log('set 25%')\n  }\n\n  const testSet50 = () => {\n    progress.set(0.5)\n    log('set 50%')\n  }\n\n  const testSet75 = () => {\n    progress.set(0.75)\n    log('set 75%')\n  }\n\n  const testFinish = () => {\n    progress.finish()\n    log('finished')\n  }\n\n  const testReset = () => {\n    progress.reset()\n    log('reset')\n  }\n\n  const testRemove = () => {\n    progress.remove()\n    log('removed')\n  }\n\n  const testHide = () => {\n    progress.hide()\n    log('hidden')\n  }\n\n  const testReveal = () => {\n    progress.reveal()\n    log('revealed')\n  }\n\n  const testIsStarted = () => {\n    log('isStarted:', progress.isStarted())\n  }\n\n  const testGetStatus = () => {\n    log('getStatus:', progress.getStatus())\n  }\n\n  const clearLogs = () => {\n    window.progressTests = []\n    setLogs([])\n  }\n\n  return (\n    <div>\n      <h1>Progress API Test</h1>\n\n      <div>\n        <button onClick={testStart}>Start</button>\n        <button onClick={testSet25}>Set 25%</button>\n        <button onClick={testSet50}>Set 50%</button>\n        <button onClick={testSet75}>Set 75%</button>\n        <button onClick={testFinish}>Finish</button>\n      </div>\n\n      <div>\n        <button onClick={testReset}>Reset</button>\n        <button onClick={testRemove}>Remove</button>\n        <button onClick={testHide}>Hide</button>\n        <button onClick={testReveal}>Reveal</button>\n      </div>\n\n      <div>\n        <button onClick={testIsStarted}>Is Started</button>\n        <button onClick={testGetStatus}>Get Status</button>\n        <button onClick={clearLogs}>Clear</button>\n      </div>\n\n      <div>\n        Logs: <span id=\"logs\">{logs.join(', ')}</span>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Reload/Concurrent.tsx",
    "content": "import { router, usePage } from '@inertiajs/react'\n\nexport default () => {\n  const { foo, bar } = usePage<{ foo?: string; bar?: string }>().props\n\n  function reloadBothProps() {\n    router.reload({ only: ['foo'] })\n    setTimeout(() => router.reload({ only: ['bar'] }), 50)\n  }\n\n  return (\n    <div>\n      <div id=\"foo\">Foo: {foo}</div>\n      <div id=\"bar\">Bar: {bar}</div>\n\n      <button onClick={reloadBothProps}>Reload both props</button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Reload/ConcurrentWithData.tsx",
    "content": "import { router, usePage } from '@inertiajs/react'\n\nexport default () => {\n  const { foo, bar, timeframe } = usePage<{ foo?: string; bar?: string; timeframe?: string }>().props\n\n  function reloadBothPropsWithData() {\n    router.reload({ only: ['foo'], data: { timeframe: 'week' } })\n    setTimeout(() => router.reload({ only: ['bar'], data: { timeframe: 'week' } }), 50)\n  }\n\n  return (\n    <div>\n      <div id=\"foo\">Foo: {foo}</div>\n      <div id=\"bar\">Bar: {bar}</div>\n      <div id=\"timeframe\">Timeframe: {timeframe}</div>\n\n      <button onClick={reloadBothPropsWithData}>Reload both props with data</button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Remember/Components/ComponentA.tsx",
    "content": "import { useRemember } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default ({ ...props }) => {\n  const [untracked, setUntracked] = useState('')\n  const [data, setData] = useRemember({ name: '', remember: false }, 'Example/ComponentA')\n\n  return (\n    <div {...props}>\n      <span>This component uses a string 'key' for the remember functionality.</span>\n      <label>\n        Full Name\n        <input\n          type=\"text\"\n          className=\"a-name\"\n          name=\"full_name\"\n          value={data.name}\n          onChange={(e) => setData({ ...data, name: e.target.value })}\n        />\n      </label>\n      <label>\n        Remember Me\n        <input\n          type=\"checkbox\"\n          className=\"a-remember\"\n          name=\"remember\"\n          checked={data.remember}\n          onChange={(e) => setData({ ...data, remember: e.target.checked })}\n        />\n      </label>\n      <label>\n        Remember Me\n        <input\n          type=\"text\"\n          className=\"a-untracked\"\n          name=\"untracked\"\n          value={untracked}\n          onChange={(e) => setUntracked(e.target.value)}\n        />\n      </label>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Remember/Components/ComponentB.tsx",
    "content": "import { useRemember } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default ({ ...props }) => {\n  const [untracked, setUntracked] = useState('')\n\n  const [data, setData] = useRemember({ name: '', remember: false }, 'Example/ComponentB')\n\n  return (\n    <div {...props}>\n      <span>This component uses a callback-style 'key' for the remember functionality.</span>\n      <label>\n        Full Name\n        <input\n          type=\"text\"\n          className=\"b-name\"\n          name=\"full_name\"\n          value={data.name}\n          onChange={(e) => setData({ ...data, name: e.target.value })}\n        />\n      </label>\n      <label>\n        Remember Me\n        <input\n          type=\"checkbox\"\n          className=\"b-remember\"\n          name=\"remember\"\n          checked={data.remember}\n          onChange={(e) => setData({ ...data, remember: e.target.checked })}\n        />\n      </label>\n      <label>\n        Remember Me\n        <input\n          type=\"text\"\n          className=\"b-untracked\"\n          name=\"untracked\"\n          value={untracked}\n          onChange={(e) => setUntracked(e.target.value)}\n        />\n      </label>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Remember/Default.tsx",
    "content": "import { Link } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const [name, setName] = useState('')\n  const [remember, setRemember] = useState(false)\n  const [untracked, setUntracked] = useState('')\n\n  return (\n    <div>\n      <label>\n        Full Name\n        <input type=\"text\" id=\"name\" name=\"full_name\" value={name} onChange={(e) => setName(e.target.value)} />\n      </label>\n      <label>\n        Remember Me\n        <input\n          type=\"checkbox\"\n          id=\"remember\"\n          name=\"remember\"\n          checked={remember}\n          onChange={(e) => setRemember(e.target.checked)}\n        />\n      </label>\n      <label>\n        Untracked\n        <input\n          type=\"text\"\n          id=\"untracked\"\n          name=\"untracked\"\n          value={untracked}\n          onChange={(e) => setUntracked(e.target.value)}\n        />\n      </label>\n\n      <Link href=\"/dump/get\" className=\"link\">\n        Navigate away\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Remember/FormHelper/Default.tsx",
    "content": "import { Link, useForm } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const [untracked, setUntracked] = useState('')\n\n  const form = useForm({ name: 'foo', handle: 'example', remember: false })\n\n  const submit = () => {\n    form.post('/remember/form-helper/default')\n  }\n\n  return (\n    <div>\n      <label>\n        Full Name\n        <input\n          type=\"text\"\n          id=\"name\"\n          name=\"name\"\n          value={form.data.name}\n          onChange={(e) => form.setData('name', e.target.value)}\n        />\n      </label>\n      {form.errors.name && <span className=\"name_error\">{form.errors.name}</span>}\n      <label>\n        Handle\n        <input\n          type=\"text\"\n          id=\"handle\"\n          name=\"handle\"\n          value={form.data.handle}\n          onChange={(e) => form.setData('handle', e.target.value)}\n        />\n      </label>\n      {form.errors.handle && <span className=\"handle_error\">{form.errors.handle}</span>}\n      <label>\n        Remember Me\n        <input\n          type=\"checkbox\"\n          id=\"remember\"\n          name=\"remember\"\n          checked={form.data.remember}\n          onChange={(e) => form.setData('remember', e.target.checked)}\n        />\n      </label>\n      {form.errors.remember && <span className=\"remember_error\">{form.errors.remember}</span>}\n      <label>\n        Untracked\n        <input\n          type=\"text\"\n          id=\"untracked\"\n          name=\"untracked\"\n          value={untracked}\n          onChange={(e) => setUntracked(e.target.value)}\n        />\n      </label>\n\n      <button onClick={submit} className=\"submit\">\n        Submit form\n      </button>\n\n      <Link href=\"/dump/get\" className=\"link\">\n        Navigate away\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Remember/FormHelper/Password.tsx",
    "content": "import { Link, useForm } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm('password-form', {\n    username: '',\n    password: '',\n  }).dontRemember('password')\n\n  return (\n    <div>\n      <label>\n        Username\n        <input\n          type=\"text\"\n          id=\"username\"\n          value={form.data.username}\n          onChange={(e) => form.setData('username', e.target.value)}\n        />\n      </label>\n      <label>\n        Password\n        <input\n          type=\"password\"\n          id=\"password\"\n          value={form.data.password}\n          onChange={(e) => form.setData('password', e.target.value)}\n        />\n      </label>\n\n      <Link href=\"/dump/get\" className=\"link\">\n        Navigate away\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Remember/FormHelper/Remember.tsx",
    "content": "import { Link, useForm } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const form = useForm('form', { name: 'foo', handle: 'example', remember: false })\n  const [untracked, setUntracked] = useState('')\n\n  const submit = () => {\n    form.post('/remember/form-helper/remember')\n  }\n\n  const reset = () => {\n    form.reset('handle')\n    form.clearErrors('name')\n  }\n\n  return (\n    <div>\n      <label>\n        Full Name\n        <input\n          type=\"text\"\n          id=\"name\"\n          name=\"name\"\n          value={form.data.name}\n          onChange={(e) => form.setData('name', e.target.value)}\n        />\n      </label>\n      {form.errors.name && <span className=\"name_error\">{form.errors.name}</span>}\n      <label>\n        Handle\n        <input\n          type=\"text\"\n          id=\"handle\"\n          name=\"handle\"\n          value={form.data.handle}\n          onChange={(e) => form.setData('handle', e.target.value)}\n        />\n      </label>\n      {form.errors.handle && <span className=\"handle_error\">{form.errors.handle}</span>}\n      <label>\n        Remember Me\n        <input\n          type=\"checkbox\"\n          id=\"remember\"\n          name=\"remember\"\n          checked={form.data.remember}\n          onChange={(e) => form.setData('remember', e.target.checked)}\n        />\n      </label>\n      {form.errors.remember && <span className=\"remember_error\">{form.errors.remember}</span>}\n      <label>\n        Untracked\n        <input\n          type=\"text\"\n          id=\"untracked\"\n          name=\"untracked\"\n          value={untracked}\n          onChange={(e) => setUntracked(e.target.value)}\n        />\n      </label>\n\n      <button onClick={submit} className=\"submit\">\n        Submit form\n      </button>\n      <button onClick={reset} className=\"reset-one\">\n        Reset one field & error\n      </button>\n\n      <Link href=\"/dump/get\" className=\"link\">\n        Navigate away\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Remember/MultipleComponents.tsx",
    "content": "import { Link, useRemember } from '@inertiajs/react'\nimport { useState } from 'react'\nimport ComponentA from './Components/ComponentA'\nimport ComponentB from './Components/ComponentB'\n\nexport default () => {\n  const [untracked, setUntracked] = useState('')\n\n  const [form, setForm] = useRemember({ name: '', remember: false })\n\n  return (\n    <div>\n      <label>\n        Full Name\n        <input\n          type=\"text\"\n          id=\"name\"\n          name=\"full_name\"\n          value={form.name}\n          onChange={(e) => setForm({ ...form, name: e.target.value })}\n        />\n      </label>\n      <label>\n        Remember Me\n        <input\n          type=\"checkbox\"\n          id=\"remember\"\n          name=\"remember\"\n          checked={form.remember}\n          onChange={(e) => setForm({ ...form, remember: e.target.checked })}\n        />\n      </label>\n      <label>\n        Untracked\n        <input\n          type=\"text\"\n          id=\"untracked\"\n          name=\"untracked\"\n          value={untracked}\n          onChange={(e) => setUntracked(e.target.value)}\n        />\n      </label>\n\n      <ComponentA className=\"component-a\" />\n      <ComponentB className=\"component-b\" />\n\n      <Link href=\"/dump/get\" className=\"link\">\n        Navigate away\n      </Link>\n      <a href=\"/non-inertia\" className=\"off-site\">\n        Navigate off-site\n      </a>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Remember/Object.tsx",
    "content": "import { Link, useRemember } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const [untracked, setUntracked] = useState('')\n\n  const [form, setForm] = useRemember({ name: '', remember: false })\n\n  return (\n    <div>\n      <label>\n        Full Name\n        <input\n          type=\"text\"\n          id=\"name\"\n          name=\"full_name\"\n          value={form.name}\n          onChange={(e) => setForm({ ...form, name: e.target.value })}\n        />\n      </label>\n      <label>\n        Remember Me\n        <input\n          type=\"checkbox\"\n          id=\"remember\"\n          name=\"remember\"\n          checked={form.remember}\n          onChange={(e) => setForm({ ...form, remember: e.target.checked })}\n        />\n      </label>\n      <label>\n        Untracked\n        <input\n          type=\"text\"\n          id=\"untracked\"\n          name=\"untracked\"\n          value={untracked}\n          onChange={(e) => setUntracked(e.target.value)}\n        />\n      </label>\n\n      <Link href=\"/dump/get\" className=\"link\">\n        Navigate away\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Remember/Router.tsx",
    "content": "import { router } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default () => {\n  const [foo, setFoo] = useState('-')\n  const [bar, setBar] = useState(0)\n\n  function remember() {\n    router.remember('foo')\n    router.remember(42, 'bar')\n  }\n\n  function restore() {\n    setFoo(router.restore() ?? '-')\n    setBar(router.restore('bar') ?? 0)\n  }\n\n  function restoreTyped() {\n    const foo = router.restore<string>()\n    const bar = router.restore<number>('bar')\n\n    foo?.startsWith('f')\n    bar?.toFixed(2)\n\n    setFoo(foo ?? '-')\n    setBar(bar ?? 0)\n\n    // @ts-expect-error - Testing type safety\n    foo?.toFixed(2)\n    // @ts-expect-error - Testing type safety\n    bar?.startsWith('b')\n  }\n\n  return (\n    <div>\n      <p>Foo: {foo}</p>\n      <p>Bar: {bar}</p>\n      <button onClick={remember}>Remember</button>\n      <button onClick={restore}>Restore</button>\n      <button onClick={restoreTyped}>Restore Typed</button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/SSR/Page1.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default ({ user, items, count }: { user: { name: string; email: string }; items: string[]; count: number }) => (\n  <div>\n    <h1 data-testid=\"ssr-title\">SSR Page 1</h1>\n\n    <div data-testid=\"user-info\">\n      <p data-testid=\"user-name\">Name: {user.name}</p>\n      <p data-testid=\"user-email\">Email: {user.email}</p>\n    </div>\n\n    <ul data-testid=\"items-list\">\n      {items.map((item) => (\n        <li key={item} data-testid=\"item\">\n          {item}\n        </li>\n      ))}\n    </ul>\n\n    <p data-testid=\"count\">Count: {count}</p>\n\n    <Link href=\"/ssr/page2\" data-testid=\"navigate-link\">\n      Navigate to another page\n    </Link>\n  </div>\n)\n"
  },
  {
    "path": "packages/react/test-app/Pages/SSR/Page2.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nexport default ({ navigatedTo }: { navigatedTo: boolean }) => (\n  <div>\n    <h1 data-testid=\"ssr-title\">SSR Page 2</h1>\n    <p data-testid=\"navigated-status\">Navigated: {String(navigatedTo)}</p>\n\n    <Link href=\"/ssr/page1\" data-testid=\"back-link\">\n      Go back\n    </Link>\n  </div>\n)\n"
  },
  {
    "path": "packages/react/test-app/Pages/SSR/PageWithScriptElement.tsx",
    "content": "export default ({ message }: { message: string }) => (\n  <div>\n    <h1 data-testid=\"ssr-title\">SSR Page With Script Element</h1>\n    <p data-testid=\"message\">{message}</p>\n  </div>\n)\n"
  },
  {
    "path": "packages/react/test-app/Pages/ScrollAfterRender.tsx",
    "content": "import { Link } from '@inertiajs/react'\n\nlet originalScrollTo: typeof window.scrollTo | null = null\n\nexport default ({ page }: { page: number }) => {\n  // Patch scrollTo to log synchronously when it's called (not when the scroll event fires)\n  if (!originalScrollTo) {\n    originalScrollTo = window.scrollTo.bind(window)\n\n    window.scrollTo = ((xOrOptions: number | ScrollToOptions, y?: number) => {\n      const firstArgIsNumber = typeof xOrOptions === 'number'\n      const scrollY = firstArgIsNumber ? y : (xOrOptions?.top ?? 0)\n\n      console.log('ScrollY', scrollY)\n\n      return firstArgIsNumber ? originalScrollTo!(xOrOptions, y!) : originalScrollTo!(xOrOptions)\n    }) as typeof window.scrollTo\n  } else {\n    console.log('Render')\n  }\n\n  return (\n    <>\n      <h1 style={{ fontSize: '40px' }}>Article Header</h1>\n      <h2 style={{ fontSize: '40px' }}>Page {page}</h2>\n      <article style={{ fontSize: '20px', maxWidth: '500px' }}>\n        <p>\n          Sunt culpa sit sunt enim aliquip. Esse ea ea quis voluptate. Enim consectetur aliqua ex ex magna cupidatat id\n          minim sit elit.\n        </p>\n        <Link\n          href={`/scroll-after-render/${page + 1}`}\n          style={{ display: 'block', marginTop: '20px' }}\n          onBefore={() => window.scrollTo(0, 100)}\n        >\n          Go to page {page + 1}\n        </Link>\n        {Array(500).map(() => (\n          <div>\n            <p>\n              Sunt culpa sit sunt enim aliquip. Esse ea ea quis voluptate. Enim consectetur aliqua ex ex magna cupidatat\n              id minim sit elit. Amet pariatur occaecat pariatur duis eiusmod dolore magna. Et commodo cupidatat in\n              commodo elit cupidatat minim qui id non enim ad. Culpa aliquip ad Lorem sit consectetur ullamco culpa duis\n              nisi et fugiat mollit eiusmod. Laboris voluptate veniam consequat proident in nulla irure velit.\n            </p>\n\n            <p>\n              Sit sint laboris sunt eiusmod ipsum laborum eiusmod amet commodo exercitation in duis magna. Proident sunt\n              minim in elit qui. Id pariatur commodo fugiat excepteur in deserunt Lorem ipsum occaecat est. Excepteur\n              sit tempor ipsum ex officia veniam enim amet velit fugiat mollit cillum. Incididunt aliqua nulla id\n              occaecat nulla. Non ea ad est occaecat deserunt officia qui commodo exercitation.\n            </p>\n\n            <p>\n              Voluptate laborum quis aliqua ullamco magna amet ullamco laborum qui cillum eu. Dolore dolore aliqua\n              proident proident sunt ipsum in. Enim velit dolore labore dolor quis incididunt duis culpa Lorem. Eu\n              adipisicing non elit fugiat voluptate labore ipsum dolore consectetur commodo. Et in et cillum duis\n              consequat quis ex eu commodo. Eiusmod aliqua excepteur consectetur eiusmod aute et consectetur sit\n              pariatur dolore qui officia pariatur.\n            </p>\n\n            <p>\n              Non sunt eu mollit qui reprehenderit. Aute culpa anim voluptate do in esse duis laborum ad dolore. Ullamco\n              nisi in nostrud officia do. Duis pariatur officia id duis. Deserunt ad incididunt est sint consectetur\n              reprehenderit mollit est Lorem ea pariatur anim dolor adipisicing. Nostrud irure magna nostrud laboris\n              aute sunt veniam laboris veniam incididunt sit. Nulla proident ad aliqua fugiat culpa sunt est in dolor\n              velit ad irure nulla.\n            </p>\n\n            <p>\n              Do aute laborum deserunt non laborum voluptate voluptate. Anim ut laborum magna sunt cupidatat irure.\n              Cupidatat fugiat minim sint cillum laborum excepteur irure id est irure ad occaecat adipisicing enim.\n              Deserunt nulla anim proident velit irure nostrud est est reprehenderit consequat pariatur qui. Fugiat\n              Lorem sint eu laborum minim pariatur cillum mollit nulla consequat ullamco ex. Ex consectetur ad ut irure\n              fugiat occaecat aliqua exercitation cillum ipsum anim dolore tempor.\n            </p>\n\n            <p>\n              Adipisicing consequat irure fugiat Lorem deserunt aliquip do cupidatat. Lorem labore elit ex qui nostrud\n              qui cillum sunt adipisicing occaecat. Sunt nostrud amet amet cupidatat fugiat Lorem quis nulla id cillum\n              esse eu. Ullamco aliqua dolore irure amet mollit anim velit dolore.\n            </p>\n\n            <p>\n              Veniam cupidatat ipsum ea officia ipsum nisi laborum culpa qui dolore. Aliqua Lorem nisi labore ea velit\n              aliquip irure excepteur eu. Laboris proident duis non labore sunt quis aute tempor laboris enim anim\n              eiusmod.\n            </p>\n\n            <p>\n              Minim proident ut aliqua ea ut culpa fugiat ullamco nisi esse nostrud reprehenderit id. Id id ullamco\n              velit anim nisi magna Lorem tempor. Et veniam occaecat ut labore consequat fugiat duis.\n            </p>\n\n            <p>\n              Adipisicing ea consectetur adipisicing aute eu pariatur enim labore consequat occaecat consectetur minim\n              nisi. Cillum commodo sunt labore reprehenderit. Duis esse excepteur magna tempor eiusmod exercitation\n              Lorem reprehenderit excepteur pariatur. Esse cupidatat occaecat magna do aliquip Lorem. Consectetur\n              adipisicing consequat dolore nostrud esse eu cillum id commodo duis. Aliquip dolor cillum cupidatat\n              fugiat.\n            </p>\n\n            <p>\n              Ex eiusmod id est laborum sunt ex ea aute adipisicing ad magna deserunt duis. Nostrud velit dolore id\n              commodo quis enim fugiat. Sint non quis consectetur voluptate aliqua dolore nulla. Irure sit reprehenderit\n              sint laboris non elit. Duis minim nisi esse dolor. Sit ex in consequat non occaecat commodo irure et.\n              Commodo qui ipsum Lorem magna consequat consequat et minim eiusmod Lorem eiusmod cupidatat voluptate.\n            </p>\n          </div>\n        ))}\n      </article>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/ScrollRegionPreserveUrl.tsx",
    "content": "import { router } from '@inertiajs/react'\nimport { useRef } from 'react'\n\nexport default ({ page }: { page: number }) => {\n  const scrollIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null)\n\n  const startScrollingAndNavigate = () => {\n    const container = document.getElementById('scroll-container')!\n    const nextPage = page === 1 ? 2 : 1\n\n    // Start continuous scrolling\n    scrollIntervalRef.current = setInterval(() => {\n      container.scrollTop += 10\n    }, 10)\n\n    // After 150ms of scrolling, navigate to the other page\n    setTimeout(() => {\n      router.visit(`/scroll-region-preserve-url/${nextPage}`, {\n        preserveScroll: true,\n        preserveState: true,\n        preserveUrl: true,\n        onSuccess: () => {\n          // Stop scrolling after navigation\n          if (scrollIntervalRef.current) {\n            clearInterval(scrollIntervalRef.current)\n            scrollIntervalRef.current = null\n          }\n        },\n      })\n    }, 150)\n  }\n\n  return (\n    <div\n      scroll-region=\"\"\n      id=\"scroll-container\"\n      style={{ height: '300px', overflowY: 'auto', border: '1px solid #ccc' }}\n    >\n      <div style={{ padding: '10px' }}>\n        <div className=\"page-number\">Page: {page}</div>\n        <button id=\"scroll-and-navigate\" onClick={startScrollingAndNavigate}>\n          Start scrolling and navigate\n        </button>\n        {Array.from({ length: 50 }, (_, i) => (\n          <div key={i} style={{ padding: '20px', borderBottom: '1px solid #eee' }}>\n            Item {i + 1}\n          </div>\n        ))}\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/ScrollSmooth.tsx",
    "content": "import { Link } from '@inertiajs/react'\nimport { useEffect } from 'react'\n\nexport default ({ page }: { page: 'long' | 'short' }) => {\n  useEffect(() => {\n    document.documentElement.style.scrollBehavior = 'smooth'\n    return () => {\n      document.documentElement.style.scrollBehavior = ''\n    }\n  }, [])\n\n  return (\n    <div>\n      <h1>{page === 'long' ? 'Long Page' : 'Short Page'}</h1>\n\n      <div style={{ height: page === 'long' ? '2000px' : '100px' }}></div>\n\n      {page === 'long' ? (\n        <Link href=\"/scroll-smooth/short\">Go to Short Page</Link>\n      ) : (\n        <Link href=\"/scroll-smooth/long\">Go to Long Page</Link>\n      )}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/ScrollableParent.tsx",
    "content": "import { getScrollableParent } from '@inertiajs/core'\nimport { useEffect, useRef, useState } from 'react'\n\nexport default () => {\n  const overflowXHidden = useRef<HTMLDivElement>(null)\n  const overflowXScroll = useRef<HTMLDivElement>(null)\n  const overflowYAuto = useRef<HTMLDivElement>(null)\n  const overflowYAutoNoHeight = useRef<HTMLDivElement>(null)\n  const overflowXScrollOverflowYHidden = useRef<HTMLDivElement>(null)\n  const horizontalScrollCalc = useRef<HTMLDivElement>(null)\n  const verticalScrollMaxHeight = useRef<HTMLDivElement>(null)\n  const nestedScroll = useRef<HTMLDivElement>(null)\n  const overflowAutoNoConstraints = useRef<HTMLDivElement>(null)\n  const flexHorizontalCarousel = useRef<HTMLDivElement>(null)\n  const coercedAutoNoConstraint = useRef<HTMLDivElement>(null)\n  const displayContents = useRef<HTMLDivElement>(null)\n  const overflowClip = useRef<HTMLDivElement>(null)\n  const overflowOverlay = useRef<HTMLDivElement>(null)\n  const inlineWidthStyle = useRef<HTMLDivElement>(null)\n  const bothScrollDirections = useRef<HTMLDivElement>(null)\n  const overflowYAutoOverflowXVisible = useRef<HTMLDivElement>(null)\n  const overflowYAutoOverflowXClip = useRef<HTMLDivElement>(null)\n  const overflowXAutoOverflowYVisible = useRef<HTMLDivElement>(null)\n  const overflowXAutoOverflowYClip = useRef<HTMLDivElement>(null)\n  const overflowYAutoOverflowXHidden = useRef<HTMLDivElement>(null)\n  const overflowXAutoOverflowYHidden = useRef<HTMLDivElement>(null)\n\n  const [results, setResults] = useState<Record<string, HTMLElement | null>>({})\n\n  useEffect(() => {\n    const newResults: Record<string, HTMLElement | null> = {}\n\n    Object.entries({\n      overflowXHidden,\n      overflowXScroll,\n      overflowYAuto,\n      overflowYAutoNoHeight,\n      overflowXScrollOverflowYHidden,\n      horizontalScrollCalc,\n      verticalScrollMaxHeight,\n      nestedScroll,\n      overflowAutoNoConstraints,\n      flexHorizontalCarousel,\n      coercedAutoNoConstraint,\n      displayContents,\n      overflowClip,\n      overflowOverlay,\n      inlineWidthStyle,\n      bothScrollDirections,\n      overflowYAutoOverflowXVisible,\n      overflowYAutoOverflowXClip,\n      overflowXAutoOverflowYVisible,\n      overflowXAutoOverflowYClip,\n      overflowYAutoOverflowXHidden,\n      overflowXAutoOverflowYHidden,\n    }).forEach(([key, ref]) => {\n      newResults[key] = getScrollableParent(ref.current)\n    })\n\n    setResults(newResults)\n  }, [])\n\n  return (\n    <div style={{ padding: '20px' }}>\n      <h1>ScrollableParent Tests</h1>\n\n      <div style={{ display: 'grid', gap: '20px', marginTop: '20px' }}>\n        {/* overflow-x: hidden */}\n        <div>\n          <h3>overflow-x: hidden</h3>\n          <div style={{ overflowX: 'hidden', border: '2px solid red', padding: '10px' }}>\n            <div ref={overflowXHidden} data-testid=\"overflow-x-hidden\">\n              Test\n            </div>\n          </div>\n          <p data-testid=\"result-overflow-x-hidden\">{results.overflowXHidden?.tagName || 'null'}</p>\n        </div>\n\n        {/* overflow-x: scroll */}\n        <div>\n          <h3>overflow-x: scroll</h3>\n          <div\n            style={{ overflowX: 'scroll', width: '300px', border: '2px solid red', padding: '10px' }}\n            data-testid=\"scroll-container-x\"\n          >\n            <div ref={overflowXScroll} data-testid=\"overflow-x-scroll\" style={{ width: '600px' }}>\n              Wide content\n            </div>\n          </div>\n          <p data-testid=\"result-overflow-x-scroll\">{results.overflowXScroll?.dataset?.testid || 'null'}</p>\n        </div>\n\n        {/* overflow-y: auto with height */}\n        <div>\n          <h3>overflow-y: auto + height</h3>\n          <div\n            style={{ overflowY: 'auto', height: '100px', border: '2px solid red', padding: '10px' }}\n            data-testid=\"scroll-container-y\"\n          >\n            <div ref={overflowYAuto} data-testid=\"overflow-y-auto\">\n              <p>Content</p>\n              <p>Content</p>\n              <p>Content</p>\n            </div>\n          </div>\n          <p data-testid=\"result-overflow-y-auto\">{results.overflowYAuto?.dataset?.testid || 'null'}</p>\n        </div>\n\n        {/* overflow-y: auto no height */}\n        <div>\n          <h3>overflow-y: auto (no height)</h3>\n          <div style={{ overflowY: 'auto', border: '2px solid red', padding: '10px' }}>\n            <div ref={overflowYAutoNoHeight} data-testid=\"overflow-y-auto-no-height\">\n              Content\n            </div>\n          </div>\n          <p data-testid=\"result-overflow-y-auto-no-height\">{results.overflowYAutoNoHeight?.tagName || 'null'}</p>\n        </div>\n\n        {/* overflow-x: scroll, overflow-y: hidden */}\n        <div>\n          <h3>overflow-x: scroll, overflow-y: hidden</h3>\n          <div\n            style={{\n              overflowX: 'scroll',\n              overflowY: 'hidden',\n              width: '300px',\n              border: '2px solid red',\n              padding: '10px',\n            }}\n            data-testid=\"scroll-container-x-y-hidden\"\n          >\n            <div\n              ref={overflowXScrollOverflowYHidden}\n              data-testid=\"overflow-x-scroll-y-hidden\"\n              style={{ width: '600px' }}\n            >\n              Wide content\n            </div>\n          </div>\n          <p data-testid=\"result-overflow-x-scroll-y-hidden\">\n            {results.overflowXScrollOverflowYHidden?.dataset?.testid || 'null'}\n          </p>\n        </div>\n\n        {/* overflow-x: scroll + max-width */}\n        <div>\n          <h3>overflow-x: scroll + max-width</h3>\n          <div\n            style={{ overflowX: 'scroll', maxWidth: '300px', border: '2px solid red', padding: '10px' }}\n            data-testid=\"scroll-container-max-width\"\n          >\n            <div ref={horizontalScrollCalc} data-testid=\"horizontal-scroll-calc\" style={{ width: '600px' }}>\n              Wide content\n            </div>\n          </div>\n          <p data-testid=\"result-horizontal-scroll-calc\">{results.horizontalScrollCalc?.dataset?.testid || 'null'}</p>\n        </div>\n\n        {/* overflow-y: auto + max-height */}\n        <div>\n          <h3>overflow-y: auto + max-height</h3>\n          <div\n            style={{ overflowY: 'auto', maxHeight: '100px', border: '2px solid red', padding: '10px' }}\n            data-testid=\"scroll-container-max-height\"\n          >\n            <div ref={verticalScrollMaxHeight} data-testid=\"vertical-scroll-max-height\">\n              <p>Content</p>\n              <p>Content</p>\n              <p>Content</p>\n            </div>\n          </div>\n          <p data-testid=\"result-vertical-scroll-max-height\">\n            {results.verticalScrollMaxHeight?.dataset?.testid || 'null'}\n          </p>\n        </div>\n\n        {/* Nested containers */}\n        <div>\n          <h3>Nested containers</h3>\n          <div\n            style={{ overflowY: 'auto', height: '200px', border: '2px solid red', padding: '10px' }}\n            data-testid=\"outer-scroll\"\n          >\n            <p>Outer</p>\n            <div\n              style={{ overflowY: 'auto', height: '100px', border: '2px solid blue', padding: '10px' }}\n              data-testid=\"inner-scroll\"\n            >\n              <div ref={nestedScroll} data-testid=\"nested-scroll\">\n                <p>Content</p>\n                <p>Content</p>\n                <p>Content</p>\n                <p>Content</p>\n                <p>Content</p>\n              </div>\n            </div>\n          </div>\n          <p data-testid=\"result-nested-scroll\">{results.nestedScroll?.dataset?.testid || 'null'}</p>\n        </div>\n\n        {/* overflow: auto (no constraints) */}\n        <div>\n          <h3>overflow: auto (no constraints)</h3>\n          <div style={{ overflow: 'auto', border: '2px solid red', padding: '10px' }}>\n            <div ref={overflowAutoNoConstraints} data-testid=\"overflow-auto-no-constraints\">\n              Content\n            </div>\n          </div>\n          <p data-testid=\"result-overflow-auto-no-constraints\">\n            {results.overflowAutoNoConstraints?.tagName || 'null'}\n          </p>\n        </div>\n\n        {/* Flex carousel */}\n        <div>\n          <h3>Flex horizontal carousel</h3>\n          <div\n            style={{\n              overflowX: 'scroll',\n              display: 'flex',\n              gap: '10px',\n              width: '300px',\n              border: '2px solid red',\n              padding: '10px',\n            }}\n            data-testid=\"flex-carousel\"\n          >\n            <div\n              ref={flexHorizontalCarousel}\n              data-testid=\"flex-horizontal-carousel\"\n              style={{ minWidth: '150px', height: '50px', background: 'lightblue' }}\n            >\n              Item\n            </div>\n            <div style={{ minWidth: '150px', height: '50px', background: 'lightgreen' }}>Item</div>\n            <div style={{ minWidth: '150px', height: '50px', background: 'lightcoral' }}>Item</div>\n          </div>\n          <p data-testid=\"result-flex-horizontal-carousel\">\n            {results.flexHorizontalCarousel?.dataset?.testid || 'null'}\n          </p>\n        </div>\n\n        {/* Coerced auto */}\n        <div>\n          <h3>overflow-x: scroll (overflow-y coerced)</h3>\n          <div\n            style={{ overflowX: 'scroll', display: 'flex', width: '300px', border: '2px solid red', padding: '10px' }}\n            data-testid=\"coerced-auto\"\n          >\n            <div ref={coercedAutoNoConstraint} data-testid=\"coerced-auto-no-constraint\" style={{ minWidth: '600px' }}>\n              Wide\n            </div>\n          </div>\n          <p data-testid=\"result-coerced-auto-no-constraint\">\n            {results.coercedAutoNoConstraint?.dataset?.testid || 'null'}\n          </p>\n        </div>\n\n        {/* display: contents */}\n        <div>\n          <h3>display: contents (skip parent)</h3>\n          <div\n            style={{ overflowY: 'auto', height: '100px', border: '2px solid red', padding: '10px' }}\n            data-testid=\"scroll-container-skip-contents\"\n          >\n            <div style={{ display: 'contents' }}>\n              <div ref={displayContents} data-testid=\"display-contents\">\n                <p>Content</p>\n                <p>Content</p>\n                <p>Content</p>\n                <p>Content</p>\n              </div>\n            </div>\n          </div>\n          <p data-testid=\"result-display-contents\">{results.displayContents?.dataset?.testid || 'null'}</p>\n        </div>\n\n        {/* overflow: clip */}\n        <div>\n          <h3>overflow: clip</h3>\n          <div style={{ overflow: 'clip', height: '100px', border: '2px solid red', padding: '10px' }}>\n            <div ref={overflowClip} data-testid=\"overflow-clip\">\n              <p>Content</p>\n              <p>Content</p>\n            </div>\n          </div>\n          <p data-testid=\"result-overflow-clip\">{results.overflowClip?.tagName || 'null'}</p>\n        </div>\n\n        {/* overflow: overlay */}\n        <div>\n          <h3>overflow: overlay</h3>\n          <div\n            style={{ overflow: 'overlay', height: '100px', border: '2px solid red', padding: '10px' }}\n            data-testid=\"scroll-container-overlay\"\n          >\n            <div ref={overflowOverlay} data-testid=\"overflow-overlay\">\n              <p>Content</p>\n              <p>Content</p>\n              <p>Content</p>\n              <p>Content</p>\n            </div>\n          </div>\n          <p data-testid=\"result-overflow-overlay\">{results.overflowOverlay?.dataset?.testid || 'null'}</p>\n        </div>\n\n        {/* Inline width */}\n        <div>\n          <h3>overflow-x: auto + inline width</h3>\n          <div\n            style={{ overflowX: 'auto', width: '300px', border: '2px solid red', padding: '10px' }}\n            data-testid=\"inline-width-container\"\n          >\n            <div ref={inlineWidthStyle} data-testid=\"inline-width-style\" style={{ width: '600px' }}>\n              Wide\n            </div>\n          </div>\n          <p data-testid=\"result-inline-width-style\">{results.inlineWidthStyle?.dataset?.testid || 'null'}</p>\n        </div>\n\n        {/* Both scroll */}\n        <div>\n          <h3>overflow: scroll (both)</h3>\n          <div\n            style={{\n              overflowX: 'scroll',\n              overflowY: 'scroll',\n              width: '300px',\n              height: '100px',\n              border: '2px solid red',\n              padding: '10px',\n            }}\n            data-testid=\"both-scroll\"\n          >\n            <div ref={bothScrollDirections} data-testid=\"both-scroll-directions\" style={{ width: '600px' }}>\n              <p>Wide and tall</p>\n              <p>Content</p>\n              <p>Content</p>\n            </div>\n          </div>\n          <p data-testid=\"result-both-scroll-directions\">{results.bothScrollDirections?.dataset?.testid || 'null'}</p>\n        </div>\n\n        {/* overflow-y: auto + overflow-x: visible */}\n        <div>\n          <h3>overflow-y: auto + overflow-x: visible</h3>\n          <div\n            style={{\n              overflowY: 'auto',\n              overflowX: 'visible',\n              height: '100px',\n              border: '2px solid red',\n              padding: '10px',\n            }}\n            data-testid=\"overflow-y-auto-x-visible\"\n          >\n            <div ref={overflowYAutoOverflowXVisible} data-testid=\"overflow-y-auto-overflow-x-visible\">\n              <p>Content</p>\n              <p>Content</p>\n              <p>Content</p>\n            </div>\n          </div>\n          <p data-testid=\"result-overflow-y-auto-overflow-x-visible\">\n            {results.overflowYAutoOverflowXVisible?.dataset?.testid || 'null'}\n          </p>\n        </div>\n\n        {/* overflow-y: auto + overflow-x: clip */}\n        <div>\n          <h3>overflow-y: auto + overflow-x: clip</h3>\n          <div\n            style={{ overflowY: 'auto', overflowX: 'clip', height: '100px', border: '2px solid red', padding: '10px' }}\n            data-testid=\"overflow-y-auto-x-clip\"\n          >\n            <div ref={overflowYAutoOverflowXClip} data-testid=\"overflow-y-auto-overflow-x-clip\">\n              <p>Content</p>\n              <p>Content</p>\n              <p>Content</p>\n            </div>\n          </div>\n          <p data-testid=\"result-overflow-y-auto-overflow-x-clip\">\n            {results.overflowYAutoOverflowXClip?.dataset?.testid || 'null'}\n          </p>\n        </div>\n\n        {/* overflow-x: auto + overflow-y: visible */}\n        <div>\n          <h3>overflow-x: auto + overflow-y: visible</h3>\n          <div\n            style={{\n              overflowX: 'auto',\n              overflowY: 'visible',\n              width: '300px',\n              border: '2px solid red',\n              padding: '10px',\n            }}\n            data-testid=\"overflow-x-auto-y-visible\"\n          >\n            <div\n              ref={overflowXAutoOverflowYVisible}\n              data-testid=\"overflow-x-auto-overflow-y-visible\"\n              style={{ width: '600px' }}\n            >\n              Wide content\n            </div>\n          </div>\n          <p data-testid=\"result-overflow-x-auto-overflow-y-visible\">\n            {results.overflowXAutoOverflowYVisible?.dataset?.testid || 'null'}\n          </p>\n        </div>\n\n        {/* overflow-x: auto + overflow-y: clip */}\n        <div>\n          <h3>overflow-x: auto + overflow-y: clip</h3>\n          <div\n            style={{ overflowX: 'auto', overflowY: 'clip', width: '300px', border: '2px solid red', padding: '10px' }}\n            data-testid=\"overflow-x-auto-y-clip\"\n          >\n            <div\n              ref={overflowXAutoOverflowYClip}\n              data-testid=\"overflow-x-auto-overflow-y-clip\"\n              style={{ width: '600px' }}\n            >\n              Wide content\n            </div>\n          </div>\n          <p data-testid=\"result-overflow-x-auto-overflow-y-clip\">\n            {results.overflowXAutoOverflowYClip?.dataset?.testid || 'null'}\n          </p>\n        </div>\n\n        {/* overflow-y: auto + overflow-x: hidden (no height) */}\n        <div>\n          <h3>overflow-y: auto + overflow-x: hidden (no height)</h3>\n          <div style={{ overflowY: 'auto', overflowX: 'hidden', border: '2px solid red', padding: '10px' }}>\n            <div ref={overflowYAutoOverflowXHidden} data-testid=\"overflow-y-auto-overflow-x-hidden\">\n              Content\n            </div>\n          </div>\n          <p data-testid=\"result-overflow-y-auto-overflow-x-hidden\">\n            {results.overflowYAutoOverflowXHidden?.tagName || 'null'}\n          </p>\n        </div>\n\n        {/* overflow-x: auto + overflow-y: hidden (no width) */}\n        <div>\n          <h3>overflow-x: auto + overflow-y: hidden (no width)</h3>\n          <div style={{ overflowX: 'auto', overflowY: 'hidden', border: '2px solid red', padding: '10px' }}>\n            <div ref={overflowXAutoOverflowYHidden} data-testid=\"overflow-x-auto-overflow-y-hidden\">\n              Content\n            </div>\n          </div>\n          <p data-testid=\"result-overflow-x-auto-overflow-y-hidden\">\n            {results.overflowXAutoOverflowYHidden?.tagName || 'null'}\n          </p>\n        </div>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/TypeScriptCreateInertiaApp.ts",
    "content": "// This file is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { type ResolvedComponent, createInertiaApp } from '@inertiajs/react'\n\ndeclare module '@inertiajs/core' {\n  export interface InertiaConfig {\n    sharedPageProps: {\n      auth: { user: { name: string } | null }\n    }\n  }\n}\n\n// createInertiaApp setup should include shared props without explicit generic\ncreateInertiaApp({\n  resolve: (name) => {\n    const pages = import.meta.glob<ResolvedComponent>('./Pages/**/*.tsx', { eager: true })\n    return pages[`./Pages/${name}.tsx`]\n  },\n  setup({ props }) {\n    console.log(props.initialPage.props.auth.user?.name)\n    // @ts-expect-error - 'email' does not exist on user\n    console.log(props.initialPage.props.auth.user?.email)\n  },\n})\n"
  },
  {
    "path": "packages/react/test-app/Pages/TypeScriptFlash.tsx",
    "content": "// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { router, usePage } from '@inertiajs/react'\n\ndeclare module '@inertiajs/core' {\n  export interface InertiaConfig {\n    flashDataType: {\n      toast?: { type: 'success' | 'error'; message: string }\n    }\n  }\n}\n\nexport default function TypeScriptFlash() {\n  const page = usePage()\n\n  // page.flash is always an object\n  const flash = page.flash\n  const toast = page.flash.toast\n  const toastMessage = page.flash.toast?.message\n  const toastType = page.flash.toast?.type\n\n  // @ts-expect-error - 'message' does not exist on flash (it's on toast)\n  const flashMessage = page.flash.message\n\n  // router.flash with object\n  router.flash({ toast: { type: 'success', message: 'Hello' } })\n\n  // router.flash with key-value\n  router.flash('toast', { type: 'error', message: 'Oops' })\n\n  // router.flash with callback\n  router.flash((current) => ({\n    ...current,\n    toast: { type: 'success', message: 'Updated' },\n  }))\n\n  // Client-side visit with flash\n  router.replace({\n    flash: { toast: { type: 'success', message: 'Replaced' } },\n    onFlash: (flash) => {\n      console.log(flash.toast?.message)\n    },\n  })\n\n  // Client-side visit with flash callback\n  router.push({\n    flash: (current) => ({\n      ...current,\n      toast: { type: 'error', message: 'Error' },\n    }),\n  })\n\n  // Scoped flash typing with generic (for page/section-specific flash)\n  router.flash<{ paymentError: string }>({ paymentError: 'Card declined' })\n\n  // @ts-expect-error - 'paymentError' should be string, not number\n  router.flash<{ paymentError: string }>({ paymentError: 123 })\n\n  console.log({\n    flash,\n    toast,\n    toastMessage,\n    toastType,\n    flashMessage,\n  })\n\n  return null\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/TypeScriptProps.tsx",
    "content": "// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { router, usePage } from '@inertiajs/react'\n\ndeclare module '@inertiajs/core' {\n  export interface InertiaConfig {\n    sharedPageProps: {\n      auth: { user: { name: string } | null }\n    }\n  }\n}\n\ntype PageProps = {\n  posts: { id: number; title: string }[]\n}\n\nexport default function TypeScriptProps() {\n  const page = usePage<PageProps>()\n\n  const userName = page.props.auth.user?.name\n  const postTitles = page.props.posts.map((post) => post.title)\n\n  // @ts-expect-error - 'email' does not exist on user\n  const userEmail = page.props.auth.user?.email\n  // @ts-expect-error - 'users' does not exist on page props\n  const userNames = page.props.users.map((user) => user.name)\n\n  // Global event callbacks should include shared props\n  router.on('success', (event) => {\n    console.log(event.detail.page.props.auth.user?.name)\n    // @ts-expect-error - 'email' does not exist on user\n    console.log(event.detail.page.props.auth.user?.email)\n  })\n\n  router.on('navigate', (event) => {\n    console.log(event.detail.page.props.auth.user?.name)\n    // @ts-expect-error - 'email' does not exist on user\n    console.log(event.detail.page.props.auth.user?.email)\n  })\n\n  router.on('beforeUpdate', (event) => {\n    console.log(event.detail.page.props.auth.user?.name)\n    // @ts-expect-error - 'email' does not exist on user\n    console.log(event.detail.page.props.auth.user?.email)\n  })\n\n  // Visit callback onSuccess should include shared props\n  router.visit('/example', {\n    onSuccess: (page) => {\n      console.log(page.props.auth.user?.name)\n      // @ts-expect-error - 'email' does not exist on user\n      console.log(page.props.auth.user?.email)\n    },\n  })\n\n  // Client-side visit onSuccess should include shared props\n  router.push({\n    onSuccess: (page) => {\n      console.log(page.props.auth.user?.name)\n      // @ts-expect-error - 'email' does not exist on user\n      console.log(page.props.auth.user?.email)\n    },\n  })\n\n  router.replace({\n    onSuccess: (page) => {\n      console.log(page.props.auth.user?.name)\n      // @ts-expect-error - 'email' does not exist on user\n      console.log(page.props.auth.user?.email)\n    },\n  })\n\n  console.log({\n    userName,\n    postTitles,\n    userEmail,\n    userNames,\n  })\n\n  return null\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/ViewTransition/FormErrors.tsx",
    "content": "import { useForm } from '@inertiajs/react'\n\nexport default () => {\n  const form = useForm({ name: '' })\n\n  const submit = () => {\n    form.post('/view-transition/form-errors', {\n      viewTransition: (viewTransition) => {\n        viewTransition.ready.then(() => console.log('ready'))\n        viewTransition.updateCallbackDone.then(() => console.log('updateCallbackDone'))\n        viewTransition.finished.then(() => console.log('finished'))\n      },\n    })\n  }\n\n  return (\n    <div>\n      <h1>View Transition Form Errors Test</h1>\n\n      <label>\n        Name\n        <input\n          type=\"text\"\n          id=\"name\"\n          name=\"name\"\n          onChange={(e) => form.setData('name', e.target.value)}\n          value={form.data.name}\n        />\n      </label>\n\n      {form.errors.name && <p className=\"name_error\">{form.errors.name}</p>}\n\n      <button onClick={submit} className=\"submit\">\n        Submit with View Transition\n      </button>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/ViewTransition/PageA.tsx",
    "content": "import { Link, router } from '@inertiajs/react'\n\nexport default () => {\n  const transitionWithBoolean = () => {\n    router.visit('/view-transition/page-b', {\n      viewTransition: true,\n    })\n  }\n\n  const transitionWithCallback = () => {\n    router.visit('/view-transition/page-b', {\n      viewTransition: (viewTransition) => {\n        viewTransition.ready.then(() => console.log('ready'))\n        viewTransition.updateCallbackDone.then(() => console.log('updateCallbackDone'))\n        viewTransition.finished.then(() => console.log('finished'))\n      },\n    })\n  }\n\n  const clientSideReplace = () => {\n    router.replace({\n      url: '/view-transition/page-b',\n      component: 'ViewTransition/PageB',\n      props: {},\n      viewTransition: (viewTransition) => {\n        viewTransition.ready.then(() => console.log('ready'))\n        viewTransition.updateCallbackDone.then(() => console.log('updateCallbackDone'))\n        viewTransition.finished.then(() => console.log('finished'))\n      },\n    })\n  }\n\n  return (\n    <div>\n      <h1>Page A - View Transition Test</h1>\n\n      <button onClick={transitionWithBoolean}>Transition with boolean</button>\n      <button onClick={transitionWithCallback}>Transition with callback</button>\n      <button onClick={clientSideReplace}>Client-side replace</button>\n      <Link\n        href=\"/view-transition/page-b\"\n        viewTransition={(viewTransition) => {\n          viewTransition.ready.then(() => console.log('ready'))\n          viewTransition.updateCallbackDone.then(() => console.log('updateCallbackDone'))\n          viewTransition.finished.then(() => console.log('finished'))\n        }}\n      >\n        Link to Page B\n      </Link>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/ViewTransition/PageB.tsx",
    "content": "export default () => {\n  return (\n    <div>\n      <h1>Page B - View Transition Test</h1>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Visits/AfterError.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default () => {\n  const visitDump = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/dump/get')\n  }\n\n  const throwErrorOnSuccess = (e: React.MouseEvent) => {\n    e.preventDefault()\n\n    router.visit('/visits/after-error/2', {\n      onSuccess: () => {\n        throw new Error('Error after visit')\n      },\n    })\n  }\n\n  return (\n    <div>\n      <a href=\"#\" onClick={visitDump}>\n        Visit dump page\n      </a>\n\n      <a href=\"#\" onClick={throwErrorOnSuccess}>\n        Throw error on success\n      </a>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Visits/AutomaticCancellation.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default () => {\n  const visit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get(\n      '/sleep',\n      {},\n      {\n        onStart: () => console.log('started'),\n        onCancel: () => console.log('cancelled'),\n      },\n    )\n  }\n\n  return (\n    <div>\n      <span className=\"text\">This is the page that demonstrates that only one visit can be active at a time</span>\n      <a href=\"#\" onClick={visit} className=\"visit\">\n        Link\n      </a>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Visits/Data/AutoConverted.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default () => {\n  const formData = { file: new File([], 'example.jpg'), foo: 'bar' }\n\n  const visitMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/dump/post', { method: 'post', data: formData })\n  }\n\n  const postMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.post('/dump/post', formData)\n  }\n\n  const putMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.put('/dump/put', formData)\n  }\n\n  const patchMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.patch('/dump/patch', formData)\n  }\n\n  const deleteMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.delete('/dump/delete', { data: formData })\n  }\n\n  return (\n    <div>\n      <span className=\"text\">\n        This is the page that demonstrates automatic conversion of plain objects to form-data using manual visits\n      </span>\n\n      <a href=\"#\" onClick={visitMethod} className=\"visit\">\n        Visit Link\n      </a>\n      <a href=\"#\" onClick={postMethod} className=\"post\">\n        POST Link\n      </a>\n      <a href=\"#\" onClick={putMethod} className=\"put\">\n        PUT Link\n      </a>\n      <a href=\"#\" onClick={patchMethod} className=\"patch\">\n        PATCH Link\n      </a>\n      <a href=\"#\" onClick={deleteMethod} className=\"delete\">\n        DELETE Link\n      </a>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Visits/Data/FormData.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default () => {\n  const visitMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    const formData = new FormData()\n    formData.append('foo', 'visit')\n    router.visit('/dump/post', { method: 'post', data: formData })\n  }\n\n  const postMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    const formData = new FormData()\n    formData.append('baz', 'post')\n    router.post('/dump/post', formData)\n  }\n\n  const putMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    const formData = new FormData()\n    formData.append('foo', 'put')\n    router.put('/dump/put', formData)\n  }\n\n  const patchMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    const formData = new FormData()\n    formData.append('bar', 'patch')\n    router.patch('/dump/patch', formData)\n  }\n\n  const deleteMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    const formData = new FormData()\n    formData.append('baz', 'delete')\n    router.delete('/dump/delete', { data: formData })\n  }\n\n  return (\n    <div>\n      <span className=\"text\">\n        This is the page that demonstrates manual visit data passing through FormData objects\n      </span>\n\n      <a href=\"#\" onClick={visitMethod} className=\"visit\">\n        Visit Link\n      </a>\n      <a href=\"#\" onClick={postMethod} className=\"post\">\n        POST Link\n      </a>\n      <a href=\"#\" onClick={putMethod} className=\"put\">\n        PUT Link\n      </a>\n      <a href=\"#\" onClick={patchMethod} className=\"patch\">\n        PATCH Link\n      </a>\n      <a href=\"#\" onClick={deleteMethod} className=\"delete\">\n        DELETE Link\n      </a>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Visits/Data/Object.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default () => {\n  const visitMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/dump/get', { data: { foo: 'visit' } })\n  }\n\n  const getMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('/dump/get', { bar: 'get' })\n  }\n\n  const postMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.post('/dump/post', { baz: 'post' })\n  }\n\n  const putMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.put('/dump/put', { foo: 'put' })\n  }\n\n  const patchMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.patch('/dump/patch', { bar: 'patch' })\n  }\n\n  const deleteMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.delete('/dump/delete', { data: { baz: 'delete' } })\n  }\n\n  const qsafDefault = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/dump/get', { data: { a: ['b', 'c'] } })\n  }\n\n  const qsafIndices = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/dump/get', { data: { a: ['b', 'c'] }, queryStringArrayFormat: 'indices' })\n  }\n\n  const qsafBrackets = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/dump/get', {\n      data: { a: ['b', 'c'] },\n      queryStringArrayFormat: 'brackets',\n    })\n  }\n\n  const deleteQueryParam = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/dump/get', {\n      data: { a: undefined },\n    })\n  }\n\n  return (\n    <div>\n      <span className=\"text\">This is the page that demonstrates manual visit data passing through plain objects</span>\n\n      <a href=\"#\" onClick={visitMethod} className=\"visit\">\n        Visit Link\n      </a>\n      <a href=\"#\" onClick={getMethod} className=\"get\">\n        GET Link\n      </a>\n      <a href=\"#\" onClick={postMethod} className=\"post\">\n        POST Link\n      </a>\n      <a href=\"#\" onClick={putMethod} className=\"put\">\n        PUT Link\n      </a>\n      <a href=\"#\" onClick={patchMethod} className=\"patch\">\n        PATCH Link\n      </a>\n      <a href=\"#\" onClick={deleteMethod} className=\"delete\">\n        DELETE Link\n      </a>\n\n      <a href=\"#\" onClick={qsafDefault} className=\"qsaf-default\">\n        QSAF Defaults\n      </a>\n      <a href=\"#\" onClick={qsafIndices} className=\"qsaf-indices\">\n        QSAF Indices\n      </a>\n      <a href=\"#\" onClick={qsafBrackets} className=\"qsaf-brackets\">\n        QSAF Brackets\n      </a>\n      <a href=\"#\" onClick={deleteQueryParam} className=\"delete-query-param\">\n        Delete Query Param\n      </a>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Visits/ErrorBags.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default () => {\n  const defaultVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.post('/dump/post')\n  }\n\n  const basicVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/dump/post', { method: 'post', data: { foo: 'bar' }, errorBag: 'visitErrorBag' })\n  }\n\n  const postVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.post('/dump/post', { foo: 'baz' }, { errorBag: 'postErrorBag' })\n  }\n\n  return (\n    <div>\n      <span className=\"text\">This is the page that demonstrates error bags using manual visits</span>\n      <a href=\"#\" onClick={defaultVisit} className=\"default\">\n        Default visit\n      </a>\n      <a href=\"#\" onClick={basicVisit} className=\"visit\">\n        Basic visit\n      </a>\n      <a href=\"#\" onClick={postVisit} className=\"get\">\n        POST visit\n      </a>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Visits/Headers.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default () => {\n  const defaultHeadersMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/dump/get')\n  }\n\n  const visitWithCustomHeaders = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/dump/get', { headers: { foo: 'bar' } })\n  }\n\n  const getMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('/dump/get', {}, { headers: { bar: 'baz' } })\n  }\n\n  const postMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.post('/dump/post', {}, { headers: { baz: 'foo' } })\n  }\n\n  const putMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.put('/dump/put', {}, { headers: { foo: 'bar' } })\n  }\n\n  const patchMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.patch('/dump/patch', {}, { headers: { bar: 'baz' } })\n  }\n\n  const deleteMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.delete('/dump/delete', { headers: { baz: 'foo' } })\n  }\n\n  const overridden = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.post('/dump/post', {}, { headers: { bar: 'baz', 'X-Requested-With': 'custom' } })\n  }\n  return (\n    <div>\n      <span className=\"text\">This is the page that demonstrates passing custom headers through manual visits</span>\n\n      <a href=\"#\" onClick={defaultHeadersMethod} className=\"default\">\n        Standard visit Link\n      </a>\n\n      <a href=\"#\" onClick={visitWithCustomHeaders} className=\"visit\">\n        Specific visit Link\n      </a>\n      <a href=\"#\" onClick={getMethod} className=\"get\">\n        GET Link\n      </a>\n      <a href=\"#\" onClick={postMethod} className=\"post\">\n        POST Link\n      </a>\n      <a href=\"#\" onClick={putMethod} className=\"put\">\n        PUT Link\n      </a>\n      <a href=\"#\" onClick={patchMethod} className=\"patch\">\n        PATCH Link\n      </a>\n      <a href=\"#\" onClick={deleteMethod} className=\"delete\">\n        DELETE Link\n      </a>\n\n      <a href=\"#\" onClick={overridden} className=\"overridden\">\n        Overriden Link\n      </a>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Visits/Location.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default () => {\n  const locationVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/location')\n  }\n\n  return (\n    <div>\n      <span className=\"text\">This is the page that demonstrates location visits</span>\n\n      <a href=\"#\" onClick={locationVisit} className=\"example\">\n        Location visit\n      </a>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Visits/Method.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default () => {\n  const standardVisitMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/dump/get')\n  }\n\n  const specificVisitMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/dump/patch', { method: 'patch' })\n  }\n\n  const getMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('/dump/get')\n  }\n\n  const postMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.post('/dump/post')\n  }\n\n  const putMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.put('/dump/put')\n  }\n\n  const patchMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.patch('/dump/patch')\n  }\n\n  const deleteMethod = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.delete('/dump/delete')\n  }\n\n  return (\n    <div>\n      <span className=\"text\">This is the page that demonstrates manual visit methods</span>\n\n      <a href=\"#\" onClick={standardVisitMethod} className=\"visit-get\">\n        Standard visit Link\n      </a>\n      <a href=\"#\" onClick={specificVisitMethod} className=\"visit-specific\">\n        Specific visit Link\n      </a>\n      <a href=\"#\" onClick={getMethod} className=\"get\">\n        GET Link\n      </a>\n      <a href=\"#\" onClick={postMethod} className=\"post\">\n        POST Link\n      </a>\n      <a href=\"#\" onClick={putMethod} className=\"put\">\n        PUT Link\n      </a>\n      <a href=\"#\" onClick={patchMethod} className=\"patch\">\n        PATCH Link\n      </a>\n      <a href=\"#\" onClick={deleteMethod} className=\"delete\">\n        DELETE Link\n      </a>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Visits/PartialReloads.tsx",
    "content": "import { router, usePage } from '@inertiajs/react'\nimport { useEffect } from 'react'\n\nexport default ({\n  foo = 0,\n  bar,\n  baz,\n  headers,\n}: {\n  foo: number\n  bar: number\n  baz: number\n  headers: Record<string, string>\n}) => {\n  const page = usePage()\n\n  useEffect(() => {\n    window._inertia_props = page.props\n  }, [page.props])\n\n  const partialReloadVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/partial-reloads', { data: { foo: foo } })\n  }\n\n  const partialReloadVisitFooBar = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/partial-reloads', { data: { foo: foo }, only: ['headers', 'foo', 'bar'] })\n  }\n\n  const partialReloadVisitBaz = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/partial-reloads', { data: { foo: foo }, only: ['headers', 'baz'] })\n  }\n\n  const partialReloadVisitExceptFooBar = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/partial-reloads', { data: { foo: foo }, except: ['foo', 'bar'] })\n  }\n\n  const partialReloadVisitExceptBaz = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/partial-reloads', { data: { foo: foo }, except: ['baz'] })\n  }\n\n  const partialReloadGet = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('/visits/partial-reloads', { foo: foo })\n  }\n\n  const partialReloadGetFooBar = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('/visits/partial-reloads', { foo: foo }, { only: ['headers', 'foo', 'bar'] })\n  }\n\n  const partialReloadGetBaz = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('/visits/partial-reloads', { foo: foo }, { only: ['headers', 'baz'] })\n  }\n\n  const partialReloadGetExceptFooBar = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('/visits/partial-reloads', { foo: foo }, { except: ['foo', 'bar'] })\n  }\n\n  const partialReloadGetExceptBaz = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get(\n      '/visits/partial-reloads',\n      { foo: foo },\n      {\n        except: ['baz'],\n      },\n    )\n  }\n\n  return (\n    <div>\n      <span className=\"text\">This is the page that demonstrates partial reloads using manual visits</span>\n      <span className=\"foo-text\">Foo is now {foo}</span>\n      <span className=\"bar-text\">Bar is now {bar}</span>\n      <span className=\"baz-text\">Baz is now {baz}</span>\n      <pre className=\"headers\">{JSON.stringify(headers, null, 2)}</pre>\n\n      <a href=\"#\" onClick={partialReloadVisit} className=\"visit\">\n        Update All (visit)\n      </a>\n      <a href=\"#\" onClick={partialReloadVisitFooBar} className=\"visit-foo-bar\">\n        'Only' foo + bar (visit)\n      </a>\n      <a href=\"#\" onClick={partialReloadVisitBaz} className=\"visit-baz\">\n        'Only' baz (visit)\n      </a>\n      <a href=\"#\" onClick={partialReloadVisitExceptFooBar} className=\"visit-except-foo-bar\">\n        'Except' foo + bar (visit)\n      </a>\n      <a href=\"#\" onClick={partialReloadVisitExceptBaz} className=\"visit-except-baz\">\n        'Except' baz (visit)\n      </a>\n\n      <a href=\"#\" onClick={partialReloadGet} className=\"get\">\n        Update All (GET)\n      </a>\n      <a href=\"#\" onClick={partialReloadGetFooBar} className=\"get-foo-bar\">\n        'Only' foo + bar (GET)\n      </a>\n      <a href=\"#\" onClick={partialReloadGetBaz} className=\"get-baz\">\n        'Only' baz (GET)\n      </a>\n      <a href=\"#\" onClick={partialReloadGetExceptFooBar} className=\"get-except-foo-bar\">\n        'Except' foo + bar (GET)\n      </a>\n      <a href=\"#\" onClick={partialReloadGetExceptBaz} className=\"get-except-baz\">\n        'Except' baz (GET)\n      </a>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Visits/PreserveScroll.tsx",
    "content": "import WithScrollRegion from '@/Layouts/WithScrollRegion.jsx'\nimport { router } from '@inertiajs/react'\n\nconst PreserveScroll = ({ foo = 'default' }) => {\n  const preserve = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/preserve-scroll-page-two', { data: { foo: 'foo' }, preserveScroll: true })\n  }\n\n  const preserveFalse = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/preserve-scroll-page-two', { data: { foo: 'bar' } })\n  }\n\n  const preserveCallback = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/preserve-scroll-page-two', {\n      data: { foo: 'baz' },\n      preserveScroll: (page) => {\n        console.log(JSON.stringify(page))\n        return true\n      },\n    })\n  }\n\n  const preserveCallbackFalse = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/preserve-scroll-page-two', {\n      data: { foo: 'foo' },\n      preserveScroll: (page) => {\n        console.log(JSON.stringify(page))\n        return false\n      },\n    })\n  }\n\n  const preserveGet = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get(\n      '/visits/preserve-scroll-page-two',\n      { foo: 'bar' },\n      {\n        preserveScroll: true,\n      },\n    )\n  }\n\n  const preserveGetFalse = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('/visits/preserve-scroll-page-two', { foo: 'baz' })\n  }\n\n  return (\n    <div style={{ height: '800px', width: '600px' }}>\n      <span className=\"text\">\n        This is the page that demonstrates scroll preservation with scroll regions when using manual visits\n      </span>\n      <span className=\"foo\">Foo is now {foo}</span>\n\n      <a href=\"#\" onClick={preserve} className=\"preserve\">\n        Preserve Scroll\n      </a>\n      <a href=\"#\" onClick={preserveFalse} data-testid=\"reset\" className=\"reset\">\n        Reset Scroll\n      </a>\n      <a href=\"#\" onClick={preserveCallback} className=\"preserve-callback\">\n        Preserve Scroll (Callback)\n      </a>\n      <br />\n      <a href=\"#\" onClick={preserveCallbackFalse} className=\"reset-callback\">\n        Reset Scroll (Callback)\n      </a>\n      <a href=\"#\" onClick={preserveGet} className=\"preserve-get\">\n        Preserve Scroll (GET)\n      </a>\n      <a href=\"#\" onClick={preserveGetFalse} className=\"reset-get\">\n        Reset Scroll (GET)\n      </a>\n\n      <a href=\"/non-inertia\" className=\"off-site\">\n        Off-site link\n      </a>\n    </div>\n  )\n}\n\nPreserveScroll.layout = (page: React.ReactNode) => <WithScrollRegion children={page} />\n\nexport default PreserveScroll\n"
  },
  {
    "path": "packages/react/test-app/Pages/Visits/PreserveScrollFalse.tsx",
    "content": "import WithoutScrollRegion from '@/Layouts/WithoutScrollRegion.jsx'\nimport { router } from '@inertiajs/react'\n\nconst PreserveScrollFalse = ({ foo = 'default' }) => {\n  const preserve = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/preserve-scroll-false-page-two', { data: { foo: 'foo' }, preserveScroll: true })\n  }\n\n  const preserveFalse = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/preserve-scroll-false-page-two', { data: { foo: 'bar' } })\n  }\n\n  const preserveCallback = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/preserve-scroll-false-page-two', {\n      data: {\n        foo: 'baz',\n      },\n      preserveScroll: (page) => {\n        console.log(JSON.stringify(page))\n        return true\n      },\n    })\n  }\n\n  const preserveCallbackFalse = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/preserve-scroll-false-page-two', {\n      data: { foo: 'foo' },\n      preserveScroll: (page) => {\n        console.log(JSON.stringify(page))\n        return false\n      },\n    })\n  }\n\n  const preserveGet = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('/visits/preserve-scroll-false-page-two', { foo: 'bar' }, { preserveScroll: true })\n  }\n\n  const preserveGetFalse = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('/visits/preserve-scroll-false-page-two', {\n      foo: 'baz',\n    })\n  }\n\n  return (\n    <div\n      style={{\n        height: '800px',\n        width: '600px',\n      }}\n    >\n      <span className=\"text\">\n        This is the page that demonstrates scroll preservation without scroll regions when using manual visits\n      </span>\n      <span className=\"foo\">Foo is now {foo}</span>\n\n      <a href=\"#\" onClick={preserve} className=\"preserve\">\n        Preserve Scroll\n      </a>\n      <a href=\"#\" onClick={preserveFalse} className=\"reset\">\n        Reset Scroll\n      </a>\n      <a href=\"#\" onClick={preserveCallback} className=\"preserve-callback\">\n        Preserve Scroll (Callback)\n      </a>\n      <br />\n      <a href=\"#\" onClick={preserveCallbackFalse} className=\"reset-callback\">\n        Reset Scroll (Callback)\n      </a>\n      <a href=\"#\" onClick={preserveGet} className=\"preserve-get\">\n        Preserve Scroll (GET)\n      </a>\n      <a href=\"#\" onClick={preserveGetFalse} className=\"reset-get\">\n        Reset Scroll (GET)\n      </a>\n\n      <a href=\"/non-inertia\" className=\"off-site\">\n        Off-site link\n      </a>\n    </div>\n  )\n}\n\nPreserveScrollFalse.layout = (page: React.ReactNode) => <WithoutScrollRegion children={page} />\n\nexport default PreserveScrollFalse\n"
  },
  {
    "path": "packages/react/test-app/Pages/Visits/PreserveState.tsx",
    "content": "import { router } from '@inertiajs/react'\nimport { useId } from 'react'\n\nexport default ({ foo = 'default' }) => {\n  window._inertia_page_key = useId()\n\n  const preserve = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/preserve-state-page-two', { data: { foo: 'bar' }, preserveState: true })\n  }\n\n  const preserveFalse = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/preserve-state-page-two', { data: { foo: 'baz' }, preserveState: false })\n  }\n\n  const preserveCallback = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get(\n      '/visits/preserve-state-page-two',\n      { foo: 'callback-bar' },\n      {\n        preserveState: (page) => {\n          console.log(JSON.stringify(page))\n          return true\n        },\n      },\n    )\n  }\n\n  const preserveCallbackFalse = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get(\n      '/visits/preserve-state-page-two',\n      { foo: 'callback-baz' },\n      {\n        preserveState: (page) => {\n          console.log(JSON.stringify(page))\n          return false\n        },\n      },\n    )\n  }\n\n  const preserveGet = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('/visits/preserve-state-page-two', { foo: 'get-bar' }, { preserveState: true })\n  }\n\n  const preserveGetFalse = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('/visits/preserve-state-page-two', { foo: 'get-baz' }, { preserveState: false })\n  }\n\n  return (\n    <div>\n      <span className=\"text\">This is the page that demonstrates preserve state on manual visits</span>\n      <span className=\"foo\">Foo is now {foo}</span>\n      <label>\n        Example Field\n        <input type=\"text\" name=\"example-field\" className=\"field\" />\n      </label>\n\n      <a href=\"#\" onClick={preserve} className=\"preserve\">\n        [State] Preserve visit: true\n      </a>\n      <a href=\"#\" onClick={preserveFalse} className=\"preserve-false\">\n        [State] Preserve visit: false\n      </a>\n      <a href=\"#\" onClick={preserveCallback} className=\"preserve-callback\">\n        [State] Preserve Callback: true\n      </a>\n      <a href=\"#\" onClick={preserveCallbackFalse} className=\"preserve-callback-false\">\n        [State] Preserve Callback: false\n      </a>\n      <a href=\"#\" onClick={preserveGet} className=\"preserve-get\">\n        [State] Preserve GET: true\n      </a>\n      <a href=\"#\" onClick={preserveGetFalse} className=\"preserve-get-false\">\n        [State] Preserve GET: false\n      </a>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Visits/ReloadOnMount.tsx",
    "content": "import { router } from '@inertiajs/react'\nimport { useEffect } from 'react'\n\nexport default (props: { name: string }) => {\n  useEffect(() => {\n    router.reload({ only: ['name'] })\n  }, [])\n\n  return <div>Name is {props.name}</div>\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Visits/Replace.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default () => {\n  const replace = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/dump/get', { replace: true })\n  }\n\n  const replaceFalse = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/dump/get', { replace: false })\n  }\n\n  const replaceGet = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('/dump/get', {}, { replace: true })\n  }\n\n  const replaceGetFalse = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('/dump/get', {}, { replace: false })\n  }\n\n  return (\n    <div>\n      <span className=\"text\">This is the links page that demonstrates manual replace</span>\n\n      <a href=\"#\" onClick={replace} className=\"replace\">\n        [State] Replace visit: true\n      </a>\n      <a href=\"#\" onClick={replaceFalse} className=\"replace-false\">\n        [State] Replace visit: false\n      </a>\n      <a href=\"#\" onClick={replaceGet} className=\"replace-get\">\n        [State] Replace GET: true\n      </a>\n      <a href=\"#\" onClick={replaceGetFalse} className=\"replace-get-false\">\n        [State] Replace GET: false\n      </a>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Visits/UrlFragments.tsx",
    "content": "import { router } from '@inertiajs/react'\nimport { useEffect, useState } from 'react'\n\nexport default () => {\n  const [documentScrollTop, setDocumentScrollTop] = useState(0)\n  const [documentScrollLeft, setDocumentScrollLeft] = useState(0)\n\n  const handleScrollEvent = () => {\n    setDocumentScrollLeft(document.documentElement.scrollLeft)\n    setDocumentScrollTop(document.documentElement.scrollTop)\n  }\n\n  useEffect(() => {\n    document.addEventListener('scroll', handleScrollEvent)\n\n    return () => {\n      document.removeEventListener('scroll', handleScrollEvent)\n    }\n  })\n\n  const basicVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/url-fragments#target')\n  }\n\n  const fragmentVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('#target')\n  }\n\n  const nonExistentFragmentVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit('/visits/url-fragments#non-existent-fragment')\n  }\n\n  const basicGetVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('/visits/url-fragments#target')\n  }\n\n  const fragmentGetVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('#target')\n  }\n\n  const nonExistentFragmentGetVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.get('/visits/url-fragments#non-existent-fragment')\n  }\n\n  return (\n    <div>\n      <span className=\"text\">This is the page that demonstrates url fragment behaviour using manual visits</span>\n      <div\n        style={{\n          width: '200vw',\n          height: '200vh',\n          marginTop: '50vh',\n        }}\n      >\n        <button onClick={handleScrollEvent}>Update scroll positions</button>\n        {/* prettier-ignore */}\n        <div className=\"document-position\">Document scroll position is {documentScrollLeft} & {documentScrollTop}</div>\n        <a href=\"#\" onClick={basicVisit} className=\"basic\">\n          Basic visit\n        </a>\n        <a href=\"#\" onClick={fragmentVisit} className=\"fragment\">\n          Fragment visit\n        </a>\n        <a href=\"#\" onClick={nonExistentFragmentVisit} className=\"non-existent-fragment\">\n          Non-existent fragment visit\n        </a>\n\n        <a href=\"#\" onClick={basicGetVisit} className=\"basic-get\">\n          Basic GET visit\n        </a>\n        <a href=\"#\" onClick={fragmentGetVisit} className=\"fragment-get\">\n          Fragment GET visit\n        </a>\n        <a href=\"#\" onClick={nonExistentFragmentGetVisit} className=\"non-existent-fragment-get\">\n          Non-existent fragment GET visit\n        </a>\n\n        <div id=\"target\">This is the element with id 'target'</div>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/Visits/Wayfinder.tsx",
    "content": "import { router } from '@inertiajs/react'\n\nexport default function Wayfinder() {\n  const wayfinderObjectVisit = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit({ url: '/dump/post', method: 'post' })\n  }\n\n  const wayfinderObjectMethodOverride = (e: React.MouseEvent) => {\n    e.preventDefault()\n    router.visit({ url: '/dump/patch', method: 'get' }, { method: 'patch' })\n  }\n\n  return (\n    <div>\n      <a href=\"#\" onClick={wayfinderObjectVisit} className=\"wayfinder-visit\">\n        Wayfinder object visit\n      </a>\n      <a href=\"#\" onClick={wayfinderObjectMethodOverride} className=\"wayfinder-method-override\">\n        Wayfinder object method override\n      </a>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/WhenVisible.tsx",
    "content": "import { WhenVisible } from '@inertiajs/react'\nimport { useState } from 'react'\n\nconst Foo = ({ label }: { label: string }) => {\n  return <div>{label}</div>\n}\n\nexport default () => {\n  const [count, setCount] = useState(0)\n\n  return (\n    <>\n      <div style={{ marginTop: '5000px' }}>\n        <WhenVisible data=\"foo\" fallback={<div>Loading first one...</div>}>\n          <Foo label=\"First one is visible!\" />\n        </WhenVisible>\n      </div>\n\n      <div style={{ marginTop: '5000px' }}>\n        <WhenVisible buffer={1000} data=\"foo\" fallback={() => <div>Loading second one...</div>}>\n          {() => <Foo label=\"Second one is visible!\" />}\n        </WhenVisible>\n      </div>\n\n      <div style={{ marginTop: '5000px' }}>\n        <WhenVisible data=\"foo\" fallback={<div>Loading third one...</div>} always>\n          <Foo label=\"Third one is visible!\" />\n        </WhenVisible>\n      </div>\n\n      <div style={{ marginTop: '5000px' }}>\n        {/* @ts-expect-error - WhenVisible requires a child, we should check whether this is a bug or not */}\n        <WhenVisible data=\"foo\" fallback={<div>Loading fourth one...</div>}></WhenVisible>\n      </div>\n\n      <div style={{ marginTop: '6000px' }}>\n        <WhenVisible\n          fallback={<div>Loading fifth one...</div>}\n          always\n          params={{\n            data: {\n              count,\n            },\n            onSuccess: () => {\n              setCount((c) => c + 1)\n            },\n          }}\n        >\n          <Foo label={`Count is now ${count}`} />\n        </WhenVisible>\n      </div>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/WhenVisibleArrayReload.tsx",
    "content": "import { router, WhenVisible } from '@inertiajs/react'\n\ninterface Props {\n  firstData?: {\n    text: string\n  }\n  secondData?: {\n    text: string\n  }\n}\n\nexport default ({ firstData, secondData }: Props) => {\n  const handleReload = () => {\n    router.reload()\n  }\n\n  return (\n    <div>\n      <h1>WhenVisible + Array Props + Reload</h1>\n\n      <button onClick={handleReload}>Reload Page</button>\n\n      <div style={{ marginTop: '2000px', padding: '20px', border: '1px solid #ccc' }}>\n        <WhenVisible data={['firstData', 'secondData']} fallback={<p>Loading array data...</p>}>\n          <div>\n            <p>{firstData?.text}</p>\n            <p>{secondData?.text}</p>\n          </div>\n        </WhenVisible>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/WhenVisibleBackButton.tsx",
    "content": "import { Link, WhenVisible } from '@inertiajs/react'\n\nexport default ({\n  lazyData,\n}: {\n  lazyData?: {\n    text: string\n  }\n}) => {\n  return (\n    <div>\n      <h1>WhenVisible + Back Button</h1>\n\n      <Link href=\"/links/method\">Navigate Away</Link>\n\n      <div style={{ marginTop: '2000px', padding: '20px', border: '1px solid #ccc' }}>\n        <WhenVisible data=\"lazyData\" fallback={<p>Loading lazy data...</p>}>\n          <p>{lazyData?.text}</p>\n        </WhenVisible>\n      </div>\n\n      <div style={{ marginTop: '2000px', padding: '20px', border: '1px solid #ccc' }}>\n        <WhenVisible data=\"lazyData\" always fallback={<p>Loading always data...</p>}>\n          <p>Always: {lazyData?.text}</p>\n        </WhenVisible>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/WhenVisibleFetching.tsx",
    "content": "import { WhenVisible } from '@inertiajs/react'\n\nexport default () => {\n  return (\n    <div style={{ marginTop: '5000px' }}>\n      <WhenVisible data=\"lazyData\" always fallback={<div>Loading lazy data...</div>}>\n        {({ fetching }) => (\n          <>\n            <div>Lazy data loaded!</div>\n            {fetching && <div>Fetching in background...</div>}\n          </>\n        )}\n      </WhenVisible>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/WhenVisibleMergeParams.tsx",
    "content": "import { WhenVisible } from '@inertiajs/react'\n\nexport default ({\n  dataOnlyProp,\n  mergedProp,\n  mergedWithCallbackProp,\n}: {\n  dataOnlyProp?: { text: string }\n  mergedProp?: { text: string }\n  mergedWithCallbackProp?: { text: string }\n}) => {\n  return (\n    <>\n      <div id=\"data-only\" style={{ marginTop: '3000px' }}>\n        <WhenVisible data=\"dataOnlyProp\" fallback={<div>Loading data only...</div>}>\n          <div>Data only loaded: {dataOnlyProp?.text}</div>\n        </WhenVisible>\n      </div>\n\n      <div id=\"merged\" style={{ marginTop: '5000px' }}>\n        <WhenVisible\n          data=\"mergedProp\"\n          params={{\n            data: { extra: 'from-params' },\n          }}\n          fallback={<div>Loading merged...</div>}\n        >\n          <div>Merged loaded: {mergedProp?.text}</div>\n        </WhenVisible>\n      </div>\n\n      <div id=\"merged-with-callback\" style={{ marginTop: '5000px' }}>\n        <WhenVisible\n          data=\"mergedWithCallbackProp\"\n          params={{\n            data: { page: '2' },\n            preserveUrl: true,\n          }}\n          fallback={<div>Loading merged with callback...</div>}\n        >\n          <div>Merged with callback loaded: {mergedWithCallbackProp?.text}</div>\n        </WhenVisible>\n      </div>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/WhenVisibleParamsUpdate.tsx",
    "content": "import { WhenVisible } from '@inertiajs/react'\nimport { useState } from 'react'\n\nexport default ({ lazyData }: { lazyData?: { text: string } }) => {\n  const [paramValue, setParamValue] = useState('initial')\n\n  return (\n    <div>\n      <button onClick={() => setParamValue('updated')}>Update Param</button>\n      <p>Current param: {paramValue}</p>\n\n      <div style={{ marginTop: '3000px' }}>\n        <WhenVisible data=\"lazyData\" params={{ data: { paramValue } }} always fallback={<p>Loading lazy data...</p>}>\n          <div>\n            <p>Data loaded: {lazyData?.text}</p>\n          </div>\n        </WhenVisible>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/Pages/WhenVisibleReload.tsx",
    "content": "import { router, WhenVisible } from '@inertiajs/react'\n\ninterface Props {\n  lazyData?: {\n    text: string\n  }\n}\n\nexport default ({ lazyData }: Props) => {\n  const handleReload = () => {\n    router.reload()\n  }\n\n  return (\n    <div>\n      <h1>WhenVisible + Reload</h1>\n\n      <button onClick={handleReload}>Reload Page</button>\n\n      <div style={{ marginTop: '2000px', padding: '20px', border: '1px solid #ccc' }}>\n        <WhenVisible data=\"lazyData\" fallback={<p>Loading lazy data...</p>}>\n          {lazyData?.text}\n        </WhenVisible>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/react/test-app/app.tsx",
    "content": "import type { VisitOptions } from '@inertiajs/core'\nimport { type ResolvedComponent, createInertiaApp, router } from '@inertiajs/react'\nimport { createRoot } from 'react-dom/client'\n\nwindow.testing = { Inertia: router }\n\nconst withAppDefaults = new URLSearchParams(window.location.search).get('withAppDefaults')\n\ncreateInertiaApp({\n  page: window.initialPage,\n  resolve: async (name) => {\n    const pages = import.meta.glob<ResolvedComponent>('./Pages/**/*.tsx', { eager: true })\n    // const typedPages = import.meta.glob<ComponentType>('./Pages/**/*.tsx', { eager: true })\n\n    if (name === 'DeferredProps/InstantReload') {\n      // Add small delay to ensure the component is loaded after the initial page load\n      // This is for projects that don't use { eager: true } in import.meta.glob\n      await new Promise((resolve) => setTimeout(resolve, 50))\n    }\n\n    return pages[`./Pages/${name}.tsx`]\n  },\n  setup({ el, App, props }) {\n    createRoot(el).render(<App {...props} />)\n  },\n  progress: {\n    delay: 0,\n    color: 'red',\n  },\n  ...(withAppDefaults && {\n    defaults: {\n      visitOptions: (href: string, options: VisitOptions) => {\n        return { headers: { ...options.headers, 'X-From-App-Defaults': 'test' } }\n      },\n    },\n  }),\n})\n"
  },
  {
    "path": "packages/react/test-app/eslint.config.js",
    "content": "import js from '@eslint/js'\nimport prettier from 'eslint-config-prettier'\nimport react from 'eslint-plugin-react'\nimport reactHooks from 'eslint-plugin-react-hooks'\nimport globals from 'globals'\nimport typescript from 'typescript-eslint'\n\n/** @type {import('eslint').Linter.Config[]} */\nexport default [\n  {\n    ignores: ['node_modules', 'dist/**/*', '*.config.js', '**/*.d.ts', '*.timestamp-*'],\n  },\n  {\n    files: ['**/*.{js,jsx,ts,tsx}'],\n    ...js.configs.recommended,\n  },\n  ...typescript.configs.recommended.map((config) => ({\n    ...config,\n    files: ['**/*.{ts,tsx}'],\n  })),\n  {\n    files: ['**/*.{ts,tsx}'],\n    languageOptions: {\n      parserOptions: {\n        projectService: true,\n        tsconfigRootDir: import.meta.dirname,\n      },\n    },\n    rules: {\n      '@typescript-eslint/unbound-method': 'error',\n    },\n  },\n  {\n    files: ['**/*.{js,jsx,ts,tsx}'],\n    ...react.configs.flat.recommended,\n    ...react.configs.flat['jsx-runtime'],\n    languageOptions: {\n      ecmaVersion: 2020,\n      sourceType: 'module',\n      globals: {\n        ...globals.browser,\n        ...globals.es2020,\n      },\n    },\n    rules: {\n      'react/react-in-jsx-scope': 'off',\n      'react/prop-types': 'off',\n      'react/no-unescaped-entities': 'off',\n    },\n    settings: {\n      react: {\n        version: 'detect',\n      },\n    },\n  },\n  {\n    files: ['**/*.{js,jsx,ts,tsx}'],\n    plugins: {\n      'react-hooks': reactHooks,\n    },\n    rules: {\n      'react-hooks/rules-of-hooks': 'error',\n      'react-hooks/exhaustive-deps': 'error',\n    },\n  },\n  prettier, // Turn off all rules that might conflict with Prettier\n]\n"
  },
  {
    "path": "packages/react/test-app/index.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title {{ headAttribute }}>Inertia React - Testing Environment</title>\n    <script>\n      window.initialPage = '{{ placeholder }}'\n    </script>\n    <script type=\"module\" src=\"app.tsx\"></script>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/react/test-app/package.json",
    "content": "{\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"vite build .\",\n    \"build:ssr\": \"vite build --ssr ssr.tsx --outDir dist\",\n    \"dev\": \"nodemon --watch . --watch ../../core/dist --watch ../../react/dist --ext js,tsx,html,json --ignore dist/ --exec 'vite build .'\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\"\n  },\n  \"devDependencies\": {\n    \"@eslint/js\": \"^9.39.3\",\n    \"@types/node\": \"^24.10.15\",\n    \"@types/react\": \"^19.2.14\",\n    \"@types/react-dom\": \"^19.2.3\",\n    \"eslint\": \"^9.39.3\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"eslint-plugin-react\": \"^7.37.5\",\n    \"eslint-plugin-react-hooks\": \"^7.0.1\",\n    \"globals\": \"^17.3.0\",\n    \"nodemon\": \"^3.1.14\",\n    \"typescript\": \"^5.9.3\",\n    \"typescript-eslint\": \"^8.56.1\",\n    \"vite\": \"^7.3.1\"\n  },\n  \"dependencies\": {\n    \"@inertiajs/core\": \"workspace:*\",\n    \"@inertiajs/react\": \"workspace:*\",\n    \"@vitejs/plugin-react\": \"^5.1.4\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\"\n  }\n}\n"
  },
  {
    "path": "packages/react/test-app/ssr.tsx",
    "content": "import { createInertiaApp, type ResolvedComponent } from '@inertiajs/react'\nimport createServer from '@inertiajs/react/server'\nimport ReactDOMServer from 'react-dom/server'\n\ncreateServer((page) =>\n  createInertiaApp({\n    page,\n    render: ReactDOMServer.renderToString,\n    resolve: (name) => {\n      const pages = import.meta.glob<ResolvedComponent>('./Pages/SSR/**/*.tsx', { eager: true })\n      return pages[`./Pages/${name}.tsx`]\n    },\n    setup: ({ App, props }) => <App {...props} />,\n    defaults: {\n      future: {\n        useScriptElementForInitialPage: page.component === 'SSR/PageWithScriptElement',\n      },\n    },\n  }),\n)\n"
  },
  {
    "path": "packages/react/test-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ESNext\", \"DOM\", \"DOM.Iterable\"],\n    \"jsx\": \"react-jsx\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"paths\": {\n      \"@/*\": [\"./*\"]\n    },\n    \"resolveJsonModule\": true,\n    \"allowJs\": true,\n    \"sourceMap\": true,\n    \"noEmit\": true,\n    \"isolatedModules\": true,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"strict\": true,\n    \"skipLibCheck\": true\n  },\n  \"include\": [\"**/*.ts\", \"**/*.tsx\", \"**/*.jsx\"]\n}\n"
  },
  {
    "path": "packages/react/test-app/types.d.ts",
    "content": "import type { Method, Page, PageProps, Router } from '@inertiajs/core'\n\ndeclare global {\n  interface Window {\n    testing: {\n      Inertia: Router\n    }\n    initialPage: Page\n    _inertia_request_dump: {\n      headers: Record<string, string>\n      method: Method\n      form: Record<string, unknown> | undefined\n      files: MulterFile[] | object\n      query: Record<string, unknown>\n      url: string\n      $page: Page\n    }\n    _inertia_page_key: number | string | undefined\n    _inertia_props: PageProps\n    _inertia_layout_id: number | string | undefined\n    _inertia_site_layout_props: PageProps\n    _inertia_nested_layout_id: number | string | undefined\n    _inertia_nested_layout_props: PageProps\n    _inertia_page_props: PageProps\n    _plugin_global_props: object\n  }\n\n  interface ImportMeta {\n    readonly glob: <T>(pattern: string, options: { eager: true }) => Record<string, T>\n  }\n}\n\nexport type MulterFile = Express.Multer.File\n"
  },
  {
    "path": "packages/react/test-app/vite.config.ts",
    "content": "import react from '@vitejs/plugin-react'\nimport { defineConfig } from 'vite'\n\nconst isSSR = process.argv.includes('--ssr')\n\nexport default defineConfig({\n  build: {\n    minify: false,\n    emptyOutDir: !isSSR,\n  },\n  resolve: {\n    alias: {\n      '@': __dirname,\n    },\n  },\n  plugins: [react()],\n})\n"
  },
  {
    "path": "packages/react/tsconfig.json",
    "content": "{\n  \"include\": [\"src/index.ts\", \"src/server.ts\"],\n  \"compilerOptions\": {\n    \"rootDir\": \"src\",\n    \"noEmitOnError\": true,\n\n    \"lib\": [\"DOM\", \"DOM.Iterable\", \"ES2020\"],\n    \"target\": \"ES2020\",\n\n    \"declaration\": true,\n    \"declarationDir\": \"types\",\n    \"emitDeclarationOnly\": true,\n\n    \"module\": \"ES2020\",\n    \"moduleResolution\": \"Node\",\n    \"resolveJsonModule\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"skipLibCheck\": true,\n\n    \"noImplicitThis\": false,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"preserveConstEnums\": true,\n    \"removeComments\": true,\n    \"typeRoots\": [\"./node_modules/@types\"],\n    \"strict\": true\n  }\n}\n"
  },
  {
    "path": "packages/svelte/.gitignore",
    "content": "dist\ntypes\nnode_modules\npackage-lock.json\nyarn.lock\n.svelte-kit\n"
  },
  {
    "path": "packages/svelte/LICENSE",
    "content": "MIT License\n\nCopyright (c) Jonathan Reinink <jonathan@reinink.ca>\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": "packages/svelte/package.json",
    "content": "{\n  \"name\": \"@inertiajs/svelte\",\n  \"version\": \"2.3.18\",\n  \"license\": \"MIT\",\n  \"description\": \"The Svelte adapter for Inertia.js\",\n  \"contributors\": [\n    \"Jonathan Reinink <jonathan@reinink.ca>\",\n    \"Pedro Borges <oi@pedroborg.es>\"\n  ],\n  \"homepage\": \"https://inertiajs.com/\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/inertiajs/inertia.git\",\n    \"directory\": \"packages/svelte\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/inertiajs/inertia/issues\"\n  },\n  \"files\": [\n    \"dist\",\n    \"!dist/**/*.test.*\",\n    \"!dist/**/*.spec.*\",\n    \"resources\"\n  ],\n  \"type\": \"module\",\n  \"types\": \"./dist/index.d.ts\",\n  \"svelte\": \"./dist/index.js\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"svelte\": \"./dist/index.js\"\n    },\n    \"./server\": {\n      \"types\": \"./dist/server.d.ts\",\n      \"svelte\": \"./dist/server.js\"\n    }\n  },\n  \"scripts\": {\n    \"build\": \"pnpm package && svelte-check --tsconfig ./tsconfig.json && publint\",\n    \"build:with-deps\": \"svelte-kit sync && vite build --config vite-with-deps.config.js\",\n    \"check\": \"svelte-kit sync && svelte-check --tsconfig ./tsconfig.json\",\n    \"check:watch\": \"svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch\",\n    \"dev\": \"pnpm package --watch\",\n    \"es2020-check\": \"pnpm build:with-deps && es-check es2020 \\\"dist/**/*.js\\\" --checkFeatures --module --noCache --verbose\",\n    \"package\": \"svelte-kit sync && svelte-package --input src\"\n  },\n  \"devDependencies\": {\n    \"@sveltejs/adapter-auto\": \"^3.3.1\",\n    \"@sveltejs/kit\": \"^2.53.3\",\n    \"@sveltejs/package\": \"^2.5.7\",\n    \"@sveltejs/vite-plugin-svelte\": \"^3.1.2\",\n    \"axios\": \"^1.13.5\",\n    \"es-check\": \"^9.6.1\",\n    \"publint\": \"^0.3.17\",\n    \"svelte\": \"^4.2.20\",\n    \"svelte-check\": \"^4.4.4\",\n    \"tslib\": \"^2.8.1\",\n    \"typescript\": \"^5.9.3\",\n    \"vite\": \"^5.4.21\"\n  },\n  \"peerDependencies\": {\n    \"svelte\": \"^4.0.0 || ^5.0.0\"\n  },\n  \"dependencies\": {\n    \"@inertiajs/core\": \"workspace:*\",\n    \"@types/lodash-es\": \"^4.17.12\",\n    \"laravel-precognition\": \"^1.0.2\",\n    \"lodash-es\": \"^4.17.23\"\n  }\n}\n"
  },
  {
    "path": "packages/svelte/readme.md",
    "content": "# Inertia.js Svelte Adapter\n\nVisit [inertiajs.com](https://inertiajs.com/) to learn more.\n"
  },
  {
    "path": "packages/svelte/resources/boost/guidelines/core.blade.php",
    "content": "# Inertia + Svelte\n\n- IMPORTANT: Activate `inertia-svelte-development` when working with Inertia Svelte client-side patterns.\n"
  },
  {
    "path": "packages/svelte/resources/boost/skills/inertia-svelte-development/SKILL.blade.php",
    "content": "---\nname: inertia-svelte-development\ndescription: \"Develops Inertia.js v2 Svelte client-side applications. Activates when creating Svelte pages, forms, or navigation; using Link, Form, or router; working with deferred props, prefetching, or polling; or when user mentions Svelte with Inertia, Svelte pages, Svelte forms, or Svelte navigation.\"\nlicense: MIT\nmetadata:\n  author: laravel\n---\n@php\n/** @var \\Laravel\\Boost\\Install\\GuidelineAssist $assist */\n@endphp\n# Inertia Svelte Development\n\n## When to Apply\n\nActivate this skill when:\n\n- Creating or modifying Svelte page components for Inertia\n- Working with forms in Svelte (using `<Form>` or `useForm`)\n- Implementing client-side navigation with `<Link>` or `router`\n- Using v2 features: deferred props, prefetching, WhenVisible, InfiniteScroll, once props, flash data, or polling\n- Building Svelte-specific features with the Inertia protocol\n\n## Documentation\n\nUse `search-docs` for detailed Inertia v2 Svelte patterns and documentation.\n\n## Basic Usage\n\n### Page Components Location\n\nSvelte page components should be placed in the `{{ $assist->inertia()->pagesDirectory() }}` directory.\n\n### Page Component Structure\n\n@boostsnippet(\"Basic Svelte Page Component\", \"svelte\")\n<script>\nexport let users\n</script>\n\n<div>\n    <h1>Users</h1>\n    <ul>\n        {#each users as user (user.id)}\n            <li>{user.name}</li>\n        {/each}\n    </ul>\n</div>\n@endboostsnippet\n\n## Client-Side Navigation\n\n### Basic Link Component\n\nUse `<Link>` for client-side navigation instead of traditional `<a>` tags:\n\n@boostsnippet(\"Inertia Svelte Navigation\", \"svelte\")\n<script>\nimport { Link } from '@inertiajs/svelte'\n</script>\n\n<Link href=\"/\">Home</Link>\n<Link href=\"/users\">Users</Link>\n<Link href={`/users/${user.id}`}>View User</Link>\n@endboostsnippet\n\n### Link With Method\n\n@boostsnippet(\"Link With POST Method\", \"svelte\")\n<script>\nimport { Link } from '@inertiajs/svelte'\n</script>\n\n<Link href=\"/logout\" method=\"post\">Logout</Link>\n@endboostsnippet\n\n### Prefetching\n\nPrefetch pages to improve perceived performance:\n\n@boostsnippet(\"Prefetch on Hover\", \"svelte\")\n<script>\nimport { Link } from '@inertiajs/svelte'\n</script>\n\n<Link href=\"/users\" prefetch>Users</Link>\n@endboostsnippet\n\n### Programmatic Navigation\n\n@boostsnippet(\"Router Visit\", \"svelte\")\n<script>\nimport { router } from '@inertiajs/svelte'\n\nfunction handleClick() {\n    router.visit('/users')\n}\n\n// Or with options\nfunction createUser() {\n    router.visit('/users', {\n        method: 'post',\n        data: { name: 'John' },\n        onSuccess: () => console.log('Success!'),\n    })\n}\n</script>\n@endboostsnippet\n\n## Form Handling\n\n@if($assist->inertia()->hasFormComponent())\n### Form Component (Recommended)\n\nThe recommended way to build forms is with the `<Form>` component:\n\n@boostsnippet(\"Form Component Example\", \"svelte\")\n<script>\nimport { Form } from '@inertiajs/svelte'\n</script>\n\n<Form action=\"/users\" method=\"post\" let:errors let:processing let:wasSuccessful>\n    <input type=\"text\" name=\"name\" />\n    {#if errors.name}\n        <div>{errors.name}</div>\n    {/if}\n\n    <input type=\"email\" name=\"email\" />\n    {#if errors.email}\n        <div>{errors.email}</div>\n    {/if}\n\n    <button type=\"submit\" disabled={processing}>\n        {processing ? 'Creating...' : 'Create User'}\n    </button>\n\n    {#if wasSuccessful}\n        <div>User created!</div>\n    {/if}\n</Form>\n@endboostsnippet\n\n### Form Component With All Props\n\n@boostsnippet(\"Form Component Full Example\", \"svelte\")\n<script>\nimport { Form } from '@inertiajs/svelte'\n</script>\n\n<Form\n    action=\"/users\"\n    method=\"post\"\n    let:errors\n    let:hasErrors\n    let:processing\n    let:progress\n    let:wasSuccessful\n    let:recentlySuccessful\n    let:clearErrors\n    let:resetAndClearErrors\n    let:defaults\n    let:isDirty\n    let:reset\n    let:submit\n>\n    <input type=\"text\" name=\"name\" value={defaults.name} />\n    {#if errors.name}\n        <div>{errors.name}</div>\n    {/if}\n\n    <button type=\"submit\" disabled={processing}>\n        {processing ? 'Saving...' : 'Save'}\n    </button>\n\n    {#if progress}\n        <progress value={progress.percentage} max=\"100\">\n            {progress.percentage}%\n        </progress>\n    {/if}\n\n    {#if wasSuccessful}\n        <div>Saved!</div>\n    {/if}\n</Form>\n@endboostsnippet\n\n@if($assist->inertia()->hasFormComponentResets())\n### Form Component Reset Props\n\nThe `<Form>` component supports automatic resetting:\n\n- `resetOnError` - Reset form data when the request fails\n- `resetOnSuccess` - Reset form data when the request succeeds\n- `setDefaultsOnSuccess` - Update default values on success\n\nUse the `search-docs` tool with a query of `form component resetting` for detailed guidance.\n\n@boostsnippet(\"Form With Reset Props\", \"svelte\")\n<script>\nimport { Form } from '@inertiajs/svelte'\n</script>\n\n<Form\n    action=\"/users\"\n    method=\"post\"\n    resetOnSuccess\n    setDefaultsOnSuccess\n    let:errors\n    let:processing\n    let:wasSuccessful\n>\n    <input type=\"text\" name=\"name\" />\n    {#if errors.name}\n        <div>{errors.name}</div>\n    {/if}\n\n    <button type=\"submit\" disabled={processing}>\n        Submit\n    </button>\n</Form>\n@endboostsnippet\n@else\nNote: This version of Inertia does not support `resetOnError`, `resetOnSuccess`, or `setDefaultsOnSuccess` on the `<Form>` component. Using these props will cause errors. Upgrade to Inertia v2.2.0+ to use these features.\n@endif\n\nForms can also be built using the `useForm` hook for more programmatic control. Use the `search-docs` tool with a query of `useForm helper` for guidance.\n\n@endif\n\n### `useForm` Hook\n\n@if($assist->inertia()->hasFormComponent() === false)\nFor Inertia v2.0.x: Build forms using the `useForm` hook as the `<Form>` component is not available until v2.1.0+.\n@else\nFor more programmatic control or to follow existing conventions, use the `useForm` hook:\n@endif\n\n@boostsnippet(\"useForm Example\", \"svelte\")\n<script>\nimport { useForm } from '@inertiajs/svelte'\n\nconst form = useForm({\n    name: '',\n    email: '',\n    password: '',\n})\n\nfunction submit() {\n    $form.post('/users', {\n        onSuccess: () => $form.reset('password'),\n    })\n}\n</script>\n\n<form on:submit|preventDefault={submit}>\n    <input type=\"text\" bind:value={$form.name} />\n    {#if $form.errors.name}\n        <div>{$form.errors.name}</div>\n    {/if}\n\n    <input type=\"email\" bind:value={$form.email} />\n    {#if $form.errors.email}\n        <div>{$form.errors.email}</div>\n    {/if}\n\n    <input type=\"password\" bind:value={$form.password} />\n    {#if $form.errors.password}\n        <div>{$form.errors.password}</div>\n    {/if}\n\n    <button type=\"submit\" disabled={$form.processing}>\n        Create User\n    </button>\n</form>\n@endboostsnippet\n\n## Inertia v2 Features\n\n### Deferred Props\n\nUse deferred props to load data after initial page render:\n\n@boostsnippet(\"Deferred Props with Empty State\", \"svelte\")\n<script>\nexport let users\n</script>\n\n<div>\n    <h1>Users</h1>\n    {#if !users}\n        <div class=\"animate-pulse\">\n            <div class=\"h-4 bg-gray-200 rounded w-3/4 mb-2\"></div>\n            <div class=\"h-4 bg-gray-200 rounded w-1/2\"></div>\n        </div>\n    {:else}\n        <ul>\n            {#each users as user (user.id)}\n                <li>{user.name}</li>\n            {/each}\n        </ul>\n    {/if}\n</div>\n@endboostsnippet\n\n### Polling\n\nAutomatically refresh data at intervals:\n\n@boostsnippet(\"Polling Example\", \"svelte\")\n<script>\nimport { router } from '@inertiajs/svelte'\nimport { onMount, onDestroy } from 'svelte'\n\nexport let stats\n\nlet interval\n\nonMount(() => {\n    interval = setInterval(() => {\n        router.reload({ only: ['stats'] })\n    }, 5000) // Poll every 5 seconds\n})\n\nonDestroy(() => {\n    clearInterval(interval)\n})\n</script>\n\n<div>\n    <h1>Dashboard</h1>\n    <div>Active Users: {stats.activeUsers}</div>\n</div>\n@endboostsnippet\n\n### WhenVisible\n\nLazy-load a prop when an element scrolls into view. Useful for deferring expensive data that sits below the fold:\n\n@boostsnippet(\"WhenVisible Example\", \"svelte\")\n<script>\nimport { WhenVisible } from '@inertiajs/svelte'\n\nexport let stats\n</script>\n\n<div>\n    <h1>Dashboard</h1>\n\n    <!-- stats prop is loaded only when this section scrolls into view -->\n    <WhenVisible data=\"stats\" buffer={200}>\n        <div>\n            <p>Total Users: {stats.total_users}</p>\n            <p>Revenue: {stats.revenue}</p>\n        </div>\n\n        <svelte:fragment slot=\"fallback\">\n            <div class=\"animate-pulse\">Loading stats...</div>\n        </svelte:fragment>\n    </WhenVisible>\n</div>\n@endboostsnippet\n\n## Server-Side Patterns\n\nServer-side patterns (Inertia::render, props, middleware) are covered in inertia-laravel guidelines.\n\n## Common Pitfalls\n\n- Using traditional `<a>` links instead of Inertia's `<Link>` component (breaks SPA behavior)\n- Forgetting to add loading states (skeleton screens) when using deferred props\n- Not handling the `undefined` state of deferred props before data loads\n- Using `<form>` without preventing default submission (use `<Form>` component or `on:submit|preventDefault`)\n- Forgetting to check if `<Form>` component is available in your Inertia version\n"
  },
  {
    "path": "packages/svelte/src/components/App.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  import type { ComponentResolver, ResolvedComponent } from '../types'\n  import { type Page, type PageProps } from '@inertiajs/core'\n\n  export interface InertiaAppProps<SharedProps extends PageProps = PageProps> {\n    initialComponent: ResolvedComponent\n    initialPage: Page<SharedProps>\n    resolveComponent: ComponentResolver\n  }\n</script>\n\n<script lang=\"ts\">\n  import type { LayoutType, LayoutResolver } from '../types'\n  import { router } from '@inertiajs/core'\n  import Render, { h, type RenderProps } from './Render.svelte'\n  import { setPage } from '../page'\n\n  export let initialComponent: InertiaAppProps['initialComponent']\n  export let initialPage: InertiaAppProps['initialPage']\n  export let resolveComponent: InertiaAppProps['resolveComponent']\n\n  let component = initialComponent\n  let key: number | null = null\n  let page = { ...initialPage, flash: initialPage.flash ?? {} }\n  let renderProps = resolveRenderProps(component, page, key)\n\n  setPage(page)\n\n  const isServer = typeof window === 'undefined'\n\n  if (!isServer) {\n    router.init<ResolvedComponent>({\n      initialPage,\n      resolveComponent,\n      swapComponent: async (args) => {\n        component = args.component\n        page = args.page\n        key = args.preserveState ? key : Date.now()\n\n        renderProps = resolveRenderProps(component, page, key)\n        setPage(page)\n      },\n      onFlash: (flash) => {\n        page = { ...page, flash }\n        setPage(page)\n      },\n    })\n  }\n\n  /**\n   * Resolves the render props for the current page component, including layouts.\n   */\n  function resolveRenderProps(component: ResolvedComponent, page: Page, key: number | null = null): RenderProps {\n    const child = h(component.default, page.props, [], key)\n    const layout = component.layout\n\n    return layout ? resolveLayout(layout, child, page.props, key) : child\n  }\n\n  /**\n   * Builds the nested layout structure by wrapping the child component with the provided layouts.\n   *\n   * Resulting nested structure:\n   *\n   *    {\n   *      \"component\": OuterLayout,\n   *      \"key\": 123456,\n   *      \"children\": [{\n   *        \"component\": InnerLayout,\n   *        \"key\": 123456,\n   *        \"children\": [{\n   *          \"component\": PageComponent,\n   *          \"key\": 123456,\n   *          \"children\": [],\n   *        }],\n   *      }],\n   *    }\n   */\n  function resolveLayout(\n    layout: LayoutType,\n    child: RenderProps,\n    pageProps: PageProps,\n    key: number | null,\n  ): RenderProps {\n    if (isLayoutFunction(layout)) {\n      return layout(h, child)\n    }\n\n    if (Array.isArray(layout)) {\n      return layout\n        .slice()\n        .reverse()\n        .reduce((currentRender, layoutComponent) => h(layoutComponent, pageProps, [currentRender], key), child)\n    }\n\n    return h(layout, pageProps, child ? [child] : [], key)\n  }\n\n  /**\n   * Type guard to check if layout is a LayoutResolver\n   */\n  function isLayoutFunction(layout: LayoutType): layout is LayoutResolver {\n    return typeof layout === 'function' && layout.length === 2 && typeof layout.prototype === 'undefined'\n  }\n</script>\n\n<Render {...renderProps} />\n"
  },
  {
    "path": "packages/svelte/src/components/Deferred.svelte",
    "content": "<script lang=\"ts\">\n  import { page } from '../index'\n\n  export let data: string | string[]\n\n  const keys = Array.isArray(data) ? data : [data]\n\n  // Synchronously derive loaded state from current props\n  // This ensures we never render slot content when props are undefined\n  $: loaded = keys.every((key) => typeof $page.props[key] !== 'undefined')\n\n  if (!$$slots.fallback) {\n    throw new Error('`<Deferred>` requires a `<svelte:fragment slot=\"fallback\">` slot')\n  }\n</script>\n\n{#if loaded}\n  <slot />\n{:else}\n  <slot name=\"fallback\" />\n{/if}\n"
  },
  {
    "path": "packages/svelte/src/components/Form.svelte",
    "content": "<script lang=\"ts\">\n  import {\n    config,\n    formDataToObject,\n    FormComponentResetSymbol,\n    resetFormFields,\n    mergeDataIntoQueryString,\n    type Errors,\n    type FormComponentProps,\n    type FormComponentRef,\n    type Method,\n    type FormDataConvertible,\n    type VisitOptions,\n    isUrlMethodPair,\n    UseFormUtils,\n  } from '@inertiajs/core'\n  import { type NamedInputEvent, type ValidationConfig, type Validator } from 'laravel-precognition'\n  import { isEqual } from 'lodash-es'\n  import { onMount, setContext } from 'svelte'\n  import { writable } from 'svelte/store'\n  import { FormContextKey } from './formContext'\n  import useForm from '../useForm'\n\n  const noop = () => undefined\n\n  export let action: FormComponentProps['action'] = ''\n  export let method: FormComponentProps['method'] = 'get'\n  export let headers: FormComponentProps['headers'] = {}\n  export let queryStringArrayFormat: FormComponentProps['queryStringArrayFormat'] = 'brackets'\n  export let errorBag: FormComponentProps['errorBag'] = null\n  export let showProgress: FormComponentProps['showProgress'] = true\n  export let transform: FormComponentProps['transform'] = (data) => data\n  export let options: FormComponentProps['options'] = {}\n  export let onCancelToken: FormComponentProps['onCancelToken'] = noop\n  export let onBefore: FormComponentProps['onBefore'] = noop\n  export let onStart: FormComponentProps['onStart'] = noop\n  export let onProgress: FormComponentProps['onProgress'] = noop\n  export let onFinish: FormComponentProps['onFinish'] = noop\n  export let onCancel: FormComponentProps['onCancel'] = noop\n  export let onSuccess: FormComponentProps['onSuccess'] = noop\n  export let onError: FormComponentProps['onError'] = noop\n  export let onSubmitComplete: FormComponentProps['onSubmitComplete'] = noop\n  export let disableWhileProcessing: boolean = false\n  export let invalidateCacheTags: FormComponentProps['invalidateCacheTags'] = []\n  export let resetOnError: FormComponentProps['resetOnError'] = false\n  export let resetOnSuccess: FormComponentProps['resetOnSuccess'] = false\n  export let setDefaultsOnSuccess: FormComponentProps['setDefaultsOnSuccess'] = false\n  export let validateFiles: FormComponentProps['validateFiles'] = false\n  export let validationTimeout: FormComponentProps['validationTimeout'] = 1500\n  export let withAllErrors: FormComponentProps['withAllErrors'] = null\n\n  type FormSubmitOptions = Omit<VisitOptions, 'data' | 'onPrefetched' | 'onPrefetching'>\n  type FormSubmitter = HTMLElement | null\n\n  const getTransformedData = (): Record<string, FormDataConvertible> => {\n    const [_url, data] = getUrlAndData()\n    return transform!(data)\n  }\n\n  const form = useForm<Record<string, any>>({})\n    .withPrecognition(\n      () => _method,\n      () => getUrlAndData()[0],\n    )\n    .setValidationTimeout(validationTimeout!)\n\n  if (validateFiles) {\n    form.validateFiles()\n  }\n\n  if (withAllErrors ?? config.get('form.withAllErrors')) {\n    form.withAllErrors()\n  }\n\n  form.transform(getTransformedData)\n\n  let formElement: HTMLFormElement\n  let isDirty = false\n  let defaultData: FormData = new FormData()\n\n  $: _method = isUrlMethodPair(action) ? action.method : ((method ?? 'get').toLowerCase() as Method)\n  $: _action = isUrlMethodPair(action) ? action.url : (action as string)\n\n  export function getFormData(submitter?: FormSubmitter): FormData {\n    return new FormData(formElement, submitter)\n  }\n\n  // Convert the FormData to an object because we can't compare two FormData\n  // instances directly (which is needed for isDirty), mergeDataIntoQueryString()\n  // expects an object, and submitting a FormData instance directly causes problems with nested objects.\n  export function getData(submitter?: FormSubmitter): Record<string, FormDataConvertible> {\n    return formDataToObject(getFormData(submitter))\n  }\n\n  function getUrlAndData(submitter?: FormSubmitter): [string, Record<string, FormDataConvertible>] {\n    return mergeDataIntoQueryString(_method, _action, getData(submitter), queryStringArrayFormat)\n  }\n\n  function updateDirtyState(event: Event) {\n    if (event.type === 'reset' && (event as CustomEvent).detail?.[FormComponentResetSymbol]) {\n      // When the form is reset programmatically, prevent native reset behavior\n      event.preventDefault()\n    }\n\n    isDirty = event.type === 'reset' ? false : !isEqual(getData(), formDataToObject(defaultData))\n  }\n\n  export function submit(submitter?: FormSubmitter) {\n    const [url, data] = getUrlAndData(submitter)\n    const formTarget = (submitter as HTMLButtonElement | HTMLInputElement | null)?.getAttribute('formtarget')\n\n    if (formTarget === '_blank' && _method === 'get') {\n      window.open(url, '_blank')\n      return\n    }\n\n    const maybeReset = (resetOption: boolean | string[] | undefined) => {\n      if (!resetOption) {\n        return\n      }\n\n      if (resetOption === true) {\n        reset()\n      } else if (resetOption.length > 0) {\n        reset(...resetOption)\n      }\n    }\n\n    const submitOptions: FormSubmitOptions = {\n      headers,\n      queryStringArrayFormat,\n      errorBag,\n      showProgress,\n      invalidateCacheTags,\n      onCancelToken,\n      onBefore,\n      onStart,\n      onProgress,\n      onFinish,\n      onCancel,\n      onSuccess: (...args) => {\n        if (onSuccess) {\n          onSuccess(...args)\n        }\n\n        if (onSubmitComplete) {\n          onSubmitComplete({\n            reset,\n            defaults,\n          })\n        }\n\n        maybeReset(resetOnSuccess)\n\n        if (setDefaultsOnSuccess === true) {\n          defaults()\n        }\n      },\n      onError: (...args) => {\n        if (onError) {\n          onError(...args)\n        }\n\n        maybeReset(resetOnError)\n      },\n      ...options,\n    }\n\n    // We need transform because we can't override the default data with different keys (by design)\n    $form.transform(() => transform!(data)).submit(_method, url, submitOptions)\n\n    // Reset the transformer back so the submitter is not used for future submissions\n    $form.transform(getTransformedData)\n  }\n\n  function handleSubmit(event: SubmitEvent) {\n    event.preventDefault()\n    submit(event.submitter)\n  }\n\n  function handleReset(event: Event) {\n    // Only intercept native reset events (from reset buttons/inputs)\n    if (event.isTrusted) {\n      event.preventDefault()\n      reset()\n    }\n  }\n\n  export function reset(...fields: string[]) {\n    resetFormFields(formElement, defaultData, fields)\n\n    form.reset(...fields)\n  }\n\n  export function clearErrors(...fields: string[]) {\n    $form.clearErrors(...fields)\n  }\n\n  export function resetAndClearErrors(...fields: string[]) {\n    clearErrors(...fields)\n    reset(...fields)\n  }\n\n  export function setError(fieldOrFields: string | Record<string, string>, maybeValue?: string) {\n    $form.setError((typeof fieldOrFields === 'string' ? { [fieldOrFields]: maybeValue } : fieldOrFields) as Errors)\n  }\n\n  export function defaults() {\n    defaultData = getFormData()\n    isDirty = false\n  }\n\n  export function validate(field?: string | NamedInputEvent | ValidationConfig, config?: ValidationConfig) {\n    return form.validate(...UseFormUtils.mergeHeadersForValidation(field, config, headers!))\n  }\n\n  export function valid(field: string) {\n    return form.valid(field)\n  }\n\n  export function invalid(field: string) {\n    return form.invalid(field)\n  }\n\n  export function touch(field: string | NamedInputEvent | string[], ...fields: string[]) {\n    return form.touch(field, ...fields)\n  }\n\n  export function touched(field?: string) {\n    return form.touched(field)\n  }\n\n  export function validator(): Validator {\n    return form.validator()\n  }\n\n  onMount(() => {\n    defaultData = getFormData()\n\n    form.defaults(getData())\n\n    const formEvents: Array<keyof HTMLElementEventMap> = ['input', 'change', 'reset']\n\n    formEvents.forEach((e) => formElement.addEventListener(e, updateDirtyState))\n\n    return () => {\n      formEvents.forEach((e) => formElement?.removeEventListener(e, updateDirtyState))\n    }\n  })\n\n  $: {\n    form.setValidationTimeout(validationTimeout!)\n\n    if (validateFiles) {\n      form.validateFiles()\n    } else {\n      form.withoutFileValidation()\n    }\n  }\n\n  $: slotErrors = $form.errors as Errors\n\n  // Form context for child components\n  const formContextStore = writable<FormComponentRef | undefined>(undefined)\n\n  $: formContextStore.set({\n    errors: $form.errors,\n    hasErrors: $form.hasErrors,\n    processing: $form.processing,\n    progress: $form.progress,\n    wasSuccessful: $form.wasSuccessful,\n    recentlySuccessful: $form.recentlySuccessful,\n    isDirty,\n    clearErrors,\n    resetAndClearErrors,\n    setError,\n    reset,\n    submit,\n    defaults,\n    getData,\n    getFormData,\n    // Precognition\n    validator,\n    validate,\n    touch,\n    validating: $form.validating,\n    valid,\n    invalid,\n    touched,\n  })\n\n  setContext(FormContextKey, formContextStore)\n</script>\n\n<form\n  bind:this={formElement}\n  action={_action}\n  method={_method}\n  on:submit={handleSubmit}\n  on:reset={handleReset}\n  {...$$restProps}\n  inert={disableWhileProcessing && $form.processing ? true : undefined}\n>\n  <slot\n    errors={slotErrors}\n    hasErrors={$form.hasErrors}\n    processing={$form.processing}\n    progress={$form.progress}\n    wasSuccessful={$form.wasSuccessful}\n    recentlySuccessful={$form.recentlySuccessful}\n    {clearErrors}\n    {resetAndClearErrors}\n    {setError}\n    {isDirty}\n    {submit}\n    {defaults}\n    {reset}\n    {getData}\n    {getFormData}\n    {validator}\n    {validate}\n    {touch}\n    validating={$form.validating}\n    valid={$form.valid}\n    invalid={$form.invalid}\n    touched={$form.touched}\n  />\n</form>\n"
  },
  {
    "path": "packages/svelte/src/components/InfiniteScroll.svelte",
    "content": "<script lang=\"ts\">\n  import {\n    getScrollableParent,\n    type InfiniteScrollActionSlotProps,\n    type InfiniteScrollComponentBaseProps,\n    type UseInfiniteScrollProps,\n    type InfiniteScrollSlotProps,\n    useInfiniteScroll,\n  } from '@inertiajs/core'\n  import { onDestroy, onMount } from 'svelte'\n\n  export let data: InfiniteScrollComponentBaseProps['data']\n  export let buffer: InfiniteScrollComponentBaseProps['buffer'] = 0\n  export let as: InfiniteScrollComponentBaseProps['as'] = 'div'\n  export let manual: InfiniteScrollComponentBaseProps['manual'] = false\n  export let manualAfter: InfiniteScrollComponentBaseProps['manualAfter'] = 0\n  export let preserveUrl: InfiniteScrollComponentBaseProps['preserveUrl'] = false\n  export let reverse: InfiniteScrollComponentBaseProps['reverse'] = false\n  export let autoScroll: InfiniteScrollComponentBaseProps['autoScroll'] = undefined\n  export let startElement: string | (() => HTMLElement | null) | null = null\n  export let endElement: string | (() => HTMLElement | null) | null = null\n  export let itemsElement: string | (() => HTMLElement | null) | null = null\n  export let onlyNext = false\n  export let onlyPrevious = false\n\n  let itemsElementRef: HTMLElement\n  let startElementRef: HTMLElement\n  let endElementRef: HTMLElement\n  let loadingPrevious = false\n  let loadingNext = false\n  let requestCount = 0\n  let hasPreviousPage = false\n  let hasNextPage = false\n\n  $: resolvedItemsElement = resolveHTMLElement(itemsElement, itemsElementRef)\n  $: scrollableParent = resolvedItemsElement ? getScrollableParent(resolvedItemsElement) : null\n\n  $: sharedExposed = {\n    loadingPrevious,\n    loadingNext,\n    hasPrevious: hasPreviousPage,\n    hasNext: hasNextPage,\n  } satisfies Pick<InfiniteScrollActionSlotProps, 'loadingPrevious' | 'loadingNext' | 'hasPrevious' | 'hasNext'>\n\n  $: exposedPrevious = {\n    loading: loadingPrevious,\n    fetch: fetchPrevious,\n    autoMode: headerAutoMode,\n    manualMode: !headerAutoMode,\n    hasMore: hasPreviousPage,\n    ...sharedExposed,\n  } satisfies InfiniteScrollActionSlotProps\n\n  $: exposedNext = {\n    loading: loadingNext,\n    fetch: fetchNext,\n    autoMode: footerAutoMode,\n    manualMode: !footerAutoMode,\n    hasMore: hasNextPage,\n    ...sharedExposed,\n  } satisfies InfiniteScrollActionSlotProps\n\n  $: exposedSlot = {\n    loading: loadingPrevious || loadingNext,\n    loadingPrevious,\n    loadingNext,\n  } satisfies InfiniteScrollSlotProps\n\n  let infiniteScrollInstance: UseInfiniteScrollProps | null = null\n\n  function resolveHTMLElement(\n    value: string | (() => HTMLElement | null) | null,\n    fallback: HTMLElement | null,\n  ): HTMLElement | null {\n    if (!value) {\n      return fallback\n    }\n\n    if (typeof value === 'string') {\n      return document.querySelector(value) as HTMLElement | null\n    }\n\n    if (typeof value === 'function') {\n      return value() || null\n    }\n\n    return fallback\n  }\n\n  function scrollToBottom() {\n    if (scrollableParent) {\n      scrollableParent.scrollTo({\n        top: scrollableParent.scrollHeight,\n        behavior: 'instant',\n      })\n    } else {\n      window.scrollTo({\n        top: document.body.scrollHeight,\n        behavior: 'instant',\n      })\n    }\n  }\n\n  export function fetchPrevious(options?: any) {\n    infiniteScrollInstance?.dataManager.fetchPrevious(options)\n  }\n\n  export function fetchNext(options?: any) {\n    infiniteScrollInstance?.dataManager.fetchNext(options)\n  }\n\n  export function hasPrevious(): boolean {\n    return infiniteScrollInstance?.dataManager.hasPrevious() || false\n  }\n\n  export function hasNext(): boolean {\n    return infiniteScrollInstance?.dataManager.hasNext() || false\n  }\n\n  onMount(() => {\n    setTimeout(setupInfiniteScrollInstance)\n  })\n\n  function syncStateFromDataManager() {\n    requestCount = infiniteScrollInstance!.dataManager.getRequestCount()\n    hasPreviousPage = infiniteScrollInstance!.dataManager.hasPrevious()\n    hasNextPage = infiniteScrollInstance!.dataManager.hasNext()\n  }\n\n  function setupInfiniteScrollInstance() {\n    const resolvedItemsElement = resolveHTMLElement(itemsElement, itemsElementRef)\n    const resolvedStartElement = resolveHTMLElement(startElement, startElementRef)\n    const resolvedEndElement = resolveHTMLElement(endElement, endElementRef)\n\n    infiniteScrollInstance = useInfiniteScroll({\n      // Data\n      getPropName: () => data,\n      inReverseMode: () => reverse ?? false,\n      shouldFetchNext: () => !onlyPrevious,\n      shouldFetchPrevious: () => !onlyNext,\n      shouldPreserveUrl: () => preserveUrl ?? false,\n\n      // Elements\n      getTriggerMargin: () => buffer ?? 0,\n      getStartElement: () => resolvedStartElement!,\n      getEndElement: () => resolvedEndElement!,\n      getItemsElement: () => resolvedItemsElement!,\n      getScrollableParent: () => (resolvedItemsElement ? getScrollableParent(resolvedItemsElement) : null),\n\n      // Request callbacks\n      onBeforePreviousRequest: () => (loadingPrevious = true),\n      onBeforeNextRequest: () => (loadingNext = true),\n      onCompletePreviousRequest: () => {\n        loadingPrevious = false\n        syncStateFromDataManager()\n      },\n      onCompleteNextRequest: () => {\n        loadingNext = false\n        syncStateFromDataManager()\n      },\n      onDataReset: syncStateFromDataManager,\n    })\n\n    const { dataManager, elementManager } = infiniteScrollInstance\n\n    syncStateFromDataManager()\n\n    elementManager.setupObservers()\n    elementManager.processServerLoadedElements(dataManager.getLastLoadedPage())\n\n    // autoScroll defaults to reverse value if not explicitly set\n    const shouldAutoScroll = autoScroll !== undefined ? autoScroll : reverse\n\n    if (shouldAutoScroll) {\n      scrollToBottom()\n    }\n  }\n\n  $: manualMode = manual || (manualAfter !== undefined && manualAfter > 0 && requestCount >= manualAfter)\n  $: autoLoad = !manualMode\n\n  $: headerAutoMode = autoLoad && !onlyNext\n  $: footerAutoMode = autoLoad && !onlyPrevious\n\n  $: {\n    // Make this block run whenever these change\n    ;[autoLoad, onlyNext, onlyPrevious, reverse]\n\n    autoLoad\n      ? infiniteScrollInstance?.elementManager.enableTriggers()\n      : infiniteScrollInstance?.elementManager.disableTriggers()\n  }\n\n  onDestroy(() => infiniteScrollInstance?.flush())\n</script>\n\n{#if !startElement && !reverse}\n  <div bind:this={startElementRef}>\n    <slot name=\"previous\" {exposedPrevious} {...exposedPrevious}>\n      {#if loadingPrevious}\n        <slot name=\"loading\" {exposedPrevious} {...exposedPrevious} />\n      {/if}\n    </slot>\n  </div>\n{/if}\n\n{#if !endElement && reverse}\n  <div bind:this={endElementRef}>\n    <slot name=\"next\" {exposedNext} {...exposedNext}>\n      {#if loadingNext}\n        <slot name=\"loading\" {exposedNext} {...exposedNext} />\n      {/if}\n    </slot>\n  </div>\n{/if}\n\n<svelte:element this={as} bind:this={itemsElementRef} {...$$restProps}>\n  <slot {exposedSlot} {...exposedSlot} />\n</svelte:element>\n\n{#if !startElement && reverse}\n  <div bind:this={startElementRef}>\n    <slot name=\"previous\" {exposedPrevious} {...exposedPrevious}>\n      {#if loadingPrevious}\n        <slot name=\"loading\" {exposedPrevious} {...exposedPrevious} />\n      {/if}\n    </slot>\n  </div>\n{/if}\n\n{#if !endElement && !reverse}\n  <div bind:this={endElementRef}>\n    <slot name=\"next\" {exposedNext} {...exposedNext}>\n      {#if loadingNext}\n        <slot name=\"loading\" {exposedNext} {...exposedNext} />\n      {/if}\n    </slot>\n  </div>\n{/if}\n"
  },
  {
    "path": "packages/svelte/src/components/Link.svelte",
    "content": "<script lang=\"ts\">\n  import { isUrlMethodPair } from '@inertiajs/core'\n  import type { LinkComponentBaseProps } from '@inertiajs/core'\n  import { inertia } from '../index'\n\n  export let href: LinkComponentBaseProps['href'] = ''\n  export let as: keyof HTMLElementTagNameMap = 'a'\n  export let data: LinkComponentBaseProps['data'] = {}\n  export let method: LinkComponentBaseProps['method'] = 'get'\n  export let replace: LinkComponentBaseProps['replace'] = false\n  export let preserveScroll: LinkComponentBaseProps['preserveScroll'] = false\n  export let preserveState: LinkComponentBaseProps['preserveState'] | null = null\n  export let preserveUrl: LinkComponentBaseProps['preserveUrl'] = false\n  export let only: LinkComponentBaseProps['only'] = []\n  export let except: LinkComponentBaseProps['except'] = []\n  export let headers: LinkComponentBaseProps['headers'] = {}\n  export let queryStringArrayFormat: LinkComponentBaseProps['queryStringArrayFormat'] = 'brackets'\n  export let async: LinkComponentBaseProps['async'] = false\n  export let prefetch: LinkComponentBaseProps['prefetch'] = false\n  export let cacheFor: LinkComponentBaseProps['cacheFor'] = 0\n  export let cacheTags: LinkComponentBaseProps['cacheTags'] = []\n  export let viewTransition: LinkComponentBaseProps['viewTransition'] = false\n\n  $: _method = isUrlMethodPair(href) ? href.method : method\n  $: _href = isUrlMethodPair(href) ? href.url : href\n\n  $: asProp = _method !== 'get' ? 'button' : as.toLowerCase()\n  $: elProps =\n    {\n      a: { href: _href },\n      button: { type: 'button' },\n    }[asProp] || {}\n</script>\n\n<!-- svelte-ignore a11y-no-static-element-interactions -->\n<svelte:element\n  this={asProp}\n  use:inertia={{\n    ...(asProp !== 'a' ? { href: _href } : {}),\n    data,\n    method: _method,\n    replace,\n    preserveScroll,\n    preserveState: preserveState ?? _method !== 'get',\n    preserveUrl,\n    only,\n    except,\n    headers,\n    queryStringArrayFormat,\n    async,\n    prefetch,\n    cacheFor,\n    cacheTags,\n    viewTransition,\n  }}\n  {...$$restProps}\n  {...elProps}\n  on:focus\n  on:blur\n  on:click\n  on:dblclick\n  on:mousedown\n  on:mousemove\n  on:mouseout\n  on:mouseover\n  on:mouseup\n  on:cancel-token\n  on:before\n  on:start\n  on:progress\n  on:finish\n  on:cancel\n  on:success\n  on:error\n  on:prefetching\n  on:prefetched\n>\n  <slot />\n</svelte:element>\n"
  },
  {
    "path": "packages/svelte/src/components/Render.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  import type { PageProps } from '@inertiajs/core'\n  import type { ComponentType } from 'svelte'\n\n  export type RenderProps = {\n    component: ComponentType\n    props?: PageProps\n    children?: RenderProps[]\n    key?: number | null\n  }\n\n  export type RenderFunction = {\n    (component: ComponentType, props?: PageProps, children?: RenderProps[], key?: number | null): RenderProps\n    (component: ComponentType, children?: RenderProps[], key?: number | null): RenderProps\n  }\n\n  export const h: RenderFunction = (component, propsOrChildren, childrenOrKey, key: number | null = null) => {\n    const hasProps = typeof propsOrChildren === 'object' && propsOrChildren !== null && !Array.isArray(propsOrChildren)\n\n    return {\n      component,\n      key: hasProps ? key : typeof childrenOrKey === 'number' ? childrenOrKey : null,\n      props: hasProps ? propsOrChildren : {},\n      children: hasProps\n        ? ((Array.isArray(childrenOrKey)\n            ? childrenOrKey\n            : childrenOrKey !== null\n              ? [childrenOrKey]\n              : []) as RenderProps[])\n        : ((Array.isArray(propsOrChildren)\n            ? propsOrChildren\n            : propsOrChildren !== null\n              ? [propsOrChildren]\n              : []) as RenderProps[]),\n    }\n  }\n</script>\n\n<script lang=\"ts\">\n  export let component: ComponentType\n  export let props: PageProps = {}\n  export let children: RenderProps[] = []\n  export let key: number | null = null\n</script>\n\n{#if component}\n  <!--\n  Add the `key` only to the last (page) component in the tree.\n  This ensures that the page component re-renders when `preserveState` is disabled,\n  while the layout components are persisted across page changes. -->\n  {#key children?.length === 0 ? key : null}\n    {#if children.length > 0}\n      <svelte:component this={component} {...props}>\n        {#each children as child}\n          <svelte:self {...child} />\n        {/each}\n      </svelte:component>\n    {:else}\n      <svelte:component this={component} {...props} />\n    {/if}\n  {/key}\n{/if}\n"
  },
  {
    "path": "packages/svelte/src/components/WhenVisible.svelte",
    "content": "<script lang=\"ts\">\n  import { router, type ReloadOptions } from '@inertiajs/core'\n  import { onDestroy } from 'svelte'\n  import { usePage } from '../page'\n\n  export let data: string | string[] = ''\n  export let params: ReloadOptions = {}\n  export let buffer: number = 0\n  export let as: keyof HTMLElementTagNameMap = 'div'\n  export let always: boolean = false\n\n  let loaded = false\n  let fetching = false\n  let el: HTMLElement\n  let observer: IntersectionObserver | null = null\n\n  const page = usePage()\n  $: keys = data ? (Array.isArray(data) ? data : [data]) : []\n  $: loaded = keys.length > 0 && keys.every((key) => $page.props[key] !== undefined)\n\n  $: if (el && (!loaded || always)) {\n    registerObserver()\n  }\n\n  function registerObserver() {\n    observer?.disconnect()\n\n    observer = new IntersectionObserver(\n      (entries) => {\n        if (!entries[0].isIntersecting) {\n          return\n        }\n\n        if (fetching) {\n          return\n        }\n\n        if (!always && loaded) {\n          return\n        }\n\n        fetching = true\n\n        const reloadParams = getReloadParams()\n\n        router.reload({\n          ...reloadParams,\n          onStart: (event) => {\n            fetching = true\n            reloadParams.onStart?.(event)\n          },\n          onFinish: (event) => {\n            loaded = true\n            fetching = false\n            reloadParams.onFinish?.(event)\n\n            if (!always) {\n              observer?.disconnect()\n            }\n          },\n        })\n      },\n      {\n        rootMargin: `${buffer}px`,\n      },\n    )\n\n    observer.observe(el)\n  }\n\n  onDestroy(() => {\n    observer?.disconnect()\n  })\n\n  function getReloadParams(): Partial<ReloadOptions> {\n    const reloadParams: Partial<ReloadOptions> = { ...params }\n\n    if (data !== '') {\n      reloadParams.only = (Array.isArray(data) ? data : [data]) as string[]\n    }\n\n    return reloadParams\n  }\n</script>\n\n{#if always || !loaded}\n  <svelte:element this={as} bind:this={el} />\n{/if}\n\n{#if loaded}\n  <slot {fetching} />\n{:else if $$slots.fallback}\n  <slot name=\"fallback\" />\n{/if}\n"
  },
  {
    "path": "packages/svelte/src/components/formContext.ts",
    "content": "import type { FormComponentRef } from '@inertiajs/core'\nimport { getContext } from 'svelte'\nimport type { Readable } from 'svelte/store'\n\nexport const FormContextKey = Symbol('InertiaFormContext')\n\nexport function useFormContext(): Readable<FormComponentRef> | undefined {\n  return getContext(FormContextKey)\n}\n"
  },
  {
    "path": "packages/svelte/src/createInertiaApp.ts",
    "content": "import {\n  getInitialPageFromDOM,\n  router,\n  setupProgress,\n  type CreateInertiaAppOptionsForCSR,\n  type InertiaAppResponse,\n  type Page,\n  type PageProps,\n  type SharedPageProps,\n} from '@inertiajs/core'\nimport { escape } from 'lodash-es'\nimport App, { type InertiaAppProps } from './components/App.svelte'\nimport { config } from './index'\nimport type { ComponentResolver, SvelteInertiaAppConfig } from './types'\n\ntype SvelteRenderResult = { html: string; head: string; css?: { code: string } }\n\ntype SetupOptions<SharedProps extends PageProps> = {\n  el: HTMLElement | null\n  App: typeof App\n  props: InertiaAppProps<SharedProps>\n}\n\n// Svelte doesn't use CreateInertiaAppOptionsForSSR as it doesn't pass a\n// 'render' function, it calls it directly in the setup() method...\ntype InertiaAppOptions<SharedProps extends PageProps> = CreateInertiaAppOptionsForCSR<\n  SharedProps,\n  ComponentResolver,\n  SetupOptions<SharedProps>,\n  SvelteRenderResult | void,\n  SvelteInertiaAppConfig\n>\n\nexport default async function createInertiaApp<SharedProps extends PageProps = PageProps & SharedPageProps>({\n  id = 'app',\n  resolve,\n  setup,\n  progress = {},\n  page,\n  defaults = {},\n}: InertiaAppOptions<SharedProps>): InertiaAppResponse {\n  config.replace(defaults)\n\n  const isServer = typeof window === 'undefined'\n  const useScriptElementForInitialPage = config.get('future.useScriptElementForInitialPage')\n  const initialPage = page || getInitialPageFromDOM<Page<SharedProps>>(id, useScriptElementForInitialPage)!\n\n  const resolveComponent = (name: string) => Promise.resolve(resolve(name))\n\n  const svelteApp = await Promise.all([\n    resolveComponent(initialPage.component),\n    router.decryptHistory().catch(() => {}),\n  ]).then(([initialComponent]) => {\n    return setup({\n      el: isServer ? null : document.getElementById(id),\n      App,\n      props: { initialPage, initialComponent, resolveComponent },\n    })\n  })\n\n  if (isServer && svelteApp) {\n    const { html, head, css } = svelteApp\n\n    return {\n      body: useScriptElementForInitialPage\n        ? `<script data-page=\"${id}\" type=\"application/json\">${JSON.stringify(initialPage).replace(/\\//g, '\\\\/')}</script><div data-server-rendered=\"true\" id=\"${id}\">${html}</div>`\n        : `<div data-server-rendered=\"true\" id=\"${id}\" data-page=\"${escape(JSON.stringify(initialPage))}\">${html}</div>`,\n      head: [head, css ? `<style data-vite-css>${css.code}</style>` : ''],\n    }\n  }\n\n  if (!isServer && progress) {\n    setupProgress(progress)\n  }\n}\n"
  },
  {
    "path": "packages/svelte/src/index.ts",
    "content": "import { config as coreConfig } from '@inertiajs/core'\nimport type { SvelteInertiaAppConfig } from './types'\n\nexport { progress, router } from '@inertiajs/core'\nexport { default as App } from './components/App.svelte'\nexport { default as Deferred } from './components/Deferred.svelte'\nexport { default as Form } from './components/Form.svelte'\nexport { useFormContext } from './components/formContext'\nexport { default as InfiniteScroll } from './components/InfiniteScroll.svelte'\nexport { default as Link } from './components/Link.svelte'\nexport { default as WhenVisible } from './components/WhenVisible.svelte'\nexport { default as createInertiaApp } from './createInertiaApp'\nexport { default as inertia } from './link'\nexport { default as page, usePage } from './page'\nexport { type ResolvedComponent, type SvelteInertiaAppConfig } from './types'\nexport { default as useForm, type InertiaForm, type InertiaFormProps, type InertiaPrecognitiveForm } from './useForm'\nexport { default as usePoll } from './usePoll'\nexport { default as usePrefetch } from './usePrefetch'\nexport { default as useRemember } from './useRemember'\n\nexport const config = coreConfig.extend<SvelteInertiaAppConfig>({})\n"
  },
  {
    "path": "packages/svelte/src/link.ts",
    "content": "import {\n  isUrlMethodPair,\n  mergeDataIntoQueryString,\n  router,\n  shouldIntercept,\n  shouldNavigate,\n  type CacheForOption,\n  type CancelToken,\n  type GlobalEventsMap,\n  type LinkComponentBaseProps,\n  type LinkPrefetchOption,\n  type Method,\n  type VisitOptions,\n} from '@inertiajs/core'\nimport type { ActionReturn } from 'svelte/action'\nimport { config } from '.'\n\ntype ActionEventHandlers = {\n  [K in keyof HTMLElementEventMap]?: (event: HTMLElementEventMap[K]) => void\n}\n\ninterface ActionElement extends HTMLElement {\n  href?: string\n}\n\ntype ActionParameters = Omit<LinkComponentBaseProps, 'onCancelToken'> & Omit<VisitOptions, keyof LinkComponentBaseProps>\n\ntype SelectedEventKeys =\n  | 'start'\n  | 'progress'\n  | 'finish'\n  | 'before'\n  | 'cancel'\n  | 'success'\n  | 'error'\n  | 'prefetching'\n  | 'prefetched'\ntype SelectedGlobalEventsMap = Pick<GlobalEventsMap, SelectedEventKeys>\ntype ActionAttributes = {\n  [K in keyof SelectedGlobalEventsMap as `on:${K}` | `on${K}`]?: (\n    event: CustomEvent<SelectedGlobalEventsMap[K]['details']>,\n  ) => void\n} & {\n  'on:cancel-token'?: (event: CustomEvent<CancelToken>) => void\n  oncanceltoken?: (event: CustomEvent<CancelToken>) => void\n}\n\nfunction link(\n  node: ActionElement,\n  initialParams: ActionParameters = {},\n): ActionReturn<ActionParameters, ActionAttributes> {\n  let inFlightCount = 0\n  let hoverTimeout: NodeJS.Timeout\n\n  // Variables initialized and controlled by the \"update\" function\n  let prefetchModes: LinkPrefetchOption[] = []\n  let cacheForValue: CacheForOption | CacheForOption[]\n  let cacheTags: string[] = []\n  let method: Method\n  let href: string\n  let data\n  let baseParams: VisitOptions\n  let visitParams: VisitOptions\n\n  const regularEvents: ActionEventHandlers = {\n    click: (event: MouseEvent) => {\n      if (shouldIntercept(event)) {\n        event.preventDefault()\n        router.visit(href, visitParams)\n      }\n    },\n  }\n\n  const prefetchHoverEvents: ActionEventHandlers = {\n    mouseenter: () => (hoverTimeout = setTimeout(() => prefetch(), config.get('prefetch.hoverDelay'))),\n    mouseleave: () => clearTimeout(hoverTimeout),\n    click: regularEvents.click,\n  }\n\n  const prefetchClickEvents: ActionEventHandlers = {\n    mousedown: (event: MouseEvent) => {\n      if (shouldIntercept(event)) {\n        event.preventDefault()\n        prefetch()\n      }\n    },\n    keydown: (event: KeyboardEvent) => {\n      if (shouldNavigate(event)) {\n        event.preventDefault()\n        prefetch()\n      }\n    },\n    mouseup: (event: MouseEvent) => {\n      if (shouldIntercept(event)) {\n        event.preventDefault()\n        router.visit(href, visitParams)\n      }\n    },\n    keyup: (event: KeyboardEvent) => {\n      if (shouldNavigate(event)) {\n        event.preventDefault()\n        router.visit(href, visitParams)\n      }\n    },\n    click: (event: MouseEvent) => {\n      if (shouldIntercept(event)) {\n        // Let the mouseup/keyup event handle the visit\n        event.preventDefault()\n      }\n    },\n  }\n\n  function update({\n    cacheFor = 0,\n    prefetch = false,\n    cacheTags: cacheTagValues = [],\n    viewTransition = false,\n    ...params\n  }: ActionParameters) {\n    prefetchModes = (() => {\n      if (prefetch === true) {\n        return ['hover']\n      }\n\n      if (prefetch === false) {\n        return []\n      }\n\n      return Array.isArray(prefetch) ? prefetch : [prefetch]\n    })()\n\n    cacheForValue = (() => {\n      if (cacheFor !== 0) {\n        // If they've provided a value, respect it\n        return cacheFor\n      }\n\n      if (prefetchModes.length === 1 && prefetchModes[0] === 'click') {\n        // If they've only provided a prefetch mode of 'click',\n        // we should only prefetch for the next request but not keep it around\n        return 0\n      }\n\n      // Otherwise, default to 30 seconds\n      return config.get('prefetch.cacheFor')\n    })()\n\n    cacheTags = Array.isArray(cacheTagValues) ? cacheTagValues : [cacheTagValues]\n\n    method = isUrlMethodPair(params.href) ? params.href.method : (params.method?.toLowerCase() as Method) || 'get'\n    ;[href, data] = hrefAndData(method, params)\n\n    if (node.tagName === 'A') {\n      node.href = href\n    }\n\n    baseParams = {\n      data,\n      method,\n      replace: params.replace || false,\n      preserveScroll: params.preserveScroll || false,\n      preserveState: params.preserveState ?? method !== 'get',\n      preserveUrl: params.preserveUrl || false,\n      only: params.only || [],\n      except: params.except || [],\n      headers: params.headers || {},\n      async: params.async || false,\n    }\n\n    visitParams = {\n      ...baseParams,\n      viewTransition,\n      onStart: (visit) => {\n        inFlightCount++\n        updateNodeAttributes()\n        return dispatchEvent('start', { detail: { visit } })\n      },\n      onProgress: (progress) => dispatchEvent('progress', { detail: { progress } }),\n      onFinish: (visit) => {\n        inFlightCount--\n        updateNodeAttributes()\n        return dispatchEvent('finish', { detail: { visit } })\n      },\n      onBefore: (visit) => dispatchEvent('before', { cancelable: true, detail: { visit } }),\n      onCancel: () => dispatchEvent('cancel'),\n      onSuccess: (page) => dispatchEvent('success', { detail: { page } }),\n      onError: (errors) => dispatchEvent('error', { detail: { errors } }),\n      onCancelToken: (token) => dispatchEvent('cancel-token', { detail: { token } }),\n      onPrefetching: (visit) => dispatchEvent('prefetching', { detail: { visit } }),\n      onPrefetched: (response, visit) => dispatchEvent('prefetched', { detail: { response, visit } }),\n    }\n\n    updateEventListeners()\n  }\n\n  function dispatchEvent(type: string, detail = {}) {\n    return node.dispatchEvent(new CustomEvent(type, detail))\n  }\n\n  function hrefAndData(method: Method, params: ActionParameters) {\n    return mergeDataIntoQueryString(\n      method,\n      isUrlMethodPair(params.href) ? params.href.url : node.href || params.href || '',\n      params.data || {},\n      params.queryStringArrayFormat || 'brackets',\n    )\n  }\n\n  function prefetch() {\n    router.prefetch(\n      href,\n      {\n        ...baseParams,\n        onPrefetching: (visit) => dispatchEvent('prefetching', { detail: { visit } }),\n        onPrefetched: (response, visit) => dispatchEvent('prefetched', { detail: { response, visit } }),\n      },\n      { cacheFor: cacheForValue, cacheTags },\n    )\n  }\n\n  function updateNodeAttributes() {\n    if (inFlightCount > 0) {\n      node.setAttribute('data-loading', '')\n      return\n    }\n\n    node.removeAttribute('data-loading')\n  }\n\n  function updateEventListeners() {\n    removeEventListeners()\n\n    if (prefetchModes.includes('hover')) {\n      addEventListeners(prefetchHoverEvents)\n      return\n    }\n\n    if (prefetchModes.includes('click')) {\n      addEventListeners(prefetchClickEvents)\n      return\n    }\n\n    addEventListeners(regularEvents)\n  }\n\n  function addEventListeners(eventHandlers: ActionEventHandlers) {\n    Object.entries(eventHandlers).forEach(([event, handler]) => {\n      node.addEventListener(event as keyof HTMLElementEventMap, handler as EventListener)\n    })\n  }\n\n  function removeEventListeners() {\n    ;[prefetchHoverEvents, prefetchClickEvents, regularEvents].forEach((eventHandlers) => {\n      Object.entries(eventHandlers).forEach(([event, handler]) => {\n        node.removeEventListener(event as keyof HTMLElementEventMap, handler as EventListener)\n      })\n    })\n  }\n\n  function destroy() {\n    clearTimeout(hoverTimeout)\n    removeEventListeners()\n  }\n\n  update(initialParams)\n\n  // TODO: Confirm is this needs to rerun when \"prefetchModes\" changes\n  if (prefetchModes.includes('mount')) {\n    prefetch()\n  }\n\n  return { update, destroy }\n}\n\nexport default link\n"
  },
  {
    "path": "packages/svelte/src/page.ts",
    "content": "import { type Page, type PageProps, type SharedPageProps } from '@inertiajs/core'\nimport { derived, writable, type Readable } from 'svelte/store'\n\ntype SveltePage<TPageProps extends PageProps = PageProps> = Omit<Page<TPageProps & SharedPageProps>, 'props'> & {\n  props: Page<TPageProps & SharedPageProps>['props'] & {\n    [key: string]: any\n  }\n}\n\nconst { set, subscribe } = writable<SveltePage>()\n\nexport const setPage = set\n\nexport default { subscribe }\n\nexport function usePage<TPageProps extends PageProps = PageProps>(): Readable<SveltePage<TPageProps>> {\n  return derived({ subscribe }, ($page) => $page as SveltePage<TPageProps>)\n}\n"
  },
  {
    "path": "packages/svelte/src/server.ts",
    "content": "export { default as default } from '@inertiajs/core/server'\n"
  },
  {
    "path": "packages/svelte/src/types.ts",
    "content": "import type { ComponentType } from 'svelte'\nimport type { RenderFunction, RenderProps } from './components/Render.svelte'\n\nexport type ComponentResolver = (name: string) => ResolvedComponent | Promise<ResolvedComponent>\n\nexport type LayoutResolver = (h: RenderFunction, page: RenderProps) => RenderProps\n\nexport type LayoutType = LayoutResolver | ComponentType | ComponentType[]\n\nexport type ResolvedComponent = {\n  default: ComponentType\n  layout?: LayoutType\n}\n\nexport type SvelteInertiaAppConfig = {}\n"
  },
  {
    "path": "packages/svelte/src/useForm.ts",
    "content": "import type {\n  ActiveVisit,\n  CancelToken,\n  Errors,\n  ErrorValue,\n  FormDataErrors,\n  FormDataKeys,\n  FormDataType,\n  FormDataValues,\n  Method,\n  Page,\n  PendingVisit,\n  Progress,\n  RequestPayload,\n  UrlMethodPair,\n  UseFormArguments,\n  UseFormSubmitArguments,\n  UseFormSubmitOptions,\n  UseFormTransformCallback,\n  UseFormWithPrecognitionArguments,\n  VisitOptions,\n} from '@inertiajs/core'\nimport { router, UseFormUtils } from '@inertiajs/core'\nimport type { AxiosProgressEvent } from 'axios'\nimport type { NamedInputEvent, PrecognitionPath, ValidationConfig, Validator } from 'laravel-precognition'\nimport { createValidator, resolveName, toSimpleValidationErrors } from 'laravel-precognition'\nimport { cloneDeep, get, has, isEqual, set } from 'lodash-es'\nimport { get as getStore, writable, type Writable } from 'svelte/store'\nimport { config } from '.'\n\n// Reserved keys validation - logs console.error at runtime when form data keys conflict with form properties\nlet reservedFormKeys: Set<string> | null = null\nlet bootstrapping = false\n\nfunction validateFormDataKeys<TForm extends object>(data: TForm): void {\n  if (bootstrapping) {\n    return\n  }\n\n  if (reservedFormKeys === null) {\n    bootstrapping = true\n    const store = useForm({})\n    // Get the store value to extract form property keys (not the Writable methods)\n    reservedFormKeys = new Set(Object.keys(getStore(store)))\n    bootstrapping = false\n  }\n\n  const conflicts = Object.keys(data).filter((key) => reservedFormKeys!.has(key))\n  if (conflicts.length > 0) {\n    console.error(\n      `[Inertia] useForm() data contains field(s) that conflict with form properties: ${conflicts.map((k) => `\"${k}\"`).join(', ')}. ` +\n        `These fields will be overwritten by form methods/properties. Please rename these fields.`,\n    )\n  }\n}\n\ntype InertiaFormStore<TForm extends object> = Writable<InertiaForm<TForm>> & InertiaForm<TForm>\ntype InertiaPrecognitiveFormStore<TForm extends object> = Writable<InertiaPrecognitiveForm<TForm>> &\n  InertiaPrecognitiveForm<TForm>\n\ntype TransformCallback<TForm> = (data: TForm) => object\n\ntype PrecognitionValidationConfig<TKeys> = ValidationConfig & {\n  only?: TKeys[] | Iterable<TKeys> | ArrayLike<TKeys>\n}\n\nexport interface InertiaFormProps<TForm extends object> {\n  isDirty: boolean\n  errors: FormDataErrors<TForm>\n  hasErrors: boolean\n  progress: Progress | null\n  wasSuccessful: boolean\n  recentlySuccessful: boolean\n  processing: boolean\n  setStore(data: TForm): void\n  setStore<T extends FormDataKeys<TForm>>(key: T, value: FormDataValues<TForm, T>): void\n  data(): TForm\n  transform(callback: UseFormTransformCallback<TForm>): this\n  defaults(): this\n  defaults(fields: Partial<TForm>): this\n  defaults<T extends FormDataKeys<TForm>>(field: T, value: FormDataValues<TForm, T>): this\n  reset<K extends FormDataKeys<TForm>>(...fields: K[]): this\n  clearErrors<K extends FormDataKeys<TForm>>(...fields: K[]): this\n  resetAndClearErrors<K extends FormDataKeys<TForm>>(...fields: K[]): this\n  setError<K extends FormDataKeys<TForm>>(field: K, value: ErrorValue): this\n  setError(errors: FormDataErrors<TForm>): this\n  submit: (...args: UseFormSubmitArguments) => void\n  get(url: string, options?: UseFormSubmitOptions): void\n  post(url: string, options?: UseFormSubmitOptions): void\n  put(url: string, options?: UseFormSubmitOptions): void\n  patch(url: string, options?: UseFormSubmitOptions): void\n  delete(url: string, options?: UseFormSubmitOptions): void\n  cancel(): void\n  dontRemember<K extends FormDataKeys<TForm>>(...fields: K[]): this\n  withPrecognition: (...args: UseFormWithPrecognitionArguments) => InertiaPrecognitiveFormStore<TForm>\n}\n\nexport interface InertiaFormValidationProps<TForm extends object> {\n  invalid<K extends FormDataKeys<TForm>>(field: K): boolean\n  setValidationTimeout(duration: number): this\n  touch<K extends FormDataKeys<TForm>>(field: K | NamedInputEvent | Array<K>, ...fields: K[]): this\n  touched<K extends FormDataKeys<TForm>>(field?: K): boolean\n  valid<K extends FormDataKeys<TForm>>(field: K): boolean\n  validate<K extends FormDataKeys<TForm> | PrecognitionPath<TForm>>(\n    field?: K | NamedInputEvent | PrecognitionValidationConfig<K>,\n    config?: PrecognitionValidationConfig<K>,\n  ): this\n  validateFiles(): this\n  validating: boolean\n  validator: () => Validator\n  withAllErrors(): this\n  withoutFileValidation(): this\n  // Backward compatibility for easy migration from the original Precognition libraries\n  setErrors(errors: FormDataErrors<TForm> | Record<string, string | string[]>): this\n  forgetError<K extends FormDataKeys<TForm> | NamedInputEvent>(field: K): this\n}\n\ninterface InternalPrecognitionState {\n  __touched: string[]\n  __valid: string[]\n}\n\nexport type InertiaForm<TForm extends object> = InertiaFormProps<TForm> & TForm\nexport type InertiaPrecognitiveForm<TForm extends object> = InertiaForm<TForm> & InertiaFormValidationProps<TForm>\n\ntype ReservedFormKeys = keyof InertiaFormProps<any>\n\ntype ValidateFormData<T> = {\n  [K in keyof T]: K extends ReservedFormKeys ? ['Error: This field name is reserved by useForm:', K] : T[K]\n}\n\nexport default function useForm<TForm extends FormDataType<TForm> & ValidateFormData<TForm>>(\n  method: Method | (() => Method),\n  url: string | (() => string),\n  data: TForm | (() => TForm),\n): InertiaPrecognitiveFormStore<TForm>\nexport default function useForm<TForm extends FormDataType<TForm> & ValidateFormData<TForm>>(\n  urlMethodPair: UrlMethodPair | (() => UrlMethodPair),\n  data: TForm | (() => TForm),\n): InertiaPrecognitiveFormStore<TForm>\nexport default function useForm<TForm extends FormDataType<TForm> & ValidateFormData<TForm>>(\n  rememberKey: string,\n  data: TForm | (() => TForm),\n): InertiaFormStore<TForm>\nexport default function useForm<TForm extends FormDataType<TForm> & ValidateFormData<TForm>>(\n  data: TForm | (() => TForm),\n): InertiaFormStore<TForm>\nexport default function useForm<TForm extends FormDataType<TForm>>(): InertiaFormStore<TForm>\nexport default function useForm<TForm extends FormDataType<TForm>>(\n  ...args: UseFormArguments<TForm>\n): InertiaFormStore<TForm> | InertiaPrecognitiveFormStore<TForm> {\n  const parsedArgs = UseFormUtils.parseUseFormArguments<TForm>(...args)\n  const { rememberKey, data: initialData } = parsedArgs\n  let precognitionEndpoint = parsedArgs.precognitionEndpoint\n\n  const data: TForm = typeof initialData === 'function' ? initialData() : (initialData as TForm)\n  const restored = rememberKey\n    ? (router.restore(rememberKey) as { data: TForm; errors: Record<FormDataKeys<TForm>, ErrorValue> } | null)\n    : null\n  let defaults = cloneDeep(data)\n  validateFormDataKeys(defaults)\n  let cancelToken: CancelToken | null = null\n  let recentlySuccessfulTimeoutId: ReturnType<typeof setTimeout> | null = null\n  let transform: UseFormTransformCallback<TForm> = (data) => data as object\n  let rememberExcludeKeys: FormDataKeys<TForm>[] = []\n  // Track if defaults was called manually during onSuccess to avoid\n  // overriding user's custom defaults with automatic behavior.\n  let defaultsCalledInOnSuccess = false\n\n  // Precognition state\n  let validatorRef: Validator | null = null\n\n  // Internal helper to update form state properties (handles both base form and precognition properties)\n  let setFormState: <K extends string>(key: K, value: any) => void\n\n  // Add withPrecognition method to store object (not just store value)\n  const withPrecognition = (...args: UseFormWithPrecognitionArguments): InertiaPrecognitiveFormStore<TForm> => {\n    precognitionEndpoint = UseFormUtils.createWayfinderCallback(...args)\n\n    // Type assertion helper for accessing precognition state\n    // We're dynamically adding precognition properties to the store value, so we assert the type\n    const formWithPrecognition = () =>\n      getStore(store) as any as InertiaPrecognitiveForm<TForm> & InternalPrecognitionState\n\n    let withAllErrors: boolean | null = null\n\n    if (!validatorRef) {\n      const validator = createValidator((client) => {\n        const { method, url } = precognitionEndpoint!()\n        const form = formWithPrecognition()\n        const transformedData = cloneDeep(transform(form.data())) as Record<string, unknown>\n        return client[method](url, transformedData)\n      }, cloneDeep(defaults))\n\n      validatorRef = validator\n\n      validator\n        .on('validatingChanged', () => {\n          setFormState('validating', validator.validating())\n        })\n        .on('validatedChanged', () => {\n          setFormState('__valid', validator.valid())\n        })\n        .on('touchedChanged', () => {\n          setFormState('__touched', validator.touched())\n        })\n        .on('errorsChanged', () => {\n          const validationErrors =\n            (withAllErrors ?? config.get('form.withAllErrors'))\n              ? validator.errors()\n              : toSimpleValidationErrors(validator.errors())\n\n          setFormState('errors', {} as FormDataErrors<TForm>)\n          formWithPrecognition().setError(validationErrors as FormDataErrors<TForm>)\n          setFormState('__valid', validator.valid())\n        })\n    }\n\n    // Helper function for method chaining\n    const tap = <T>(value: T, callback: (value: T) => unknown): T => {\n      callback(value)\n      return value\n    }\n\n    // Add validation methods to store object for direct calls\n    // These need to be added after validatorRef is initialized\n    if (validatorRef) {\n      Object.assign(store, {})\n    }\n\n    // Add validation methods to store value for $form reactive access\n    store.update((form) => {\n      return Object.assign(store, {\n        ...form,\n        __touched: [],\n        __valid: [],\n        validating: false,\n        validator: () => validatorRef!,\n        validate: (field?: string | NamedInputEvent | ValidationConfig, config?: ValidationConfig) => {\n          const form = formWithPrecognition()\n\n          // Handle config object passed as first argument\n          if (typeof field === 'object' && !('target' in field)) {\n            config = field\n            field = undefined\n          }\n\n          if (field === undefined) {\n            validatorRef!.validate(config)\n          } else {\n            field = resolveName(field)\n            const transformedData = transform(form.data()) as Record<string, unknown>\n            validatorRef!.validate(field, get(transformedData, field), config)\n          }\n\n          return form\n        },\n        touch: (\n          field: FormDataKeys<TForm> | NamedInputEvent | Array<FormDataKeys<TForm>>,\n          ...fields: FormDataKeys<TForm>[]\n        ) => {\n          const form = formWithPrecognition()\n          if (Array.isArray(field)) {\n            validatorRef?.touch(field)\n          } else if (typeof field === 'string') {\n            validatorRef?.touch([field, ...fields])\n          } else {\n            validatorRef?.touch(field)\n          }\n\n          return form\n        },\n        validateFiles: () => tap(formWithPrecognition(), () => validatorRef?.validateFiles()),\n        setValidationTimeout: (duration: number) =>\n          tap(formWithPrecognition(), () => validatorRef!.setTimeout(duration)),\n        withAllErrors: () => tap(formWithPrecognition(), () => (withAllErrors = true)),\n        withoutFileValidation: () => tap(formWithPrecognition(), () => validatorRef?.withoutFileValidation()),\n        valid: (field: string) => formWithPrecognition().__valid.includes(field),\n        invalid: (field: string) => field in formWithPrecognition().errors,\n        touched: (field?: string): boolean => {\n          const touched = formWithPrecognition().__touched\n\n          return typeof field === 'string' ? touched.includes(field) : touched.length > 0\n        },\n        setErrors: (errors: FormDataErrors<TForm>) =>\n          tap(formWithPrecognition(), () => {\n            const form = formWithPrecognition()\n            form.setError(errors)\n          }),\n        forgetError: (field: FormDataKeys<TForm> | NamedInputEvent) =>\n          tap(formWithPrecognition(), () => {\n            const form = formWithPrecognition()\n            form.clearErrors(resolveName(field as string | NamedInputEvent) as FormDataKeys<TForm>)\n          }),\n      })\n    })\n\n    return store as any as InertiaPrecognitiveFormStore<TForm>\n  }\n\n  const store = writable<InertiaForm<TForm>>({\n    ...(restored ? restored.data : data),\n    isDirty: false,\n    errors: (restored ? restored.errors : {}) as FormDataErrors<TForm>,\n    hasErrors: false,\n    progress: null,\n    wasSuccessful: false,\n    recentlySuccessful: false,\n    processing: false,\n    setStore(keyOrData: keyof InertiaFormProps<TForm> | FormDataKeys<TForm> | TForm, maybeValue = undefined) {\n      store.update((store) => {\n        return typeof keyOrData === 'string' ? set(store, keyOrData, maybeValue) : Object.assign(store, keyOrData)\n      })\n    },\n    data() {\n      return Object.keys(data).reduce((carry, key) => {\n        return set(carry, key, get(this, key))\n      }, {} as TForm)\n    },\n    transform(callback: TransformCallback<TForm>) {\n      transform = callback\n      return this\n    },\n    defaults(fieldOrFields?: FormDataKeys<TForm> | Partial<TForm>, maybeValue?: unknown) {\n      defaultsCalledInOnSuccess = true\n\n      if (typeof fieldOrFields === 'undefined') {\n        defaults = cloneDeep(this.data())\n      } else {\n        defaults =\n          typeof fieldOrFields === 'string'\n            ? set(cloneDeep(defaults), fieldOrFields, maybeValue)\n            : Object.assign(cloneDeep(defaults), fieldOrFields)\n      }\n\n      validatorRef?.defaults(defaults)\n\n      return this\n    },\n    reset(...fields: Array<FormDataKeys<TForm>>) {\n      const clonedData = cloneDeep(defaults)\n      if (fields.length === 0) {\n        this.setStore(clonedData)\n      } else {\n        this.setStore(\n          fields\n            .filter((key) => has(clonedData, key))\n            .reduce((carry, key) => {\n              return set(carry, key, get(clonedData, key))\n            }, {} as TForm),\n        )\n      }\n\n      validatorRef?.reset(...fields)\n\n      return this\n    },\n    setError(fieldOrFields: FormDataKeys<TForm> | FormDataErrors<TForm>, maybeValue?: ErrorValue) {\n      const errors = typeof fieldOrFields === 'string' ? { [fieldOrFields]: maybeValue } : fieldOrFields\n\n      setFormState('errors', {\n        ...this.errors,\n        ...errors,\n      })\n\n      validatorRef?.setErrors(errors as Errors)\n\n      return this\n    },\n    clearErrors(...fields: string[]) {\n      setFormState(\n        'errors',\n        Object.keys(this.errors).reduce(\n          (carry, field) => ({\n            ...carry,\n            ...(fields.length > 0 && !fields.includes(field) ? { [field]: (this.errors as Errors)[field] } : {}),\n          }),\n          {},\n        ) as FormDataErrors<TForm>,\n      )\n\n      if (validatorRef) {\n        if (fields.length === 0) {\n          validatorRef.setErrors({})\n        } else {\n          fields.forEach(validatorRef.forgetError)\n        }\n      }\n\n      return this\n    },\n    resetAndClearErrors(...fields: Array<FormDataKeys<TForm>>) {\n      this.reset(...fields)\n      this.clearErrors(...fields)\n      return this\n    },\n    submit(...args: UseFormSubmitArguments) {\n      const { method, url, options } = UseFormUtils.parseSubmitArguments(args, precognitionEndpoint)\n\n      defaultsCalledInOnSuccess = false\n\n      const data = transform(this.data()) as RequestPayload\n\n      const _options: Omit<VisitOptions, 'method'> = {\n        ...options,\n        onCancelToken: (token: CancelToken) => {\n          cancelToken = token\n\n          if (options.onCancelToken) {\n            return options.onCancelToken(token)\n          }\n        },\n        onBefore: (visit: PendingVisit) => {\n          setFormState('wasSuccessful', false)\n          setFormState('recentlySuccessful', false)\n          if (recentlySuccessfulTimeoutId) {\n            clearTimeout(recentlySuccessfulTimeoutId)\n          }\n\n          if (options.onBefore) {\n            return options.onBefore(visit)\n          }\n        },\n        onStart: (visit: PendingVisit) => {\n          setFormState('processing', true)\n\n          if (options.onStart) {\n            return options.onStart(visit)\n          }\n        },\n        onProgress: (event?: AxiosProgressEvent) => {\n          setFormState('progress', event || null)\n\n          if (options.onProgress) {\n            return options.onProgress(event)\n          }\n        },\n        onSuccess: async (page: Page) => {\n          setFormState('processing', false)\n          setFormState('progress', null)\n          this.clearErrors()\n          setFormState('wasSuccessful', true)\n          setFormState('recentlySuccessful', true)\n          recentlySuccessfulTimeoutId = setTimeout(\n            () => setFormState('recentlySuccessful', false),\n            config.get('form.recentlySuccessfulDuration'),\n          )\n\n          const onSuccess = options.onSuccess ? await options.onSuccess(page) : null\n\n          if (!defaultsCalledInOnSuccess) {\n            this.defaults(cloneDeep(getStore(store).data()))\n          }\n\n          return onSuccess\n        },\n        onError: (errors: Errors) => {\n          setFormState('processing', false)\n          setFormState('progress', null)\n          setFormState('errors', errors as FormDataErrors<TForm>)\n\n          validatorRef?.setErrors(errors)\n\n          if (options.onError) {\n            return options.onError(errors)\n          }\n        },\n        onCancel: () => {\n          setFormState('processing', false)\n          setFormState('progress', null)\n\n          if (options.onCancel) {\n            return options.onCancel()\n          }\n        },\n        onFinish: (visit: ActiveVisit) => {\n          setFormState('processing', false)\n          setFormState('progress', null)\n          cancelToken = null\n\n          if (options.onFinish) {\n            return options.onFinish(visit)\n          }\n        },\n      }\n\n      if (method === 'delete') {\n        router.delete(url, { ..._options, data })\n      } else {\n        router[method](url, data, _options)\n      }\n    },\n    get(url: string, options: VisitOptions) {\n      this.submit('get', url, options)\n    },\n    post(url: string, options: VisitOptions) {\n      this.submit('post', url, options)\n    },\n    put(url: string, options: VisitOptions) {\n      this.submit('put', url, options)\n    },\n    patch(url: string, options: VisitOptions) {\n      this.submit('patch', url, options)\n    },\n    delete(url: string, options: VisitOptions) {\n      this.submit('delete', url, options)\n    },\n    cancel() {\n      cancelToken?.cancel()\n    },\n    __remember() {\n      const data = this.data()\n      if (rememberExcludeKeys.length > 0) {\n        const filtered = { ...data } as Record<string, unknown>\n        rememberExcludeKeys.forEach((k) => delete filtered[k as string])\n        return { data: filtered as TForm, errors: this.errors }\n      }\n      return { data, errors: this.errors }\n    },\n    withPrecognition,\n  } as any)\n\n  // Add withPrecognition and dontRemember to store object\n  const dontRememberMethod = (...keys: FormDataKeys<TForm>[]) => {\n    rememberExcludeKeys = keys\n    return store\n  }\n\n  Object.assign(store, {\n    withPrecognition,\n    dontRemember: dontRememberMethod,\n  })\n\n  // Assign setFormState after store is created\n  setFormState = <K extends string>(key: K, value: any) => {\n    store.update((form) => ({ ...form, [key]: value }))\n  }\n\n  store.subscribe((form) => {\n    if (form.isDirty === isEqual(form.data(), defaults)) {\n      setFormState('isDirty', !form.isDirty)\n    }\n\n    const hasErrors = Object.keys(form.errors).length > 0\n    if (form.hasErrors !== hasErrors) {\n      setFormState('hasErrors', !form.hasErrors)\n    }\n\n    if (rememberKey) {\n      const storedData = router.restore(rememberKey)\n      const newData = (form as any).__remember()\n      if (!isEqual(storedData, newData)) {\n        router.remember(newData, rememberKey)\n      }\n    }\n  })\n\n  return precognitionEndpoint\n    ? (store as any).withPrecognition(precognitionEndpoint)\n    : (store as InertiaFormStore<TForm>)\n}\n"
  },
  {
    "path": "packages/svelte/src/usePoll.ts",
    "content": "import { router, type PollOptions, type ReloadOptions } from '@inertiajs/core'\nimport { onDestroy, onMount } from 'svelte'\n\nexport default function usePoll(\n  interval: number,\n  requestOptions: ReloadOptions = {},\n  options: PollOptions = {\n    keepAlive: false,\n    autoStart: true,\n  },\n) {\n  const { stop, start } = router.poll(interval, requestOptions, {\n    ...options,\n    autoStart: false,\n  })\n\n  onMount(() => {\n    if (options.autoStart ?? true) {\n      start()\n    }\n  })\n\n  onDestroy(() => {\n    stop()\n  })\n\n  return { stop, start }\n}\n"
  },
  {
    "path": "packages/svelte/src/usePrefetch.ts",
    "content": "import { router, type VisitOptions } from '@inertiajs/core'\nimport { onDestroy, onMount } from 'svelte'\nimport { readonly, writable } from 'svelte/store'\n\nexport default function usePrefetch(options: VisitOptions = {}) {\n  const isPrefetched = writable(false)\n  const isPrefetching = writable(false)\n  const lastUpdatedAt = writable<number | null>(null)\n\n  const cached = typeof window === 'undefined' ? null : router.getCached(window.location.pathname, options)\n  const inFlight = typeof window === 'undefined' ? null : router.getPrefetching(window.location.pathname, options)\n\n  isPrefetched.set(cached !== null)\n  isPrefetching.set(inFlight !== null)\n  lastUpdatedAt.set(cached?.staleTimestamp || null)\n\n  let removePrefetchedListener: () => void\n  let removePrefetchingListener: () => void\n\n  onMount(() => {\n    removePrefetchingListener = router.on('prefetching', ({ detail }) => {\n      if (detail.visit.url.pathname === window.location.pathname) {\n        isPrefetching.set(true)\n      }\n    })\n\n    removePrefetchedListener = router.on('prefetched', ({ detail }) => {\n      if (detail.visit.url.pathname === window.location.pathname) {\n        isPrefetched.set(true)\n        isPrefetching.set(false)\n      }\n    })\n  })\n\n  onDestroy(() => {\n    if (removePrefetchedListener) {\n      removePrefetchedListener()\n    }\n\n    if (removePrefetchingListener) {\n      removePrefetchingListener()\n    }\n  })\n\n  return {\n    isPrefetched: readonly(isPrefetched),\n    isPrefetching: readonly(isPrefetching),\n    lastUpdatedAt: readonly(lastUpdatedAt),\n    flush() {\n      router.flush(window.location.pathname, options)\n    },\n  }\n}\n"
  },
  {
    "path": "packages/svelte/src/useRemember.ts",
    "content": "import { router } from '@inertiajs/core'\nimport { cloneDeep } from 'lodash-es'\nimport { onDestroy } from 'svelte'\nimport { writable } from 'svelte/store'\n\nexport default function useRemember<State>(initialState: State, key?: string) {\n  const restored = router.restore(key) as State | undefined\n  const store = writable(restored !== undefined ? cloneDeep(restored) : initialState)\n  const unsubscribe = store.subscribe((state) => router.remember(cloneDeep(state), key))\n\n  onDestroy(unsubscribe)\n\n  return store\n}\n"
  },
  {
    "path": "packages/svelte/svelte.config.js",
    "content": "import adapter from '@sveltejs/adapter-auto'\nimport { vitePreprocess } from '@sveltejs/vite-plugin-svelte'\n\n/** @type {import('@sveltejs/kit').Config} */\nconst config = {\n  preprocess: vitePreprocess(),\n  kit: {\n    adapter: adapter(),\n  },\n  files: {\n    lib: 'src',\n  },\n}\n\nexport default config\n"
  },
  {
    "path": "packages/svelte/test-app/.gitignore",
    "content": "cypress/videos\ncypress/screenshots\napp/dist\nnode_modules\n"
  },
  {
    "path": "packages/svelte/test-app/Layouts/NestedLayout.svelte",
    "content": "<script lang=\"ts\">\n  import { onMount } from 'svelte'\n  import { page } from '@inertiajs/svelte'\n\n  let createdAt: number | null = null\n\n  onMount(() => {\n    window._inertia_nested_layout_id = crypto.randomUUID()\n    window._inertia_nested_layout_props = $page.props\n    createdAt = Date.now()\n  })\n</script>\n\n<div>\n  <span>Nested Layout</span>\n  <span>{createdAt}</span>\n  <div>\n    <slot />\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Layouts/Prefetch.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <a href=\"/prefetch/1\" use:inertia={{ prefetch: true }}>On Hover (Default)</a>\n  <a href=\"/prefetch/2\" use:inertia={{ prefetch: 'mount' }}>On Mount</a>\n  <a href=\"/prefetch/3\" use:inertia={{ prefetch: 'click' }}>On Click</a>\n  <a href=\"/prefetch/4\" use:inertia={{ prefetch: ['hover', 'mount'], cacheFor: '1s' }}>On Hover + Mount</a>\n  <a href=\"/prefetch/5\" use:inertia={{ prefetch: 'mount', cacheFor: '0' }}>On Mount (Once)</a>\n  <a href=\"/prefetch/6\" use:inertia={{ prefetch: 'click' }}>On Enter</a>\n  <button use:inertia={{ href: '/prefetch/7', prefetch: 'click' }}>On Spacebar</button>\n  <div>\n    <slot />\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Layouts/SWR.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <a href=\"/prefetch/swr/2\" use:inertia={{ prefetch: true, cacheFor: '1s' }}>1s Expired</a>\n  <a href=\"/prefetch/swr/3\" use:inertia={{ prefetch: true, cacheFor: 1000 }}>1s Expired (Number)</a>\n  <a href=\"/prefetch/swr/4\" style=\"margin: 0 20px\" use:inertia={{ prefetch: true, cacheFor: ['1s', '3s'] }}>\n    1s Stale, 2s Expired\n  </a>\n  <a href=\"/prefetch/swr/5\" use:inertia={{ prefetch: true, cacheFor: [1000, 3000] }}> 1s Stale, 2s Expired (Number) </a>\n  <div>\n    <slot />\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Layouts/SiteLayout.svelte",
    "content": "<script lang=\"ts\">\n  import { onMount } from 'svelte'\n  import { page } from '@inertiajs/svelte'\n\n  let createdAt: number | null = null\n\n  onMount(() => {\n    window._inertia_layout_id = crypto.randomUUID()\n    window._inertia_site_layout_props = $page.props\n    createdAt = Date.now()\n  })\n</script>\n\n<div>\n  <span>Site Layout</span>\n  <span>{createdAt}</span>\n  <div>\n    <slot />\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Layouts/WithScrollRegion.svelte",
    "content": "<script lang=\"ts\">\n  let slot: HTMLDivElement\n  let documentScrollTop = 0\n  let documentScrollLeft = 0\n  let slotScrollTop = 0\n  let slotScrollLeft = 0\n\n  const handleScrollEvent = () => {\n    documentScrollTop = document.documentElement.scrollTop\n    documentScrollLeft = document.documentElement.scrollLeft\n    slotScrollTop = slot.scrollTop\n    slotScrollLeft = slot.scrollLeft\n  }\n</script>\n\n<svelte:document on:scroll={handleScrollEvent} />\n\n<div style=\"width: 200vw\">\n  <span class=\"layout-text\">With scroll regions</span>\n  <button on:click={handleScrollEvent}>Update scroll positions</button>\n  <div class=\"document-position\">Document scroll position is {documentScrollLeft} & {documentScrollTop}</div>\n  <div style=\"height: 200vh\">\n    <span class=\"slot-position\">Slot scroll position is {slotScrollLeft} & {slotScrollTop}</span>\n    <div\n      bind:this={slot}\n      id=\"slot\"\n      scroll-region\n      style=\"height: 100px; width: 500px; overflow: scroll\"\n      on:scroll={handleScrollEvent}\n    >\n      <slot />\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Layouts/WithoutScrollRegion.svelte",
    "content": "<script lang=\"ts\">\n  let slot: HTMLDivElement\n  let documentScrollTop = 0\n  let documentScrollLeft = 0\n  let slotScrollTop = 0\n  let slotScrollLeft = 0\n\n  const handleScrollEvent = () => {\n    documentScrollTop = document.documentElement.scrollTop\n    documentScrollLeft = document.documentElement.scrollLeft\n    slotScrollTop = slot.scrollTop\n    slotScrollLeft = slot.scrollLeft\n  }\n</script>\n\n<svelte:document on:scroll={handleScrollEvent} />\n\n<div style=\"width: 200vw\">\n  <span class=\"layout-text\">Without scroll regions</span>\n  <button on:click={handleScrollEvent}>Update scroll positions</button>\n  <div class=\"document-position\">Document scroll position is {documentScrollLeft} & {documentScrollTop}</div>\n  <div style=\"height: 200vh\">\n    <span class=\"slot-position\">Slot scroll position is {slotScrollLeft} & {slotScrollTop}</span>\n    <div bind:this={slot} id=\"slot\" style=\"height: 100px; width: 500px; overflow: scroll\" on:scroll={handleScrollEvent}>\n      <slot />\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Article.svelte",
    "content": "<script lang=\"ts\">\n  import { Link } from '@inertiajs/svelte'\n  import { onMount, onDestroy } from 'svelte'\n\n  const enableSmoothScroll = () => {\n    document.documentElement.style.scrollBehavior = 'smooth'\n  }\n\n  export let scrollLog: number[] = []\n\n  const handleScrollEvent = () => {\n    scrollLog = [...scrollLog, document.documentElement.scrollTop]\n  }\n\n  onMount(() => document.addEventListener('scroll', handleScrollEvent))\n  onDestroy(() => document.removeEventListener('scroll', handleScrollEvent))\n</script>\n\n<h1 style=\"font-size: 40px;\">Article Header</h1>\n<article style=\"font-size: 20px; max-width: 500px;\">\n  <p>\n    Sunt culpa sit sunt enim aliquip. Esse ea ea quis voluptate. Enim consectetur aliqua ex ex magna cupidatat id minim\n    sit elit. Amet pariatur occaecat pariatur duis eiusmod dolore magna. Et commodo cupidatat in commodo elit cupidatat\n    minim qui id non enim ad. Culpa aliquip ad Lorem sit consectetur ullamco culpa duis nisi et fugiat mollit eiusmod.\n    Laboris voluptate veniam consequat proident in nulla irure velit.\n  </p>\n  <p>\n    Sit sint laboris sunt eiusmod ipsum laborum eiusmod amet commodo exercitation in duis magna. Proident sunt minim in\n    elit qui. Id pariatur commodo fugiat excepteur in deserunt Lorem ipsum occaecat est. Excepteur sit tempor ipsum ex\n    officia veniam enim amet velit fugiat mollit cillum. Incididunt aliqua nulla id occaecat nulla. Non ea ad est\n    occaecat deserunt officia qui commodo exercitation.\n  </p>\n  <p>\n    Voluptate laborum quis aliqua ullamco magna amet ullamco laborum qui cillum eu. Dolore dolore aliqua proident\n    proident sunt ipsum in. Enim velit dolore labore dolor quis incididunt duis culpa Lorem. Eu adipisicing non elit\n    fugiat voluptate labore ipsum dolore consectetur commodo. Et in et cillum duis consequat quis ex eu commodo. Eiusmod\n    aliqua excepteur consectetur eiusmod aute et consectetur sit pariatur dolore qui officia pariatur.\n  </p>\n  <p>\n    Non sunt eu mollit qui reprehenderit. Aute culpa anim voluptate do in esse duis laborum ad dolore. Ullamco nisi in\n    nostrud officia do. Duis pariatur officia id duis. Deserunt ad incididunt est sint consectetur reprehenderit mollit\n    est Lorem ea pariatur anim dolor adipisicing. Nostrud irure magna nostrud laboris aute sunt veniam laboris veniam\n    incididunt sit. Nulla proident ad aliqua fugiat culpa sunt est in dolor velit ad irure nulla.\n  </p>\n  <p>\n    Do aute laborum deserunt non laborum voluptate voluptate. Anim ut laborum magna sunt cupidatat irure. Cupidatat\n    fugiat minim sint cillum laborum excepteur irure id est irure ad occaecat adipisicing enim. Deserunt nulla anim\n    proident velit irure nostrud est est reprehenderit consequat pariatur qui. Fugiat Lorem sint eu laborum minim\n    pariatur cillum mollit nulla consequat ullamco ex. Ex consectetur ad ut irure fugiat occaecat aliqua exercitation\n    cillum ipsum anim dolore tempor.\n  </p>\n  <p>\n    Adipisicing consequat irure fugiat Lorem deserunt aliquip do cupidatat. Lorem labore elit ex qui nostrud qui cillum\n    sunt adipisicing occaecat. Sunt nostrud amet amet cupidatat fugiat Lorem quis nulla id cillum esse eu. Ullamco\n    aliqua dolore irure amet mollit anim velit dolore.\n  </p>\n  <p>\n    Veniam cupidatat ipsum ea officia ipsum nisi laborum culpa qui dolore. Aliqua Lorem nisi labore ea velit aliquip\n    irure excepteur eu. Laboris proident duis non labore sunt quis aute tempor laboris enim anim eiusmod.\n  </p>\n  <p>\n    Minim proident ut aliqua ea ut culpa fugiat ullamco nisi esse nostrud reprehenderit id. Id id ullamco velit anim\n    nisi magna Lorem tempor. Et veniam occaecat ut labore consequat fugiat duis.\n  </p>\n  <p>\n    Adipisicing ea consectetur adipisicing aute eu pariatur enim labore consequat occaecat consectetur minim nisi.\n    Cillum commodo sunt labore reprehenderit. Duis esse excepteur magna tempor eiusmod exercitation Lorem reprehenderit\n    excepteur pariatur. Esse cupidatat occaecat magna do aliquip Lorem. Consectetur adipisicing consequat dolore nostrud\n    esse eu cillum id commodo duis. Aliquip dolor cillum cupidatat fugiat.\n  </p>\n  <p>\n    Ex eiusmod id est laborum sunt ex ea aute adipisicing ad magna deserunt duis. Nostrud velit dolore id commodo quis\n    enim fugiat. Sint non quis consectetur voluptate aliqua dolore nulla. Irure sit reprehenderit sint laboris non elit.\n    Duis minim nisi esse dolor. Sit ex in consequat non occaecat commodo irure et. Commodo qui ipsum Lorem magna\n    consequat consequat et minim eiusmod Lorem eiusmod cupidatat voluptate.\n  </p>\n  <h2 id=\"far-down\">Far down</h2>\n  <p>\n    Ex eiusmod id est laborum sunt ex ea aute adipisicing ad magna deserunt duis. Nostrud velit dolore id commodo quis\n    enim fugiat. Sint non quis consectetur voluptate aliqua dolore ad voluptate nulla. Irure sit reprehenderit sint\n    laboris non elit. Duis minim nisi esse dolor. Sit ex in consequat non occaecat commodo irure et. Commodo qui ipsum\n    Lorem magna consequat consequat et minim eiusmod Lorem eiusmod cupidatat voluptate.\n  </p>\n</article>\n\n<div class=\"document-position\">Scroll log: {JSON.stringify(scrollLog)}</div>\n\n<Link id=\"home\" data-testid=\"home\" href=\"/\">Home</Link>\n\n<Link id=\"article-far-down\" data-testid=\"article-far-down\" href=\"/article#far-down\">Article Far Down</Link>\n\n<button id=\"enable-smooth-scroll\" data-testid=\"enable-smooth-scroll\" on:click={enableSmoothScroll}>\n  Enable Smooth Scroll\n</button>\n\n<button id=\"clear-scroll-log\" data-testid=\"clear-scroll-log\" on:click={() => (scrollLog = [])}>Clear Scroll Log</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/ClientSideVisit/Page1.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n  import type { Page } from '@inertiajs/core'\n\n  interface PageProps {\n    foo: string\n    bar: string\n  }\n\n  export let foo: string\n  export let bar: string\n\n  let errors = 0\n  let finished = 0\n  let success = 0\n  let random = Math.random()\n\n  const bagErrors = () => {\n    router.replace({\n      preserveState: true,\n      props: (props: Page['props']) => ({ ...props, errors: { bag: { foo: 'bar' } } }),\n      errorBag: 'bag',\n      onError: (err) => {\n        errors = Object.keys(err).length\n      },\n      onFinish: () => finished++,\n      onSuccess: () => success++,\n    })\n  }\n\n  const defaultErrors = () => {\n    router.replace({\n      preserveState: true,\n      props: (props: PageProps) => ({ ...props, errors: { foo: 'bar', baz: 'qux' } }),\n      onError: (err) => {\n        errors = Object.keys(err).length\n      },\n      onFinish: () => finished++,\n      onSuccess: () => success++,\n    })\n  }\n\n  const replace = () => {\n    router.replace({\n      preserveState: true,\n      props: (props) => ({ ...props, foo: 'foo from client' }),\n      onFinish: () => finished++,\n      onSuccess: () => success++,\n    })\n  }\n\n  const replaceAndPreserveStateWithErrors = (errors = {}) => {\n    router.replace({\n      preserveState: 'errors',\n      props: (props: PageProps) => ({ ...props, errors }),\n    })\n  }\n\n  const push = () => {\n    router.push({\n      url: '/client-side-visit-2',\n      component: 'ClientSideVisit/Page2',\n      props: { baz: 'baz from client' },\n    })\n  }\n</script>\n\n<div>\n  <div>{foo}</div>\n  <div>{bar}</div>\n  <button on:click={replace}>Replace</button>\n  <button on:click={() => replaceAndPreserveStateWithErrors({ name: 'Field is required' })}>\n    Replace with errors\n  </button>\n  <button on:click={() => replaceAndPreserveStateWithErrors()}>Replace without errors</button>\n  <button on:click={push}>Push</button>\n  <button on:click={defaultErrors}>Errors (default)</button>\n  <button on:click={bagErrors}>Errors (bag)</button>\n  <div>Errors: {errors}</div>\n  <div>Finished: {finished}</div>\n  <div>Success: {success}</div>\n  <div id=\"random\">Random: {random}</div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/ClientSideVisit/Page2.svelte",
    "content": "<script lang=\"ts\">\n  export let baz: string\n</script>\n\n<div>{baz}</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/ClientSideVisit/Props.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  interface Tag {\n    id: number\n    name: string\n  }\n\n  interface User {\n    name: string\n    age: number\n  }\n\n  export let items: string[] = []\n  export let tags: Tag[] = []\n  export let user: User | undefined = undefined\n  export let count = 0\n  export let singleValue: string | string[] | undefined = undefined\n  export let undefinedValue: string | string[] | undefined = undefined\n\n  const replacePropString = () => {\n    router.replaceProp('user.name', 'Jane Smith')\n  }\n\n  const replacePropNumber = () => {\n    router.replaceProp('count', 10)\n  }\n\n  const replacePropFunction = () => {\n    router.replaceProp('count', (oldValue: number) => oldValue * 2)\n  }\n\n  const appendToPropArray = () => {\n    router.appendToProp('items', 'item3')\n  }\n\n  const appendToPropMultiple = () => {\n    router.appendToProp('items', ['item4', 'item5'])\n  }\n\n  const appendToPropFunction = () => {\n    router.appendToProp('tags', () => ({ id: 3, name: 'tag3' }))\n  }\n\n  const appendArrayToArray = () => {\n    router.appendToProp('tags', [\n      { id: 3, name: 'tag3' },\n      { id: 4, name: 'tag4' },\n    ])\n  }\n\n  const prependToPropArray = () => {\n    router.prependToProp('items', 'item0')\n  }\n\n  const prependToPropMultiple = () => {\n    router.prependToProp('items', ['itemA', 'itemB'])\n  }\n\n  const prependToPropFunction = () => {\n    router.prependToProp('tags', () => ({ id: 0, name: 'tag0' }))\n  }\n\n  // Edge case tests for mergeArrays behavior\n  const appendToNonArray = () => {\n    router.appendToProp('singleValue', 'world')\n  }\n\n  const prependToNonArray = () => {\n    router.prependToProp('singleValue', 'hey')\n  }\n\n  const appendArrayToNonArray = () => {\n    router.appendToProp('singleValue', ['there', 'world'])\n  }\n\n  const prependArrayToNonArray = () => {\n    router.prependToProp('singleValue', ['hey', 'hi'])\n  }\n\n  const appendToUndefined = () => {\n    router.appendToProp('undefinedValue', 'new value')\n  }\n\n  const prependToUndefined = () => {\n    router.prependToProp('undefinedValue', 'start value')\n  }\n</script>\n\n<div>\n  <h1>Client Side Visit Props Testing</h1>\n\n  <div>User: {user?.name || 'Unknown'} (Age: {user?.age || 'Unknown'})</div>\n  <div>Count: {count}</div>\n\n  <div>Items: {JSON.stringify(items)}</div>\n  <div>Tags: {JSON.stringify(tags)}</div>\n  <div>Single Value: {JSON.stringify(singleValue)}</div>\n  <div>Undefined Value: {JSON.stringify(undefinedValue)}</div>\n\n  <hr />\n\n  <h2>Replace Prop Tests</h2>\n  <button on:click={replacePropString}>Replace user.name</button>\n  <button on:click={replacePropNumber}>Replace count</button>\n  <button on:click={replacePropFunction}>Replace count (function)</button>\n\n  <h2>Append To Prop Tests</h2>\n  <button on:click={appendToPropArray}>Append to items (single)</button>\n  <button on:click={appendToPropMultiple}>Append to items (multiple)</button>\n  <button on:click={appendToPropFunction}>Append to tags (function)</button>\n  <button on:click={appendArrayToArray}>Append array to array (objects)</button>\n\n  <h2>Prepend To Prop Tests</h2>\n  <button on:click={prependToPropArray}>Prepend to items (single)</button>\n  <button on:click={prependToPropMultiple}>Prepend to items (multiple)</button>\n  <button on:click={prependToPropFunction}>Prepend to tags (function)</button>\n\n  <h2>Edge Case Tests (mergeArrays behavior)</h2>\n  <button on:click={appendToNonArray}>Append to non-array (single + single)</button>\n  <button on:click={prependToNonArray}>Prepend to non-array (single + single)</button>\n  <button on:click={appendArrayToNonArray}>Append array to non-array (single + array)</button>\n  <button on:click={prependArrayToNonArray}>Prepend array to non-array (array + single)</button>\n  <button on:click={appendToUndefined}>Append to undefined</button>\n  <button on:click={prependToUndefined}>Prepend to undefined</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/ClientSideVisit/Sequential.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  export let foo = ''\n  export let bar = ''\n\n  const replaceSequentially = () => {\n    router.replaceProp('foo', 'baz')\n    router.replaceProp('bar', 'qux')\n  }\n</script>\n\n<div>\n  <p>Foo: {foo}</p>\n  <p>Bar: {bar}</p>\n\n  <button on:click={replaceSequentially}>Replace foo and bar sequentially</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/ComplexMergeSelective.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  export let mixed: {\n    name: string\n    users: string[]\n    chat: { data: number[] }\n    post: { id: number; comments: { allowed: boolean; data: string[] } }\n  }\n\n  const reload = () => {\n    router.reload({\n      only: ['mixed'],\n    })\n  }\n</script>\n\n<div>name is {mixed.name}</div>\n<div>users: {mixed.users.join(', ')}</div>\n<div>chat.data: {mixed.chat.data.join(', ')}</div>\n<div>post.id: {mixed.post.id}</div>\n<div>post.comments.allowed: {mixed.post.comments.allowed ? 'true' : 'false'}</div>\n<div>post.comments.data: {mixed.post.comments.data.join(', ')}</div>\n<button on:click={reload}>Reload</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/CustomConfig.svelte",
    "content": "<script lang=\"ts\">\n  import type { VisitOptions } from '@inertiajs/core'\n  import { config, Link, useForm, page } from '@inertiajs/svelte'\n\n  const form = useForm({})\n\n  const submit = () => {\n    $form.post($page.url)\n  }\n\n  config.set({\n    'form.recentlySuccessfulDuration': 1000,\n    'prefetch.cacheFor': '2s',\n  })\n\n  config.set('visitOptions', (href: string, options: VisitOptions) => {\n    if (href !== '/dump/post') {\n      return {}\n    }\n\n    return { headers: { ...options.headers, 'X-From-Callback': 'bar' } }\n  })\n</script>\n\n<Link prefetch href=\"/dump/get\">Prefetch Link</Link>\n<Link method=\"post\" headers={{ 'X-From-Link': 'foo' }} href=\"/dump/post\">Post Dump</Link>\n<button on:click={submit}>Submit Form</button>\n{#if $form.recentlySuccessful}\n  <p>Form was recently successful!</p>\n{/if}\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/DeepMergeProps.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  export let foo: { page: number; data: number[]; per_page: number; meta: { label: string } }\n  export let bar: number[]\n  export let baz: number[]\n\n  let page = foo.page\n\n  const reloadIt = () => {\n    router.reload({\n      data: {\n        page,\n      },\n      only: ['foo', 'baz'],\n      onSuccess(visit) {\n        page = (visit.props as unknown as { foo: { page: number } }).foo.page\n      },\n    })\n  }\n\n  const getFresh = () => {\n    page = 0\n    router.visit('/deep-merge-props', {\n      reset: ['foo', 'baz'],\n    })\n  }\n</script>\n\n<div>bar count is {bar.length}</div>\n<div>baz count is {baz.length}</div>\n<div>foo.data count is {foo.data.length}</div>\n<div>foo.page is {foo.page}</div>\n<div>foo.per_page is {foo.per_page}</div>\n<div>foo.meta.label is {foo.meta.label}</div>\n<button on:click={reloadIt}>Reload</button>\n<button on:click={getFresh}>Get Fresh</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/DeferredProps/BackButton/PageA.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred, inertia } from '@inertiajs/svelte'\n\n  export let fastProp: string | undefined\n  export let slowProp: string | undefined\n</script>\n\n<Deferred data=\"fastProp\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading fast prop...</div>\n  </svelte:fragment>\n  {fastProp}\n</Deferred>\n\n<Deferred data=\"slowProp\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading slow prop...</div>\n  </svelte:fragment>\n  {slowProp}\n</Deferred>\n\n<a href=\"/deferred-props/back-button/b\" use:inertia>Go to Page B</a>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/DeferredProps/BackButton/PageB.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred, inertia } from '@inertiajs/svelte'\n\n  export let data: string | undefined\n</script>\n\n<Deferred data=\"data\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading data...</div>\n  </svelte:fragment>\n  {data}\n</Deferred>\n\n<a href=\"/deferred-props/back-button/a\" use:inertia>Go to Page A</a>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/DeferredProps/InstantReload.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred, router } from '@inertiajs/svelte'\n  import { onMount } from 'svelte'\n\n  export let foo: { text: string } | undefined\n  export let bar: { text: string } | undefined\n\n  onMount(() => {\n    router.reload({\n      only: ['foo'],\n    })\n  })\n</script>\n\n<Deferred data=\"foo\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading foo...</div>\n  </svelte:fragment>\n  <div>{foo?.text}</div>\n</Deferred>\n\n<Deferred data=\"bar\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading bar...</div>\n  </svelte:fragment>\n  <div>{bar?.text}</div>\n</Deferred>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/DeferredProps/ManyGroups.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred, inertia } from '@inertiajs/svelte'\n\n  export let foo: { text: string } | undefined\n  export let bar: { text: string } | undefined\n  export let baz: { text: string } | undefined\n  export let qux: { text: string } | undefined\n  export let quux: { text: string } | undefined\n</script>\n\n<Deferred data=\"foo\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading foo...</div>\n  </svelte:fragment>\n  {foo?.text}\n</Deferred>\n\n<Deferred data=\"bar\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading bar...</div>\n  </svelte:fragment>\n  {bar?.text}\n</Deferred>\n\n<Deferred data=\"baz\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading baz...</div>\n  </svelte:fragment>\n  {baz?.text}\n</Deferred>\n\n<Deferred data=\"qux\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading qux...</div>\n  </svelte:fragment>\n  {qux?.text}\n</Deferred>\n\n<Deferred data=\"quux\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading quux...</div>\n  </svelte:fragment>\n  {quux?.text}\n</Deferred>\n\n<a href=\"/deferred-props/page-1\" use:inertia>Page 1</a>\n<a href=\"/deferred-props/page-2\" use:inertia>Page 2</a>\n<a href=\"/deferred-props/many-groups\" use:inertia>Many groups</a>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/DeferredProps/Page1.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred, inertia } from '@inertiajs/svelte'\n\n  export let foo: { text: string } | undefined\n  export let bar: { text: string } | undefined\n</script>\n\n<Deferred data=\"foo\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading foo...</div>\n  </svelte:fragment>\n  {foo?.text}\n</Deferred>\n\n<Deferred data=\"bar\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading bar...</div>\n  </svelte:fragment>\n  {bar?.text}\n</Deferred>\n\n<a href=\"/deferred-props/page-1\" use:inertia>Page 1</a>\n<a href=\"/deferred-props/page-2\" use:inertia>Page 2</a>\n<a href=\"/deferred-props/page-3\" use:inertia={{ prefetch: true }}>Page 3</a>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/DeferredProps/Page2.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred } from '@inertiajs/svelte'\n\n  export let baz: string | undefined\n  export let qux: string | undefined\n</script>\n\n<Deferred data=\"baz\">\n  <div slot=\"fallback\">Loading baz...</div>\n  {baz}\n</Deferred>\n\n<Deferred data=\"qux\">\n  <div slot=\"fallback\">Loading qux...</div>\n  {qux}\n</Deferred>\n\n<Deferred data={['baz', 'qux']}>\n  <div slot=\"fallback\">Loading baz and qux...</div>\n  both {baz} and {qux}\n</Deferred>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/DeferredProps/Page3.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred } from '@inertiajs/svelte'\n\n  export let alpha: string | undefined\n  export let beta: string | undefined\n</script>\n\n<Deferred data=\"alpha\">\n  <div slot=\"fallback\">Loading alpha...</div>\n  {alpha}\n</Deferred>\n\n<Deferred data=\"beta\">\n  <div slot=\"fallback\">Loading beta...</div>\n  {beta}\n</Deferred>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/DeferredProps/PartialReloads.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred, router } from '@inertiajs/svelte'\n\n  export let foo: { timestamp: string } | undefined\n  export let bar: { timestamp: string } | undefined\n\n  const reloadOnlyFoo = () => {\n    router.reload({\n      only: ['foo'],\n    })\n  }\n\n  const reloadOnlyBar = () => {\n    router.reload({\n      only: ['bar'],\n    })\n  }\n\n  const reloadBoth = () => {\n    router.reload({\n      only: ['foo', 'bar'],\n    })\n  }\n</script>\n\n<Deferred data=\"foo\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading foo...</div>\n  </svelte:fragment>\n  <div id=\"foo-timestamp\">{foo?.timestamp}</div>\n</Deferred>\n\n<Deferred data=\"bar\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading bar...</div>\n  </svelte:fragment>\n  <div id=\"bar-timestamp\">{bar?.timestamp}</div>\n</Deferred>\n\n<button on:click={reloadOnlyFoo}>Reload foo only</button>\n<button on:click={reloadOnlyBar}>Reload bar only</button>\n<button on:click={reloadBoth}>Reload both</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/DeferredProps/RapidNavigation.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred, Link, router, page } from '@inertiajs/svelte'\n\n  $: id = $page.props.id as string\n  $: users = $page.props.users as { text: string } | undefined\n  $: stats = $page.props.stats as { text: string } | undefined\n  $: activity = $page.props.activity as { text: string } | undefined\n\n  function handleOnBeforeClick() {\n    const shouldNavigate = confirm('Navigate away?')\n    if (shouldNavigate) {\n      router.visit('/deferred-props/page-2')\n    }\n  }\n</script>\n\n<div>Page: {id}</div>\n\n<Deferred data=\"users\">\n  <div slot=\"fallback\">Loading users...</div>\n  <div>{users?.text}</div>\n</Deferred>\n\n<Deferred data=\"stats\">\n  <div slot=\"fallback\">Loading stats...</div>\n  <div>{stats?.text}</div>\n</Deferred>\n\n<Deferred data=\"activity\">\n  <div slot=\"fallback\">Loading activity...</div>\n  <div>{activity?.text}</div>\n</Deferred>\n\n<Link href=\"/deferred-props/rapid-navigation/a\">Page A</Link>\n<Link href=\"/deferred-props/rapid-navigation/b\">Page B</Link>\n<Link href=\"/deferred-props/rapid-navigation/c\">Page C</Link>\n<Link href=\"/deferred-props/page-1\">Navigate Away</Link>\n\n<button on:click={handleOnBeforeClick}>Navigate with onBefore</button>\n\n<button on:click={() => router.reload()}>Plain reload</button>\n\n<button on:click={() => router.visit(`/deferred-props/rapid-navigation/${id}?foo=bar`)}>Add query param</button>\n\n<button on:click={() => router.prefetch('/deferred-props/page-1')}>Prefetch Page 1</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/DeferredProps/ReloadResults.svelte",
    "content": "<script>\n  import { page } from '@inertiajs/svelte'\n\n  // Access props from page store - this component only renders when Deferred shows slot\n  $: results = $page.props.results\n</script>\n\n<div id=\"results-data\">{results.data.join(', ')}</div>\n<div id=\"results-page\">Page: {results.page}</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/DeferredProps/ReloadWithoutOptionalChaining.svelte",
    "content": "<script>\n  import { Deferred, router } from '@inertiajs/svelte'\n  import ReloadResults from './ReloadResults.svelte'\n\n  const handleReload = () => {\n    router.reload({\n      data: { page: 2 },\n    })\n  }\n</script>\n\n<Deferred data=\"results\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading results...</div>\n  </svelte:fragment>\n  <ReloadResults />\n</Deferred>\n\n<button on:click={handleReload}>Reload with page 2</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/DeferredProps/WithErrors.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred, page, useForm } from '@inertiajs/svelte'\n\n  export let foo: { text: string } | undefined\n\n  const form = useForm({\n    name: '',\n  })\n\n  const submit = () => {\n    $form.post('/deferred-props/with-errors')\n  }\n</script>\n\n<Deferred data=\"foo\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading foo...</div>\n  </svelte:fragment>\n\n  <div id=\"foo\">{foo?.text}</div>\n</Deferred>\n\n{#if $page.props.errors?.name}\n  <p id=\"page-error\">{$page.props.errors.name}</p>\n{/if}\n{#if $form.errors.name}\n  <p id=\"form-error\">{$form.errors.name}</p>\n{/if}\n\n<button type=\"button\" on:click={submit}>Submit</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/DeferredProps/WithQueryParams.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred } from '@inertiajs/svelte'\n\n  export let filter: string\n  export let users: { text: string } | undefined\n</script>\n\n<div>Filter: {filter}</div>\n\n<Deferred data=\"users\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading users...</div>\n  </svelte:fragment>\n  <div>{users?.text}</div>\n</Deferred>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/DeferredProps/WithReload.svelte",
    "content": "<script>\n  import { Deferred, router } from '@inertiajs/svelte'\n\n  export let results\n\n  const handleReload = () => {\n    router.reload({\n      data: { page: 2 },\n    })\n  }\n</script>\n\n<Deferred data=\"results\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading results...</div>\n  </svelte:fragment>\n  <div id=\"results-data\">{results?.data?.join(', ')}</div>\n  <div id=\"results-page\">Page: {results?.page}</div>\n</Deferred>\n\n<button on:click={handleReload}>Reload with page 2</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Dump.svelte",
    "content": "<script lang=\"ts\">\n  import { beforeUpdate } from 'svelte'\n  import { page } from '@inertiajs/svelte'\n  import type { Method } from '@inertiajs/core'\n  import type { MulterFile } from '../types'\n\n  export let headers: Record<string, string>\n  export let method: Method\n  export let form: Record<string, unknown>\n  export let files: MulterFile[] | object = {}\n  export let url: string\n  export let query: Record<string, unknown>\n\n  const dump = {\n    headers,\n    method,\n    form,\n    files,\n    query,\n    url,\n    $page: $page,\n  }\n\n  beforeUpdate(() => {\n    window._inertia_request_dump = dump\n  })\n</script>\n\n<div>\n  <div class=\"text\">This is Inertia page component containing a data dump of the request</div>\n  <hr />\n  <pre class=\"dump\" style=\"white-space: pre-wrap; word-break: keep-all;\">{JSON.stringify(dump)}</pre>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/ErrorModal.svelte",
    "content": "<script lang=\"ts\">\n  import { config, router } from '@inertiajs/svelte'\n\n  export let dialog: boolean = false\n\n  const invalidVisit = () => {\n    router.post('/non-inertia')\n  }\n\n  const invalidVisitJson = () => {\n    router.post('/json')\n  }\n\n  if (dialog) {\n    config.set('future.useDialogForErrorModal', true)\n  }\n</script>\n\n<div>\n  <span\n    on:click={invalidVisit}\n    on:keydown={(e) => e.key === 'Enter' && invalidVisit()}\n    role=\"button\"\n    tabindex=\"0\"\n    class=\"invalid-visit\">Invalid Visit</span\n  >\n  <span\n    on:click={invalidVisitJson}\n    on:keydown={(e) => e.key === 'Enter' && invalidVisitJson()}\n    role=\"button\"\n    tabindex=\"0\"\n    class=\"invalid-visit-json\">Invalid Visit (JSON response)</span\n  >\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Events.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  declare global {\n    interface Window {\n      messages: unknown[]\n    }\n  }\n</script>\n\n<script lang=\"ts\">\n  import { inertia, page, router } from '@inertiajs/svelte'\n\n  const payloadWithFile = {\n    file: new File(['foobar'], 'example.bin'),\n  }\n\n  window.messages = []\n\n  const internalAlert = (...args: unknown[]) => {\n    window.messages.push(...args)\n  }\n\n  const withoutEventListeners = () => {\n    router.post($page.url, {})\n  }\n\n  const removeInertiaListener = () => {\n    const removeEventListener = router.on('before', () => internalAlert('Inertia.on(before)'))\n\n    internalAlert('Removing Inertia.on Listener')\n    removeEventListener()\n\n    router.post(\n      $page.url,\n      {},\n      {\n        onBefore: () => internalAlert('onBefore'),\n        onStart: () => internalAlert('onStart'),\n      },\n    )\n  }\n\n  const beforeVisit = () => {\n    router.on('before', (event) => {\n      internalAlert('Inertia.on(before)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:before', (event) => {\n      internalAlert('addEventListener(inertia:before)')\n      internalAlert(event)\n    })\n\n    router.post(\n      $page.url,\n      {},\n      {\n        onBefore: (event) => {\n          internalAlert('onBefore')\n          internalAlert(event)\n        },\n        onStart: () => internalAlert('onStart'),\n      },\n    )\n  }\n\n  const beforeVisitPreventLocal = () => {\n    document.addEventListener('inertia:before', () => internalAlert('addEventListener(inertia:before)'))\n    router.on('before', () => internalAlert('Inertia.on(before)'))\n\n    router.post(\n      $page.url,\n      {},\n      {\n        onBefore: () => {\n          internalAlert('onBefore')\n          return false\n        },\n        onStart: () => internalAlert('This listener should not have been called.'),\n      },\n    )\n  }\n\n  const beforeVisitPreventGlobalInertia = () => {\n    document.addEventListener('inertia:before', () => internalAlert('addEventListener(inertia:before)'))\n    router.on('before', () => {\n      internalAlert('Inertia.on(before)')\n      return false\n    })\n\n    router.post(\n      $page.url,\n      {},\n      {\n        onBefore: () => internalAlert('onBefore'),\n        onStart: () => internalAlert('This listener should not have been called.'),\n      },\n    )\n  }\n\n  const beforeVisitPreventGlobalNative = () => {\n    router.on('before', () => internalAlert('Inertia.on(before)'))\n    document.addEventListener('inertia:before', (event) => {\n      internalAlert('addEventListener(inertia:before)')\n      event.preventDefault()\n    })\n\n    router.post(\n      $page.url,\n      {},\n      {\n        onBefore: () => internalAlert('onBefore'),\n        onStart: () => internalAlert('This listener should not have been called.'),\n      },\n    )\n  }\n\n  const cancelTokenVisit = () => {\n    // @ts-expect-error - We're testing that the router doesn't have an onCancelToken listener\n    router.on('cancelToken', () => internalAlert('This listener should not have been called.'))\n    document.addEventListener('inertia:cancelToken', () => internalAlert('This listener should not have been called.'))\n\n    router.post(\n      $page.url,\n      {},\n      {\n        onCancelToken: (event) => {\n          internalAlert('onCancelToken')\n          internalAlert(event)\n        },\n      },\n    )\n  }\n\n  const startVisit = () => {\n    router.on('start', (event) => {\n      internalAlert('Inertia.on(start)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:start', (event) => {\n      internalAlert('addEventListener(inertia:start)')\n      internalAlert(event)\n    })\n\n    router.post(\n      $page.url,\n      {},\n      {\n        onStart: (event) => {\n          internalAlert('onStart')\n          internalAlert(event)\n        },\n      },\n    )\n  }\n\n  const progressVisit = () => {\n    router.on('progress', (event) => {\n      internalAlert('Inertia.on(progress)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:progress', (event) => {\n      internalAlert('addEventListener(inertia:progress)')\n      internalAlert(event)\n    })\n\n    router.post($page.url, payloadWithFile, {\n      onProgress: (event) => {\n        internalAlert('onProgress')\n        internalAlert(event)\n      },\n    })\n  }\n\n  const progressNoFilesVisit = () => {\n    router.on('progress', (event) => {\n      internalAlert('Inertia.on(progress)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:progress', (event) => {\n      internalAlert('addEventListener(inertia:progress)')\n      internalAlert(event)\n    })\n\n    router.post(\n      $page.url,\n      {},\n      {\n        onBefore: () => internalAlert('progressNoFilesOnBefore'),\n        onProgress: (event) => {\n          internalAlert('onProgress')\n          internalAlert(event)\n        },\n      },\n    )\n  }\n\n  const cancelVisit = () => {\n    router.on('cancel', (event) => {\n      internalAlert('Inertia.on(cancel)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:cancel', (event) => {\n      internalAlert('addEventListener(inertia:cancel)')\n      internalAlert(event)\n    })\n\n    router.post(\n      $page.url,\n      {},\n      {\n        onCancelToken: (token) => {\n          token.cancel()\n        },\n        // @ts-expect-error - We're testing that the onCancel callback has no arguments, so event will be undefined\n        onCancel: (event) => {\n          internalAlert('onCancel')\n          internalAlert(event)\n        },\n      },\n    )\n  }\n\n  const errorVisit = () => {\n    router.on('error', (event) => {\n      internalAlert('Inertia.on(error)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:error', (event) => {\n      internalAlert('addEventListener(inertia:error)')\n      internalAlert(event)\n    })\n\n    router.post(\n      '/events/errors',\n      {},\n      {\n        onError: (errors) => {\n          internalAlert('onError')\n          internalAlert(errors)\n        },\n      },\n    )\n  }\n\n  const errorPromiseVisit = () => {\n    router.post(\n      '/events/errors',\n      {},\n      {\n        onError: () => callbackSuccessErrorPromise('onError'),\n        onSuccess: () => internalAlert('This listener should not have been called'),\n        onFinish: () => internalAlert('onFinish'),\n      },\n    )\n  }\n\n  const successVisit = () => {\n    router.on('success', (event) => {\n      internalAlert('Inertia.on(success)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:success', (event) => {\n      internalAlert('addEventListener(inertia:success)')\n      internalAlert(event)\n    })\n\n    router.post(\n      $page.url,\n      {},\n      {\n        onError: () => internalAlert('This listener should not have been called'),\n        onSuccess: (page) => {\n          internalAlert('onSuccess')\n          internalAlert(page)\n        },\n      },\n    )\n  }\n\n  const successPromiseVisit = () => {\n    router.post(\n      $page.url,\n      {},\n      {\n        onSuccess: () => callbackSuccessErrorPromise('onSuccess'),\n        onError: () => internalAlert('This listener should not have been called'),\n        onFinish: () => internalAlert('onFinish'),\n      },\n    )\n  }\n\n  const finishVisit = () => {\n    router.on('finish', (event) => {\n      internalAlert('Inertia.on(finish)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:finish', (event) => {\n      internalAlert('addEventListener(inertia:finish)')\n      internalAlert(event)\n    })\n\n    router.post(\n      $page.url,\n      {},\n      {\n        onFinish: (event) => {\n          internalAlert('onFinish')\n          internalAlert(event)\n        },\n      },\n    )\n  }\n\n  const invalidVisit = () => {\n    router.on('invalid', (event) => {\n      internalAlert('Inertia.on(invalid)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:invalid', (event) => {\n      internalAlert('addEventListener(inertia:invalid)')\n      internalAlert(event)\n    })\n\n    router.post(\n      '/non-inertia',\n      {},\n      {\n        // @ts-expect-error - We're testing that the VisitCallbacks interface does not have an onInvalid method\n        onInvalid: () => internalAlert('This listener should not have been called.'),\n      },\n    )\n  }\n\n  const exceptionVisit = () => {\n    router.on('exception', (event) => {\n      internalAlert('Inertia.on(exception)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:exception', (event) => {\n      internalAlert('addEventListener(inertia:exception)')\n      internalAlert(event)\n    })\n\n    router.post(\n      '/disconnect',\n      {},\n      {\n        // @ts-expect-error - We're testing that the VisitCallbacks interface does not have an onException method\n        onException: () => internalAlert('This listener should not have been called.'),\n      },\n    )\n  }\n\n  const navigateVisit = () => {\n    router.on('navigate', (event) => {\n      internalAlert('Inertia.on(navigate)')\n      internalAlert(event)\n    })\n\n    document.addEventListener('inertia:navigate', (event) => {\n      internalAlert('addEventListener(inertia:navigate)')\n      internalAlert(event)\n    })\n\n    router.get(\n      '/',\n      {},\n      {\n        // @ts-expect-error - We're testing that the VisitCallbacks interface does not have an onNavigate method\n        onNavigate: () => internalAlert('This listener should not have been called.'),\n      },\n    )\n  }\n\n  const registerAllListeners = () => {\n    router.on('before', () => internalAlert('Inertia.on(before)'))\n    // @ts-expect-error - We're testing that the router doesn't have an onCancelToken listener\n    router.on('cancelToken', () => internalAlert('Inertia.on(cancelToken)'))\n    router.on('cancel', () => internalAlert('Inertia.on(cancel)'))\n    router.on('start', () => internalAlert('Inertia.on(start)'))\n    router.on('progress', () => internalAlert('Inertia.on(progress)'))\n    router.on('error', () => internalAlert('Inertia.on(error)'))\n    router.on('success', () => internalAlert('Inertia.on(success)'))\n    router.on('invalid', () => internalAlert('Inertia.on(invalid)'))\n    router.on('exception', () => internalAlert('Inertia.on(exception)'))\n    router.on('finish', () => internalAlert('Inertia.on(finish)'))\n    router.on('navigate', () => internalAlert('Inertia.on(navigate)'))\n    document.addEventListener('inertia:before', () => internalAlert('addEventListener(inertia:before)'))\n    document.addEventListener('inertia:cancelToken', () => internalAlert('addEventListener(inertia:cancelToken)'))\n    document.addEventListener('inertia:cancel', () => internalAlert('addEventListener(inertia:cancel)'))\n    document.addEventListener('inertia:start', () => internalAlert('addEventListener(inertia:start)'))\n    document.addEventListener('inertia:progress', () => internalAlert('addEventListener(inertia:progress)'))\n    document.addEventListener('inertia:error', () => internalAlert('addEventListener(inertia:error)'))\n    document.addEventListener('inertia:success', () => internalAlert('addEventListener(inertia:success)'))\n    document.addEventListener('inertia:invalid', () => internalAlert('addEventListener(inertia:invalid)'))\n    document.addEventListener('inertia:exception', () => internalAlert('addEventListener(inertia:exception)'))\n    document.addEventListener('inertia:finish', () => internalAlert('addEventListener(inertia:finish)'))\n    document.addEventListener('inertia:navigate', () => internalAlert('addEventListener(inertia:navigate)'))\n\n    return {\n      onBefore: () => internalAlert('onBefore'),\n      onCancelToken: () => internalAlert('onCancelToken'),\n      onCancel: () => internalAlert('onCancel'),\n      onStart: () => internalAlert('onStart'),\n      onProgress: () => internalAlert('onProgress'),\n      onError: () => internalAlert('onError'),\n      onSuccess: () => internalAlert('onSuccess'),\n      onInvalid: () => internalAlert('onInvalid'), // Does not exist.\n      onException: () => internalAlert('onException'), // Does not exist.\n      onFinish: () => internalAlert('onFinish'),\n      onNavigate: () => internalAlert('onNavigate'), // Does not exist.\n    }\n  }\n\n  const lifecycleSuccess = () => {\n    router.post($page.url, payloadWithFile, registerAllListeners())\n  }\n\n  const lifecycleError = () => {\n    router.post('/events/errors', payloadWithFile, registerAllListeners())\n  }\n\n  const lifecycleCancel = () => {\n    router.post('/sleep', payloadWithFile, {\n      ...registerAllListeners(),\n      onCancelToken: (token) => {\n        internalAlert('onCancelToken')\n\n        setTimeout(() => {\n          internalAlert('CANCELLING!')\n          token.cancel()\n        }, 250)\n      },\n    })\n  }\n\n  const lifecycleCancelAfterFinish = () => {\n    let cancelToken: { cancel: () => void } | null = null\n\n    router.post($page.url, payloadWithFile, {\n      ...registerAllListeners(),\n      onCancelToken: (token) => {\n        internalAlert('onCancelToken')\n        cancelToken = token\n      },\n      onFinish: () => {\n        internalAlert('onFinish')\n        internalAlert('CANCELLING!')\n        cancelToken?.cancel()\n      },\n    })\n  }\n\n  const callbackSuccessErrorPromise = (eventName: string) => {\n    internalAlert(eventName)\n    setTimeout(() => internalAlert('onFinish should have been fired by now if Promise functionality did not work'), 5)\n    return new Promise((resolve) => setTimeout(resolve, 20))\n  }\n\n  const handleCancelToken = (event: CustomEvent) => {\n    ;(event.detail as { token: { cancel: () => void } }).token.cancel()\n  }\n\n  const handleCancel = (event: Event | CustomEvent) => {\n    const customEvent = event as CustomEvent\n    internalAlert('linkOnCancel', customEvent.detail || undefined)\n  }\n\n  const handleProgress = (event: Event | CustomEvent<{ progress: unknown }>) => {\n    const customEvent = event as CustomEvent<{ progress: unknown }>\n    internalAlert('linkOnProgress', customEvent.detail.progress)\n  }\n\n  const handleError = (event: Event | CustomEvent<{ errors: unknown }>) => {\n    const customEvent = event as CustomEvent<{ errors: unknown }>\n    internalAlert('linkOnError', customEvent.detail.errors)\n  }\n</script>\n\n<div>\n  <!-- Listeners -->\n  <a href={'#'} on:click|preventDefault={withoutEventListeners} class=\"without-listeners\">Basic Visit</a>\n  <a href={'#'} on:click|preventDefault={removeInertiaListener} class=\"remove-inertia-listener\"\n    >Remove Inertia Listener</a\n  >\n\n  <!-- Events: Before -->\n  <a href={'#'} on:click|preventDefault={beforeVisit} class=\"before\">Before Event</a>\n  <a href={'#'} on:click|preventDefault={beforeVisitPreventLocal} class=\"before-prevent-local\">Before Event (Prevent)</a\n  >\n  <button\n    use:inertia={{ href: $page.url, method: 'post' }}\n    on:before={(event) => internalAlert('linkOnBefore', event.detail.visit)}\n    on:start={() => internalAlert('linkOnStart')}\n    class=\"link-before\">Before Event Link</button\n  >\n  <button\n    use:inertia={{ href: $page.url, method: 'post' }}\n    on:before={(event) => {\n      event.preventDefault()\n      internalAlert('linkOnBefore')\n    }}\n    on:start={() => {\n      internalAlert('This listener should not have been called.')\n    }}\n    class=\"link-before-prevent-local\">Before Event Link (Prevent)</button\n  >\n  <a href={'#'} on:click|preventDefault={beforeVisitPreventGlobalInertia} class=\"before-prevent-global-inertia\"\n    >Before Event - Prevent globally using Inertia Event Listener</a\n  >\n  <a href={'#'} on:click|preventDefault={beforeVisitPreventGlobalNative} class=\"before-prevent-global-native\"\n    >Before Event - Prevent globally using Native Event Listeners</a\n  >\n\n  <!-- Events: CancelToken -->\n  <a href={'#'} on:click|preventDefault={cancelTokenVisit} class=\"canceltoken\">Cancel Token Event</a>\n  <button\n    use:inertia={{ href: $page.url, method: 'post' }}\n    on:cancel-token={(event) => internalAlert('linkOnCancelToken', event.detail)}\n    class=\"link-canceltoken\">Cancel Token Event Link</button\n  >\n\n  <!-- Events: Cancel -->\n  <a href={'#'} on:click|preventDefault={cancelVisit} class=\"cancel\">Cancel Event</a>\n  <button\n    use:inertia={{ href: $page.url, method: 'post' }}\n    on:cancel-token={handleCancelToken}\n    on:cancel={handleCancel}\n    class=\"link-cancel\">Cancel Event Link</button\n  >\n\n  <!-- Events: Start -->\n  <a href={'#'} on:click|preventDefault={startVisit} class=\"start\">Start Event</a>\n  <button\n    use:inertia={{ href: $page.url, method: 'post' }}\n    on:start={(event) => internalAlert('linkOnStart', event.detail.visit)}\n    class=\"link-start\">Start Event Link</button\n  >\n\n  <!-- Events: Progress -->\n  <a href={'#'} on:click|preventDefault={progressVisit} class=\"progress\">Progress Event</a>\n  <a href={'#'} on:click|preventDefault={progressNoFilesVisit} class=\"progress-no-files\"\n    >Missing Progress Event (no files)</a\n  >\n  <button\n    use:inertia={{ href: $page.url, method: 'post', data: payloadWithFile }}\n    on:progress={handleProgress}\n    class=\"link-progress\">Progress Event Link</button\n  >\n  <button\n    use:inertia={{ href: $page.url, method: 'post' }}\n    on:before={() => internalAlert('linkProgressNoFilesOnBefore')}\n    on:progress={handleProgress}\n    class=\"link-progress-no-files\">Progress Event Link (no files)</button\n  >\n\n  <!-- Events: Error -->\n  <a href={'#'} on:click|preventDefault={errorVisit} class=\"error\">Error Event</a>\n  <a href={'#'} on:click|preventDefault={errorPromiseVisit} class=\"error-promise\"\n    >Error Event (delaying onFinish w/ Promise)</a\n  >\n  <button\n    use:inertia={{ href: '/events/errors', method: 'post' }}\n    on:error={handleError}\n    on:success={() => internalAlert('This listener should not have been called')}\n    class=\"link-error\">Error Event Link</button\n  >\n  <button\n    use:inertia={{ href: '/events/errors', method: 'post' }}\n    on:error={() => callbackSuccessErrorPromise('linkOnError')}\n    on:success={() => internalAlert('This listener should not have been called')}\n    on:finish={() => internalAlert('linkOnFinish')}\n    class=\"link-error-promise\">Error Event Link (delaying onFinish w/ Promise)</button\n  >\n\n  <!-- Events: Success -->\n  <a href={'#'} on:click|preventDefault={successVisit} class=\"success\">Success Event</a>\n  <a href={'#'} on:click|preventDefault={successPromiseVisit} class=\"success-promise\"\n    >Success Event (delaying onFinish w/ Promise)</a\n  >\n  <button\n    use:inertia={{ href: $page.url, method: 'post' }}\n    on:error={() => internalAlert('This listener should not have been called')}\n    on:success={(event) => internalAlert('linkOnSuccess', event.detail.page)}\n    class=\"link-success\">Success Event Link</button\n  >\n  <button\n    use:inertia={{ href: $page.url, method: 'post' }}\n    on:error={() => internalAlert('This listener should not have been called')}\n    on:success={() => callbackSuccessErrorPromise('linkOnSuccess')}\n    on:finish={() => internalAlert('linkOnFinish')}\n    class=\"link-success-promise\">Success Event Link (delaying onFinish w/ Promise)</button\n  >\n\n  <!-- Events: Invalid -->\n  <a href={'#'} on:click|preventDefault={invalidVisit} class=\"invalid\">Invalid Event</a>\n\n  <!-- Events: Exception -->\n  <a href={'#'} on:click|preventDefault={exceptionVisit} class=\"exception\">Exception Event</a>\n\n  <!-- Events: Finish -->\n  <a href={'#'} on:click|preventDefault={finishVisit} class=\"finish\">Finish Event</a>\n  <button\n    use:inertia={{ href: $page.url, method: 'post' }}\n    on:finish={(event) => internalAlert('linkOnFinish', event.detail.visit)}\n    class=\"link-finish\">Finish Event Link</button\n  >\n\n  <!-- Events: Navigate -->\n  <a href={'#'} on:click|preventDefault={navigateVisit} class=\"navigate\">Navigate Event</a>\n\n  <!-- Events: Prefetch -->\n  <button\n    use:inertia={{ href: '/prefetch/2', prefetch: 'hover' }}\n    on:prefetching={(event) => internalAlert('linkOnPrefetching', event.detail.visit)}\n    on:prefetched={(event) => internalAlert('linkOnPrefetched', event.detail.response, event.detail.visit)}\n    class=\"link-prefetch-hover\"\n  >\n    Prefetch Event Link (Hover)\n  </button>\n\n  <!-- Lifecycles -->\n  <a href={'#'} on:click|preventDefault={lifecycleSuccess} class=\"lifecycle-success\">Lifecycle Success</a>\n  <a href={'#'} on:click|preventDefault={lifecycleError} class=\"lifecycle-error\">Lifecycle Error</a>\n  <a href={'#'} on:click|preventDefault={lifecycleCancel} class=\"lifecycle-cancel\">Lifecycle Cancel</a>\n  <a href={'#'} on:click|preventDefault={lifecycleCancelAfterFinish} class=\"lifecycle-cancel-after-finish\"\n    >Lifecycle Cancel - After Finish</a\n  >\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Flash/ClientSideVisits.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  declare global {\n    interface Window {\n      flashCount: number\n    }\n  }\n</script>\n\n<script lang=\"ts\">\n  import { router, page } from '@inertiajs/svelte'\n\n  window.flashCount ??= 0\n\n  const withFlash = () => {\n    router.replace({\n      flash: { foo: 'bar' },\n      onFlash: () => window.flashCount++,\n    })\n  }\n\n  const withFlashFunction = () => {\n    router.replace({\n      flash: (flash) => ({ ...flash, bar: 'baz' }),\n      onFlash: () => window.flashCount++,\n    })\n  }\n\n  const withoutFlash = () => {\n    router.replace({\n      props: (props) => ({ ...props }),\n      onFlash: () => window.flashCount++,\n    })\n  }\n</script>\n\n<div>\n  <span id=\"flash\">{JSON.stringify($page.flash)}</span>\n\n  <button on:click={withFlash}>With flash object</button>\n  <button on:click={withFlashFunction}>With flash function</button>\n  <button on:click={withoutFlash}>Without flash</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Flash/Events.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  declare global {\n    interface Window {\n      messages: unknown[]\n    }\n  }\n</script>\n\n<script lang=\"ts\">\n  import { router, page } from '@inertiajs/svelte'\n\n  window.messages = []\n\n  const internalAlert = (...args: unknown[]) => {\n    window.messages.push(...args)\n  }\n\n  const visitWithFlash = () => {\n    router.on('flash', (event) => {\n      internalAlert('Inertia.on(flash)')\n      internalAlert(event.detail.flash)\n    })\n\n    document.addEventListener('inertia:flash', (event) => {\n      internalAlert('addEventListener(inertia:flash)')\n      internalAlert((event as CustomEvent).detail.flash)\n    })\n\n    router.post(\n      '/flash/events/with-data',\n      {},\n      {\n        onFlash: (flash) => {\n          internalAlert('onFlash')\n          internalAlert(flash)\n        },\n        onSuccess: (page) => {\n          internalAlert('onSuccess')\n          internalAlert(page.flash)\n        },\n      },\n    )\n  }\n\n  const visitWithoutFlash = () => {\n    router.on('flash', () => {\n      internalAlert('Inertia.on(flash)')\n    })\n\n    document.addEventListener('inertia:flash', () => {\n      internalAlert('addEventListener(inertia:flash)')\n    })\n\n    router.post(\n      '/flash/events/without-data',\n      {},\n      {\n        onFlash: () => {\n          internalAlert('onFlash')\n        },\n        onSuccess: () => {\n          internalAlert('onSuccess')\n        },\n      },\n    )\n  }\n\n  const navigateAway = () => {\n    router.get('/')\n  }\n</script>\n\n<div>\n  <span id=\"flash\">{JSON.stringify($page.flash)}</span>\n\n  <a href={'#'} on:click|preventDefault={visitWithFlash} class=\"with-flash\">Visit with flash</a>\n  <a href={'#'} on:click|preventDefault={visitWithoutFlash} class=\"without-flash\">Visit without flash</a>\n  <a href={'#'} on:click|preventDefault={navigateAway} class=\"navigate-away\">Navigate away</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Flash/InitialFlash.svelte",
    "content": "<script lang=\"ts\">\n  import { page, router } from '@inertiajs/svelte'\n\n  let flashEvents: Record<string, unknown>[] = []\n\n  router.on('flash', (e) => {\n    flashEvents = [...flashEvents, e.detail.flash]\n  })\n</script>\n\n<div>\n  <span id=\"flash\">{$page.flash ? JSON.stringify($page.flash) : 'no-flash'}</span>\n  <span id=\"flash-events\">{JSON.stringify(flashEvents)}</span>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Flash/Partial.svelte",
    "content": "<script lang=\"ts\">\n  import { page, router } from '@inertiajs/svelte'\n\n  export let count: number\n\n  let flashEventCount = 0\n\n  router.on('flash', () => {\n    flashEventCount++\n  })\n\n  const reloadWithSameFlash = () => {\n    router.reload({ only: ['count'], data: { flashType: 'same', count: Date.now() } })\n  }\n\n  const reloadWithDifferentFlash = () => {\n    router.reload({ only: ['count'], data: { flashType: 'different', count: Date.now() } })\n  }\n</script>\n\n<div>\n  <span id=\"flash\">{JSON.stringify($page.flash)}</span>\n  <span id=\"flash-event-count\">{flashEventCount}</span>\n  <span id=\"count\">{count}</span>\n\n  <button on:click={reloadWithSameFlash}>Reload with same flash</button>\n  <button on:click={reloadWithDifferentFlash}>Reload with different flash</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Flash/RouterFlash.svelte",
    "content": "<script lang=\"ts\">\n  import { router, page } from '@inertiajs/svelte'\n\n  const setFlash = () => {\n    router.flash({ foo: 'bar' })\n  }\n\n  const setFlashKeyValue = () => {\n    router.flash('foo', 'bar')\n  }\n\n  const mergeFlash = () => {\n    router.flash((current) => ({ ...current, bar: 'baz' }))\n  }\n\n  const clearFlash = () => {\n    router.flash(() => ({}))\n  }\n</script>\n\n<div>\n  <span id=\"flash\">{JSON.stringify($page.flash)}</span>\n\n  <button on:click={setFlash}>Set flash</button>\n  <button on:click={setFlashKeyValue}>Set flash key-value</button>\n  <button on:click={mergeFlash}>Merge flash</button>\n  <button on:click={clearFlash}>Clear flash</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Flash/WithDeferred.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred, page, router } from '@inertiajs/svelte'\n\n  export let data: string | undefined\n\n  let flashEventCount = 0\n\n  router.on('flash', () => {\n    flashEventCount++\n  })\n</script>\n\n<div>\n  <span id=\"flash\">{JSON.stringify($page.flash)}</span>\n  <span id=\"flash-event-count\">{flashEventCount}</span>\n\n  <Deferred data=\"data\">\n    <div id=\"loading\" slot=\"fallback\">Loading...</div>\n    <div id=\"data\">{data}</div>\n  </Deferred>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Flash/WithInfiniteScroll.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll, page, router } from '@inertiajs/svelte'\n\n  export let users: { data: { id: number; name: string }[] }\n\n  let flashEventCount = 0\n\n  router.on('flash', () => {\n    flashEventCount++\n  })\n</script>\n\n<div>\n  <span id=\"flash\">{JSON.stringify($page.flash)}</span>\n  <span id=\"flash-event-count\">{flashEventCount}</span>\n\n  <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\">\n    {#each users.data as user (user.id)}\n      <div style=\"height: 15vh; border: 1px solid #ccc\">\n        {user.name}\n      </div>\n    {/each}\n  </InfiniteScroll>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Context/ChildComponent.svelte",
    "content": "<script lang=\"ts\">\n  import { useFormContext } from '@inertiajs/svelte'\n\n  export let formId: string | undefined = undefined\n\n  const form = useFormContext()\n</script>\n\n{#if $form}\n  <div>\n    <span>Child: Form is {$form.isDirty ? 'dirty' : 'clean'}</span>\n    {#if $form.hasErrors}<span> | Child: Form has errors</span>{/if}\n    {#if $form.processing}<span> | Child: Form is processing</span>{/if}\n    {#if $form.wasSuccessful}<span> | Child: Form was successful</span>{/if}\n    {#if $form.recentlySuccessful}<span> | Child: Form recently successful</span>{/if}\n    {#if $form.errors.name}<span> | Error: {$form.errors.name}</span>{/if}\n  </div>\n{:else}\n  <div>No form context available</div>\n{/if}\n\n<button\n  type=\"button\"\n  on:click={() => $form?.setError('name', formId ? 'Error from child' : 'Error set from child component')}\n>\n  Set Error\n</button>\n<button type=\"button\" on:click={() => $form?.clearErrors('name')}>Clear Error</button>\n{#if !formId}\n  <button type=\"button\" on:click={() => $form?.submit()}>Submit from Child</button>\n  <button type=\"button\" on:click={() => $form?.reset()}>Reset from Child</button>\n  <button type=\"button\" on:click={() => $form?.defaults()}>Set Defaults</button>\n{/if}\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Context/DeeplyNestedComponent.svelte",
    "content": "<script lang=\"ts\">\n  import { useFormContext } from '@inertiajs/svelte'\n\n  const form = useFormContext()\n</script>\n\n{#if $form}\n  <div>\n    <span>Deeply Nested: Form is {$form.isDirty ? 'dirty' : 'clean'}</span>\n  </div>\n{:else}\n  <div>No context</div>\n{/if}\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Context/Default.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n  import ChildComponent from './ChildComponent.svelte'\n  import NestedComponent from './NestedComponent.svelte'\n  import OutsideFormComponent from './OutsideFormComponent.svelte'\n</script>\n\n<Form action=\"/dump/post\" method=\"post\" let:isDirty let:hasErrors let:errors>\n  <div>\n    <span>Parent: Form is {isDirty ? 'dirty' : 'clean'}</span>\n    {#if hasErrors}<span> | Parent: Form has errors</span>{/if}\n    {#if errors.name}<span> | {errors.name}</span>{/if}\n  </div>\n\n  <input type=\"text\" name=\"name\" value=\"John Doe\" />\n  <input type=\"email\" name=\"email\" value=\"john@example.com\" />\n\n  <ChildComponent />\n  <NestedComponent />\n</Form>\n\n<OutsideFormComponent />\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Context/Methods.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n  import MethodsTestComponent from './MethodsTestComponent.svelte'\n</script>\n\n<Form action=\"/form-component/context/methods\" method=\"post\" let:errors>\n  {#if Object.keys(errors).length}<pre>{JSON.stringify(errors, null, 2)}</pre>{/if}\n\n  <input type=\"text\" name=\"name\" value=\"Initial Name\" />\n  <input type=\"email\" name=\"email\" value=\"initial@example.com\" />\n  <textarea name=\"bio\">Initial bio</textarea>\n\n  <MethodsTestComponent />\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Context/MethodsTestComponent.svelte",
    "content": "<script lang=\"ts\">\n  import { useFormContext } from '@inertiajs/svelte'\n\n  const form = useFormContext()\n\n  let getDataResult = ''\n  let getFormDataResult = ''\n\n  function testGetData() {\n    if ($form) {\n      getDataResult = JSON.stringify($form.getData(), null, 2)\n    }\n  }\n\n  function testGetFormData() {\n    if ($form) {\n      const formData = $form.getFormData()\n      const obj: Record<string, FormDataEntryValue> = {}\n      formData.forEach((value, key) => {\n        obj[key] = value\n      })\n      getFormDataResult = JSON.stringify(obj, null, 2)\n    }\n  }\n</script>\n\n{#if $form}\n  {#if $form.processing}<span>Child: processing</span>{/if}\n  {#if $form.wasSuccessful}<span>Child: was successful</span>{/if}\n  {#if $form.recentlySuccessful}<span>Child: recently successful</span>{/if}\n  {#if $form.hasErrors}<pre>{JSON.stringify($form.errors, null, 2)}</pre>{/if}\n\n  <button type=\"button\" on:click={() => $form.submit()}>submit()</button>\n  <button type=\"button\" on:click={() => $form.reset()}>reset()</button>\n  <button type=\"button\" on:click={() => $form.reset('name')}>reset('name')</button>\n  <button type=\"button\" on:click={() => $form.reset('name', 'email')}>reset('name', 'email')</button>\n\n  <button type=\"button\" on:click={() => $form.clearErrors()}>clearErrors()</button>\n  <button type=\"button\" on:click={() => $form.clearErrors('name')}>clearErrors('name')</button>\n  <button type=\"button\" on:click={() => $form.setError('name', 'Name is invalid')}>setError('name')</button>\n  <button\n    type=\"button\"\n    on:click={() =>\n      $form.setError({ name: 'Name error from child', email: 'Email error from child', bio: 'Bio error from child' })}\n    >setError({'{...}'})</button\n  >\n\n  <button type=\"button\" on:click={() => $form.resetAndClearErrors()}>resetAndClearErrors()</button>\n  <button type=\"button\" on:click={() => $form.resetAndClearErrors('name')}>resetAndClearErrors('name')</button>\n\n  <button type=\"button\" on:click={testGetData}>getData()</button>\n  <button type=\"button\" on:click={testGetFormData}>getFormData()</button>\n\n  {#if getDataResult}<pre id=\"get-data-result\">{getDataResult}</pre>{/if}\n  {#if getFormDataResult}<pre id=\"get-form-data-result\">{getFormDataResult}</pre>{/if}\n{:else}\n  <div>No form context available</div>\n{/if}\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Context/Multiple.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n  import ChildComponent from './ChildComponent.svelte'\n</script>\n\n<Form action=\"/dump/post\" method=\"post\" let:isDirty let:errors>\n  <div>\n    <span>Form 1 Parent: {isDirty ? 'dirty' : 'clean'}</span>\n    {#if errors.name}<span> | Error: {errors.name}</span>{/if}\n  </div>\n  <input type=\"text\" name=\"name\" value=\"Form 1 Name\" />\n  <ChildComponent formId=\"form1\" />\n</Form>\n\n<Form action=\"/dump/post\" method=\"post\" let:isDirty let:errors>\n  <div>\n    <span>Form 2 Parent: {isDirty ? 'dirty' : 'clean'}</span>\n    {#if errors.name}<span> | Error: {errors.name}</span>{/if}\n  </div>\n  <input type=\"text\" name=\"name\" value=\"Form 2 Name\" />\n  <ChildComponent formId=\"form2\" />\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Context/NestedComponent.svelte",
    "content": "<script lang=\"ts\">\n  import DeeplyNestedComponent from './DeeplyNestedComponent.svelte'\n</script>\n\n<DeeplyNestedComponent />\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Context/OutsideFormComponent.svelte",
    "content": "<script lang=\"ts\">\n  import { useFormContext } from '@inertiajs/svelte'\n\n  const form = useFormContext()\n</script>\n\n{#if $form === undefined}\n  <div>Correctly returns undefined when used outside a Form component</div>\n{:else}\n  <div>Unexpectedly has form context</div>\n{/if}\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/DataMethods.svelte",
    "content": "<script lang=\"ts\">\n  import type { FormDataConvertible } from '@inertiajs/core'\n  import { Form } from '@inertiajs/svelte'\n\n  function testGetData(getData: () => Record<string, FormDataConvertible>) {\n    const data = getData()\n    console.log('getData result: ' + JSON.stringify(data))\n  }\n\n  function testGetFormData(getFormData: () => FormData) {\n    const formData = getFormData()\n    console.log('getFormData entries: ' + JSON.stringify(Object.fromEntries(formData.entries())))\n  }\n</script>\n\n<div>\n  <h1>Test getData() and getFormData() Methods</h1>\n\n  <Form let:getData let:getFormData>\n    <input type=\"text\" id=\"name\" name=\"name\" />\n\n    <button type=\"button\" on:click={() => testGetData(getData)}> Test getData() </button>\n\n    <button type=\"button\" on:click={() => testGetFormData(getFormData)}> Test getFormData() </button>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/DefaultValue.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n\n  export let user: {\n    name: string\n  }\n</script>\n\n<Form action=\"/form-component/default-value\" method=\"patch\" let:errors>\n  <h1>Form Default Values</h1>\n\n  <div>\n    <label for=\"name\">Name</label>\n    <input type=\"text\" name=\"name\" id=\"name\" value={user.name} />\n    <div id=\"error_name\">{errors['user.name']}</div>\n  </div>\n\n  <button type=\"submit\">Submit</button>\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/DisableWhileProcessing.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n  export let disable: boolean = false\n  let url = `/form-component/disable-while-processing/${disable ? 'yes' : 'no'}/submit`\n</script>\n\n<div>\n  <h1>Form Disable While Processing Test</h1>\n\n  <Form method=\"post\" let:errors bind:action={url} disableWhileProcessing={disable}>\n    <div>\n      <input type=\"text\" name=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n      {#if errors.name}\n        <p id=\"error_name\">{errors.name}</p>\n      {/if}\n    </div>\n\n    <div>\n      <button type=\"submit\">Submit</button>\n    </div>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/DottedKeys.svelte",
    "content": "<script>\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <h1>Dotted Keys Form Test</h1>\n\n  <!-- Test basic and nested dotted keys -->\n  <Form action=\"/dump/post\" method=\"post\">\n    <h2>Basic Dotted Keys</h2>\n    <input type=\"text\" name=\"user.name\" placeholder=\"User Name\" />\n    <input type=\"text\" name=\"user.profile.city\" placeholder=\"City\" />\n    <input type=\"text\" name=\"user.skills[]\" placeholder=\"First Skill\" />\n    <input type=\"text\" name=\"user.skills[]\" placeholder=\"Second Skill\" />\n    <input type=\"text\" name=\"company.address.street\" placeholder=\"Street\" />\n    <button type=\"submit\">Submit Basic</button>\n  </Form>\n\n  <!-- Test escaped dots (literal keys) -->\n  <Form action=\"/dump/post\" method=\"post\">\n    <h2>Escaped Dots</h2>\n    <input type=\"text\" name=\"config\\.app\\.name\" placeholder=\"App Name\" />\n    <input type=\"text\" name=\"settings.theme\\.mode\" placeholder=\"Theme Mode\" />\n    <button type=\"submit\">Submit Escaped</button>\n  </Form>\n\n  <!-- Test mixed bracket and dotted notation -->\n  <Form action=\"/dump/post\" method=\"post\">\n    <h2>Mixed Notation</h2>\n    <input type=\"text\" name=\"user[roles][]\" value=\"admin\" />\n    <input type=\"text\" name=\"user[roles][]\" value=\"editor\" />\n    <input type=\"text\" name=\"settings.ui.theme\" placeholder=\"UI Theme\" />\n    <button type=\"submit\">Submit Mixed</button>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Elements.svelte",
    "content": "<script lang=\"ts\">\n  import { config, Form } from '@inertiajs/svelte'\n  import type { QueryStringArrayFormatOption } from '@inertiajs/core'\n\n  export let queryStringArrayFormat: QueryStringArrayFormatOption | 'force-brackets'\n\n  const format = queryStringArrayFormat === 'force-brackets' ? 'brackets' : queryStringArrayFormat\n\n  if (queryStringArrayFormat === 'force-brackets') {\n    config.set('form.forceIndicesArrayFormatInFormData', false)\n  }\n</script>\n\n<Form action=\"/dump/post\" method=\"post\" let:isDirty queryStringArrayFormat={format}>\n  <h1>Form Elements</h1>\n\n  <div>\n    Form is <span>{isDirty ? 'dirty' : 'clean'}</span>\n  </div>\n\n  <!-- Text input -->\n  <div>\n    <input type=\"text\" name=\"name\" id=\"name\" placeholder=\"Name\" />\n  </div>\n\n  <!-- Select with default selected option -->\n  <div>\n    <select name=\"country\" id=\"country\" value=\"uk\">\n      <option value=\"us\">United States</option>\n      <option value=\"ca\">Canada</option>\n      <option value=\"uk\">United Kingdom</option>\n    </select>\n  </div>\n\n  <!-- Select with default disabled option -->\n  <div>\n    <select name=\"role\" id=\"role\" value=\"\">\n      <option value=\"\" disabled>Role</option>\n      <option value=\"User\">User</option>\n      <option value=\"Admin\">Admin</option>\n      <option value=\"Super\">Super</option>\n    </select>\n  </div>\n\n  <!-- Radio buttons -->\n  <div>\n    <label><input type=\"radio\" name=\"plan\" value=\"free\" /> Free</label>\n    <label><input type=\"radio\" name=\"plan\" value=\"pro\" /> Pro</label>\n    <label><input type=\"radio\" name=\"plan\" value=\"enterprise\" /> Enterprise</label>\n  </div>\n\n  <!-- Checkbox (single) -->\n  <div>\n    <input type=\"checkbox\" name=\"subscribe\" value=\"yes\" id=\"subscribe\" />\n    <label for=\"subscribe\">Subscribe to newsletter</label>\n  </div>\n\n  <!-- Checkbox (multiple) -->\n  <div>\n    <label><input type=\"checkbox\" name=\"interests[]\" value=\"sports\" /> Sports</label>\n    <label><input type=\"checkbox\" name=\"interests[]\" value=\"music\" /> Music</label>\n    <label><input type=\"checkbox\" name=\"interests[]\" value=\"tech\" /> Tech</label>\n  </div>\n\n  <!-- Multiple select -->\n  <div>\n    <select name=\"skills[]\" id=\"skills\" multiple value=\"\">\n      <option disabled value=\"\">Skills</option>\n      <option value=\"vue\">Vue</option>\n      <option value=\"react\">React</option>\n      <option value=\"angular\">Angular</option>\n      <option value=\"svelte\">Svelte</option>\n    </select>\n  </div>\n\n  <!-- File input (single) -->\n  <div>\n    <input type=\"file\" name=\"avatar\" id=\"avatar\" placeholder=\"Avatar\" />\n  </div>\n\n  <!-- File input (multiple) -->\n  <div>\n    <input type=\"file\" name=\"documents[]\" id=\"documents\" multiple placeholder=\"Documents\" />\n  </div>\n\n  <!-- Textarea -->\n  <div>\n    <textarea name=\"bio\" id=\"bio\" rows=\"3\" placeholder=\"Bio\"></textarea>\n  </div>\n\n  <!-- Hidden input -->\n  <div>\n    <input type=\"hidden\" name=\"token\" id=\"token\" value=\"abc123\" />\n  </div>\n\n  <!-- Number input -->\n  <div>\n    <input type=\"number\" name=\"age\" id=\"age\" placeholder=\"Age\" />\n  </div>\n\n  <!-- Deep nested input -->\n  <div>\n    <input type=\"text\" name=\"user[address][street]\" id=\"nested_street\" placeholder=\"Street\" />\n  </div>\n\n  <!-- Indexed array of objects -->\n  <div>\n    <input type=\"text\" name=\"items[0][name]\" value=\"Item A\" id=\"item_a\" />\n    <input type=\"text\" name=\"items[1][name]\" value=\"Item B\" id=\"item_b\" />\n  </div>\n\n  <!-- Disabled input (should be ignored) -->\n  <div>\n    <input type=\"text\" name=\"disabled_field\" value=\"Ignore me\" disabled />\n  </div>\n\n  <button type=\"submit\">Submit</button>\n  <button type=\"reset\">Reset</button>\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/EmptyAction.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <h1>Form Empty Action Test</h1>\n\n  <Form method=\"post\" let:errors>\n    <div>\n      <input type=\"text\" name=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n      {#if errors.name}\n        <p id=\"error_name\">{errors.name}</p>\n      {/if}\n    </div>\n\n    <div>\n      <button type=\"submit\">Submit</button>\n    </div>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Errors.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n\n  let errorBag: string | null = null\n</script>\n\n<Form\n  action={errorBag ? '/form-component/errors/bag' : '/form-component/errors'}\n  method=\"post\"\n  {errorBag}\n  let:errors\n  let:hasErrors\n  let:setError\n  let:clearErrors\n>\n  <h1>Form Errors</h1>\n\n  {#if hasErrors}\n    <div>Form has errors</div>\n  {:else}\n    <div>No errors</div>\n  {/if}\n\n  <div>\n    <label for=\"name\">Name</label>\n    <input type=\"text\" name=\"name\" id=\"name\" />\n    <div id=\"error_name\">{errors.name || ''}</div>\n  </div>\n\n  <div>\n    <label for=\"handle\">Handle</label>\n    <input type=\"text\" name=\"handle\" id=\"handle\" />\n    <div id=\"error_handle\">{errors.handle || ''}</div>\n  </div>\n\n  <div>\n    <button\n      type=\"button\"\n      on:click={() =>\n        setError({\n          name: 'The name field is required.',\n          handle: 'The handle field is invalid.',\n        })}\n    >\n      Set Errors\n    </button>\n    <button type=\"button\" on:click={() => clearErrors()}>Clear Errors</button>\n    <button type=\"button\" on:click={() => clearErrors('name')}>Clear Name Error</button>\n    <button type=\"button\" on:click={() => (errorBag = 'bag')}>Use Error Bag</button>\n  </div>\n\n  <button type=\"submit\">Submit</button>\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Events.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n\n  let events: string[] = []\n  let cancelInOnBefore = false\n  let shouldFail = false\n  let shouldDelay = false\n  let cancelToken: { cancel: () => void } | null = null\n\n  function log(eventName: string) {\n    events = [...events, eventName]\n  }\n\n  $: action = (() => {\n    if (shouldFail) {\n      return '/form-component/events/errors'\n    }\n\n    if (shouldDelay) {\n      return '/form-component/events/delay'\n    }\n\n    return '/form-component/events/success'\n  })()\n\n  function onBefore() {\n    log('onBefore')\n\n    if (cancelInOnBefore) {\n      log('onCancel')\n      return false\n    }\n  }\n\n  function onStart() {\n    log('onStart')\n  }\n\n  function onProgress() {\n    log('onProgress')\n  }\n\n  function onFinish() {\n    log('onFinish')\n  }\n\n  function onCancel() {\n    log('onCancel')\n  }\n\n  function onSuccess() {\n    log('onSuccess')\n  }\n\n  function onError() {\n    log('onError')\n  }\n\n  function onCancelToken(token: { cancel: () => void }) {\n    log('onCancelToken')\n    cancelToken = token\n  }\n\n  function cancelVisit() {\n    if (cancelToken) {\n      cancelToken.cancel()\n      cancelToken = null\n    }\n  }\n</script>\n\n<Form\n  {action}\n  method=\"post\"\n  {onBefore}\n  {onStart}\n  {onProgress}\n  {onFinish}\n  {onCancel}\n  {onSuccess}\n  {onError}\n  {onCancelToken}\n  let:processing\n  let:progress\n  let:wasSuccessful\n  let:recentlySuccessful\n>\n  <h1>Form Events & State</h1>\n\n  <div>\n    Events: <span id=\"events\">{events.join(',')}</span>\n  </div>\n\n  <div>\n    Processing: <span id=\"processing\">{String(processing)}</span>\n  </div>\n\n  <div>\n    Progress: <span id=\"progress\" class={progress?.percentage ? 'uploading' : ''}>\n      {progress?.percentage || 0}\n    </span>\n  </div>\n\n  <div>\n    Was successful: <span id=\"was-successful\">{String(wasSuccessful)}</span>\n  </div>\n\n  <div>\n    Recently successful: <span id=\"recently-successful\">{String(recentlySuccessful)}</span>\n  </div>\n\n  <div>\n    <input type=\"file\" name=\"avatar\" id=\"avatar\" />\n  </div>\n\n  <div>\n    <button type=\"button\" on:click={() => (cancelInOnBefore = true)}>Cancel in onBefore</button>\n    <button type=\"button\" on:click={() => (shouldFail = true)}>Fail Request</button>\n    <button type=\"button\" on:click={() => (shouldDelay = true)}>Should Delay</button>\n    <button type=\"button\" on:click={cancelVisit}>Cancel Visit</button>\n    <button type=\"submit\">Submit</button>\n  </div>\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/FormTarget.svelte",
    "content": "<script>\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<Form action=\"/non-inertia/download\" method=\"get\">\n  <input type=\"text\" name=\"search\" id=\"search\" value=\"test-query\" />\n\n  <button type=\"submit\" formtarget=\"_blank\" name=\"format\" value=\"csv\" id=\"button-blank\">\n    Button with formTarget blank\n  </button>\n  <input type=\"submit\" formtarget=\"_blank\" name=\"type\" value=\"export\" id=\"input-blank\" />\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Headers.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n\n  let headers: Record<string, string> = {\n    'X-Foo': 'Bar',\n  }\n\n  function addCustomHeader() {\n    headers = {\n      ...headers,\n      'X-Custom': 'MyCustomValue',\n    }\n  }\n</script>\n\n<Form action=\"/dump/post\" method=\"post\" {headers}>\n  <h1>Form Headers</h1>\n\n  <div>\n    <button type=\"button\" on:click={addCustomHeader}>Add Custom Header</button>\n  </div>\n\n  <button type=\"submit\">Submit</button>\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/InvalidateTags.svelte",
    "content": "<script lang=\"ts\">\n  import { Link, Form } from '@inertiajs/svelte'\n\n  export let lastLoaded\n  export let propType\n</script>\n\n<div>\n  <div id=\"links\">\n    <Link href=\"/prefetch/tags/1\" prefetch=\"hover\" cacheTags={propType === 'string' ? 'user' : ['user']}>\n      User Tagged Page\n    </Link>\n    <Link href=\"/prefetch/tags/2\" prefetch=\"hover\" cacheTags={propType === 'string' ? 'product' : ['product']}>\n      Product Tagged Page\n    </Link>\n  </div>\n\n  <div id=\"form-section\">\n    <h3>Form Component with invalidateCacheTags</h3>\n    <Form action=\"/dump/post\" method=\"post\" invalidateCacheTags={propType === 'string' ? 'user' : ['user']}>\n      <input id=\"form-name\" name=\"name\" type=\"text\" placeholder=\"Enter name\" />\n      <button id=\"submit-invalidate-user\" type=\"submit\"> Submit (Invalidate User Tags) </button>\n    </Form>\n  </div>\n\n  <div>\n    <div>Form Component Invalidate Tags Test Page</div>\n    <div>\n      Last loaded at <span id=\"last-loaded\">{lastLoaded}</span>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Methods.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n  import type { Method } from '@inertiajs/core'\n\n  let method: Method = 'get'\n</script>\n\n<div>\n  <h1>HTTP Methods</h1>\n\n  <div>\n    <button on:click={() => (method = 'get')}>GET</button>\n    <button on:click={() => (method = 'post')}>POST</button>\n    <button on:click={() => (method = 'put')}>PUT</button>\n    <button on:click={() => (method = 'patch')}>PATCH</button>\n    <button on:click={() => (method = 'delete')}>DELETE</button>\n  </div>\n\n  <div>Current method: {method}</div>\n\n  <Form action={`/dump/${method}`} {method}>\n    <div>\n      <input type=\"text\" name=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n    </div>\n\n    <div>\n      <label for=\"active\">Active</label>\n      <input type=\"checkbox\" name=\"active\" id=\"active\" value=\"true\" checked />\n    </div>\n\n    <div>\n      <button type=\"submit\">\n        Submit {method.toUpperCase()}\n      </button>\n    </div>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/MixedKeySerialization.svelte",
    "content": "<script>\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <h1>Mixed Key Serialization</h1>\n\n  <Form action=\"/dump/post\" method=\"post\">\n    <div>\n      <input type=\"text\" name=\"fields[entries][100][name]\" placeholder=\"Name for ID 100\" value=\"John Doe\" />\n    </div>\n\n    <div>\n      <input type=\"email\" name=\"fields[entries][100][email]\" placeholder=\"Email for ID 100\" value=\"john@example.com\" />\n    </div>\n\n    <div>\n      <input type=\"text\" name=\"fields[entries][new:1][name]\" placeholder=\"Name for new entry\" value=\"Jane Smith\" />\n    </div>\n\n    <div>\n      <input\n        type=\"email\"\n        name=\"fields[entries][new:1][email]\"\n        placeholder=\"Email for new entry\"\n        value=\"jane@example.com\"\n      />\n    </div>\n\n    <button type=\"submit\">Submit</button>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Options.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n  import type { Method, QueryStringArrayFormatOption } from '@inertiajs/core'\n  import Article from '../Article.svelte'\n\n  let only: string[] = []\n  let except: string[] = []\n  let reset: string[] = []\n  let replace = false\n  let state = 'Default State'\n  let preserveScroll = false\n  let preserveState = false\n  let preserveUrl = false\n  let queryStringArrayFormat: QueryStringArrayFormatOption | undefined = undefined\n\n  function setOnly() {\n    only = ['users']\n  }\n\n  function setExcept() {\n    except = ['stats']\n  }\n\n  function setReset() {\n    reset = ['orders']\n  }\n\n  function enableReplace() {\n    replace = true\n  }\n\n  function enablePreserveScroll() {\n    preserveScroll = true\n  }\n\n  function enablePreserveState() {\n    preserveState = true\n    state = 'Replaced State'\n  }\n\n  function enablePreserveUrl() {\n    preserveUrl = true\n  }\n\n  $: action = (() => {\n    if (preserveScroll) {\n      return '/article'\n    }\n\n    if (preserveState) {\n      return '/form-component/options'\n    }\n\n    if (preserveUrl) {\n      return '/form-component/options?page=2'\n    }\n\n    return queryStringArrayFormat ? '/dump/get' : '/dump/post'\n  })()\n\n  $: method = (() => {\n    if (preserveScroll || preserveState || preserveUrl) {\n      return 'get'\n    }\n\n    return queryStringArrayFormat ? 'get' : 'post'\n  })() as Method\n\n  $: options = {\n    only,\n    except,\n    reset,\n    replace,\n    preserveScroll,\n    preserveState,\n    preserveUrl,\n  }\n</script>\n\n<Form {action} {method} {options} {queryStringArrayFormat}>\n  <h1>Form Options</h1>\n\n  <input type=\"text\" name=\"tags[]\" value=\"alpha\" readonly />\n  <input type=\"text\" name=\"tags[]\" value=\"beta\" readonly />\n\n  <div>\n    State: <span id=\"state\">{state}</span>\n  </div>\n\n  <div>\n    <button type=\"button\" on:click={setOnly}>Set Only (users)</button>\n    <button type=\"button\" on:click={setExcept}>Set Except (stats)</button>\n    <button type=\"button\" on:click={setReset}>Set Reset (orders)</button>\n    <button type=\"button\" on:click={() => (queryStringArrayFormat = 'brackets')}>Use Brackets Format</button>\n    <button type=\"button\" on:click={() => (queryStringArrayFormat = 'indices')}>Use Indices Format</button>\n    <button type=\"button\" on:click={enablePreserveScroll}>Enable Preserve Scroll</button>\n    <button type=\"button\" on:click={enablePreserveState}>Enable Preserve State</button>\n    <button type=\"button\" on:click={enablePreserveUrl}>Enable Preserve URL</button>\n    <button type=\"button\" on:click={enableReplace}>Enable Replace</button>\n    <button type=\"submit\">Submit</button>\n  </div>\n\n  {#if preserveScroll}\n    <Article />\n  {/if}\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Precognition/BeforeValidation.svelte",
    "content": "<script lang=\"ts\">\n  import { isEqual } from 'lodash-es'\n  import { Form } from '@inertiajs/svelte'\n\n  const handleBeforeValidation = (\n    newRequest: { data: Record<string, unknown> | null; touched: string[] },\n    oldRequest: { data: Record<string, unknown> | null; touched: string[] },\n  ) => {\n    const payloadIsCorrect =\n      isEqual(newRequest, { data: { name: 'block' }, touched: ['name'] }) &&\n      isEqual(oldRequest, { data: {}, touched: [] })\n\n    // Block validation if name is \"block\"\n    if (payloadIsCorrect && newRequest.data?.name === 'block') {\n      return false\n    }\n\n    return true\n  }\n</script>\n\n<div>\n  <h1>Precognition - onBefore</h1>\n\n  <Form\n    action=\"/precognition/default\"\n    method=\"post\"\n    let:errors\n    let:invalid\n    let:validate\n    let:validating\n    validationTimeout={100}\n  >\n    <div>\n      <label for=\"name\">Name:</label>\n      <input\n        id=\"name\"\n        name=\"name\"\n        on:change={() =>\n          validate('name', {\n            onBeforeValidation: handleBeforeValidation,\n          })}\n      />\n      {#if invalid('name')}\n        <p class=\"error\">{errors.name}</p>\n      {/if}\n    </div>\n\n    <div>\n      <label for=\"email\">Email:</label>\n      <input id=\"email\" name=\"email\" on:change={() => validate('email')} />\n      {#if invalid('email')}\n        <p class=\"error\">{errors.email}</p>\n      {/if}\n    </div>\n\n    {#if validating}\n      <p class=\"validating\">Validating...</p>\n    {/if}\n\n    <button type=\"submit\">Submit</button>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Precognition/Callbacks.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n\n  let successCalled = false\n  let errorCalled = false\n  let finishCalled = false\n</script>\n\n<div>\n  <h1>Form Precognition Callbacks</h1>\n\n  <h2>Callbacks Test</h2>\n  <Form action=\"/precognition/default\" method=\"post\" validationTimeout={100} let:validate let:validating let:touch>\n    <div>\n      <input name=\"name\" placeholder=\"Name\" on:blur={() => touch('name')} />\n    </div>\n\n    {#if validating}\n      <p>Validating...</p>\n    {/if}\n    {#if successCalled}\n      <p>onPrecognitionSuccess called!</p>\n    {/if}\n    {#if errorCalled}\n      <p>onValidationError called!</p>\n    {/if}\n    {#if finishCalled}\n      <p>onFinish called!</p>\n    {/if}\n\n    <button\n      type=\"button\"\n      on:click={() => {\n        successCalled = false\n        errorCalled = false\n        finishCalled = false\n        validate({\n          onPrecognitionSuccess: () => {\n            successCalled = true\n          },\n          onValidationError: () => {\n            errorCalled = true\n          },\n          onFinish: () => {\n            finishCalled = true\n          },\n        })\n      }}\n    >\n      Validate\n    </button>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Precognition/Cancel.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <h1>Precognition - Cancel Tests</h1>\n\n  <h2>Auto Cancel Test</h2>\n  <Form\n    action=\"/precognition/default?slow=1\"\n    method=\"post\"\n    validationTimeout={100}\n    let:invalid\n    let:errors\n    let:validate\n    let:validating\n  >\n    <div>\n      <input id=\"auto-cancel-name-input\" name=\"name\" placeholder=\"Name\" on:blur={() => validate('name')} />\n      {#if invalid('name')}\n        <p class=\"error\">\n          {errors.name}\n        </p>\n      {/if}\n    </div>\n\n    {#if validating}\n      <p class=\"validating\">Validating...</p>\n    {/if}\n\n    <button type=\"submit\">Submit</button>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Precognition/Default.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <h1>Form Precognition</h1>\n\n  <Form\n    action=\"/precognition/default\"\n    method=\"post\"\n    validationTimeout={100}\n    let:invalid\n    let:errors\n    let:validate\n    let:valid\n    let:validating\n  >\n    <div>\n      <input name=\"name\" placeholder=\"Name\" on:blur={() => validate('name')} />\n      {#if invalid('name')}\n        <p>{errors.name}</p>\n      {/if}\n      {#if valid('name')}\n        <p>Name is valid!</p>\n      {/if}\n    </div>\n\n    <div>\n      <input name=\"email\" placeholder=\"Email\" on:blur={() => validate('email')} />\n      {#if invalid('email')}\n        <p>{errors.email}</p>\n      {/if}\n      {#if valid('email')}\n        <p>Email is valid!</p>\n      {/if}\n    </div>\n\n    {#if validating}\n      <p>Validating...</p>\n    {/if}\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Precognition/DynamicArrayInputs.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n\n  let items: Array<{ name: string }> = []\n\n  function addItem() {\n    items = [...items, { name: '' }]\n  }\n</script>\n\n<div>\n  <button id=\"add-item\" on:click={addItem}>Add Item</button>\n\n  <Form\n    action=\"/precognition/dynamic-array-inputs\"\n    method=\"post\"\n    validationTimeout={100}\n    let:invalid\n    let:errors\n    let:validate\n    let:validating\n  >\n    {#each items as item, idx (idx)}\n      <div>\n        <input bind:value={item.name} name={`items.${idx}.name`} on:blur={() => validate(`items.${idx}.name`)} />\n        {#if invalid(`items.${idx}.name`)}<p id={`items.${idx}.name-error`}>{errors[`items.${idx}.name`]}</p>{/if}\n      </div>\n    {/each}\n\n    {#if validating}<p>Validating...</p>{/if}\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Precognition/ErrorSync.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <h1>Precognition Error Sync Test</h1>\n\n  <Form\n    action=\"/precognition/error-sync\"\n    method=\"post\"\n    validationTimeout={100}\n    let:invalid\n    let:errors\n    let:validate\n    let:validating\n  >\n    <div>\n      <input name=\"name\" placeholder=\"Name\" on:blur={() => validate('name')} />\n      {#if invalid('name')}\n        <p id=\"name-error\">{errors.name}</p>\n      {/if}\n    </div>\n\n    <div>\n      <input name=\"email\" placeholder=\"Email\" on:blur={() => validate('email')} />\n      {#if invalid('email')}\n        <p id=\"email-error\">{errors.email}</p>\n      {/if}\n    </div>\n\n    {#if validating}\n      <p id=\"validating\">Validating...</p>\n    {/if}\n\n    <button type=\"submit\" id=\"submit-btn\">Submit</button>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Precognition/Files.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n\n  let validateFilesEnabled = false\n</script>\n\n<div>\n  <h1>Form Precognition Files</h1>\n\n  <Form\n    action=\"/precognition/files\"\n    method=\"post\"\n    validationTimeout={100}\n    validateFiles={validateFilesEnabled}\n    let:invalid\n    let:errors\n    let:validate\n    let:valid\n    let:validating\n  >\n    <div>\n      <input name=\"name\" placeholder=\"Name\" on:blur={() => validate('name')} />\n      {#if invalid('name')}\n        <p>{errors.name}</p>\n      {/if}\n      {#if valid('name')}\n        <p>Name is valid!</p>\n      {/if}\n    </div>\n\n    <div>\n      <input type=\"file\" name=\"avatar\" id=\"avatar\" />\n      {#if invalid('avatar')}\n        <p>{errors.avatar}</p>\n      {/if}\n      {#if valid('avatar')}\n        <p>Avatar is valid!</p>\n      {/if}\n    </div>\n\n    {#if validating}\n      <p>Validating...</p>\n    {/if}\n\n    <button type=\"button\" on:click={() => (validateFilesEnabled = !validateFilesEnabled)}>\n      Toggle Validate Files ({validateFilesEnabled ? 'enabled' : 'disabled'})\n    </button>\n\n    <button type=\"button\" on:click={() => validate({ only: ['name', 'avatar'] })}>Validate Both</button>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Precognition/Headers.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <h1>Precognition - Custom Headers</h1>\n\n  <Form\n    action=\"/precognition/headers\"\n    method=\"post\"\n    headers={{ 'X-Custom-Header': 'custom-value' }}\n    validationTimeout={100}\n    let:invalid\n    let:errors\n    let:validate\n    let:validating\n  >\n    <div>\n      <input name=\"name\" placeholder=\"Name\" on:blur={() => validate('name')} />\n      {#if invalid('name')}\n        <p>\n          {errors.name}\n        </p>\n      {/if}\n    </div>\n\n    {#if validating}\n      <p>Validating...</p>\n    {/if}\n\n    <button type=\"submit\">Submit</button>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Precognition/Methods.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <h1>Form Precognition - Touch, Reset & Validate</h1>\n\n  <Form\n    action=\"/precognition/default\"\n    method=\"post\"\n    validationTimeout={100}\n    let:invalid\n    let:errors\n    let:validate\n    let:touch\n    let:touched\n    let:validating\n    let:reset\n  >\n    <div>\n      <input name=\"name\" placeholder=\"Name\" on:blur={() => touch('name')} />\n      {#if invalid('name')}\n        <p>{errors.name}</p>\n      {/if}\n    </div>\n\n    <div>\n      <input name=\"email\" placeholder=\"Email\" on:blur={() => touch('email')} />\n      {#if invalid('email')}\n        <p>{errors.email}</p>\n      {/if}\n    </div>\n\n    {#if validating}\n      <p>Validating...</p>\n    {/if}\n\n    <p id=\"name-touched\">{touched('name') ? 'Name is touched' : 'Name is not touched'}</p>\n    <p id=\"email-touched\">{touched('email') ? 'Email is touched' : 'Email is not touched'}</p>\n    <p id=\"any-touched\">{touched() ? 'Form has touched fields' : 'Form has no touched fields'}</p>\n\n    <button type=\"button\" on:click={() => validate()}>Validate All Touched</button>\n    <button type=\"button\" on:click={() => validate('name')}>Validate Name</button>\n    <button type=\"button\" on:click={() => validate({ only: ['name', 'email'] })}>Validate Name and Email</button>\n    <button type=\"button\" on:click={() => touch('name', 'email')}>Touch Name and Email</button>\n    <button\n      type=\"button\"\n      on:click={() => {\n        touch('name')\n        touch('name')\n      }}\n    >\n      Touch Name Twice\n    </button>\n    <button type=\"button\" on:click={() => reset()}>Reset All</button>\n    <button type=\"button\" on:click={() => reset('name')}>Reset Name</button>\n    <button type=\"button\" on:click={() => reset('name', 'email')}>Reset Name and Email</button>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Precognition/Transform.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <h1>Form Precognition Transform</h1>\n\n  <Form\n    action=\"/precognition/default\"\n    method=\"post\"\n    validationTimeout={100}\n    transform={(data) => ({ name: String(data.name || '').repeat(2) })}\n    let:invalid\n    let:errors\n    let:validate\n    let:valid\n    let:validating\n  >\n    <div>\n      <input name=\"name\" placeholder=\"Name\" on:blur={() => validate('name')} />\n      {#if invalid('name')}\n        <p>{errors.name}</p>\n      {/if}\n      {#if valid('name')}\n        <p>Name is valid!</p>\n      {/if}\n    </div>\n\n    {#if validating}\n      <p>Validating...</p>\n    {/if}\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Precognition/TransformKeys.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  const transformData = (data: Record<string, any>) => {\n    const document = data.document || {}\n    return document\n  }\n</script>\n\n<div>\n  <h1>Form Precognition Transform Keys</h1>\n\n  <Form\n    action=\"/precognition/transform-keys\"\n    method=\"post\"\n    validationTimeout={100}\n    transform={transformData}\n    let:invalid\n    let:errors\n    let:validate\n    let:valid\n    let:validating\n  >\n    <div>\n      <input\n        id=\"email-input\"\n        name=\"document[customer][email]\"\n        placeholder=\"Email\"\n        on:blur={() => validate('customer.email')}\n      />\n      {#if invalid('customer.email')}\n        <p>{errors['customer.email']}</p>\n      {/if}\n      {#if valid('customer.email')}\n        <p>Email is valid!</p>\n      {/if}\n    </div>\n\n    {#if validating}\n      <p>Validating...</p>\n    {/if}\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Precognition/WithAllErrors.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <h1>Form Precognition - All Errors</h1>\n\n  <Form\n    action=\"/precognition/with-all-errors\"\n    method=\"post\"\n    validationTimeout={100}\n    withAllErrors\n    let:invalid\n    let:errors\n    let:validate\n    let:valid\n    let:validating\n  >\n    <div>\n      <input name=\"name\" placeholder=\"Name\" on:blur={() => validate('name')} />\n      {#if invalid('name')}\n        <div>\n          {#if Array.isArray(errors.name)}\n            {#each errors.name as error, index (index)}\n              <p id=\"name-error-{index}\">{error}</p>\n            {/each}\n          {:else}\n            <p id=\"name-error-0\">{errors.name}</p>\n          {/if}\n        </div>\n      {/if}\n      {#if valid('name')}\n        <p>Name is valid!</p>\n      {/if}\n    </div>\n\n    <div>\n      <input name=\"email\" placeholder=\"Email\" on:blur={() => validate('email')} />\n      {#if invalid('email')}\n        <div>\n          {#if Array.isArray(errors.email)}\n            {#each errors.email as error, index (index)}\n              <p id=\"email-error-{index}\">{error}</p>\n            {/each}\n          {:else}\n            <p id=\"email-error-0\">{errors.email}</p>\n          {/if}\n        </div>\n      {/if}\n      {#if valid('email')}\n        <p>Email is valid!</p>\n      {/if}\n    </div>\n\n    {#if validating}\n      <p>Validating...</p>\n    {/if}\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Precognition/WithAllErrorsConfig.svelte",
    "content": "<script lang=\"ts\">\n  import { config, Form } from '@inertiajs/svelte'\n\n  // Set global config for withAllErrors (no prop on the Form component)\n  config.set('form.withAllErrors', true)\n</script>\n\n<div>\n  <h1>Form Precognition - All Errors via Config</h1>\n\n  <Form\n    action=\"/precognition/with-all-errors\"\n    method=\"post\"\n    validationTimeout={100}\n    let:invalid\n    let:errors\n    let:validate\n    let:valid\n    let:validating\n  >\n    <div>\n      <input name=\"name\" placeholder=\"Name\" on:blur={() => validate('name')} />\n      {#if invalid('name')}\n        <div>\n          {#if Array.isArray(errors.name)}\n            {#each errors.name as error, index (index)}\n              <p id=\"name-error-{index}\">{error}</p>\n            {/each}\n          {:else}\n            <p id=\"name-error-0\">{errors.name}</p>\n          {/if}\n        </div>\n      {/if}\n      {#if valid('name')}\n        <p>Name is valid!</p>\n      {/if}\n    </div>\n\n    <div>\n      <input name=\"email\" placeholder=\"Email\" on:blur={() => validate('email')} />\n      {#if invalid('email')}\n        <div>\n          {#if Array.isArray(errors.email)}\n            {#each errors.email as error, index (index)}\n              <p id=\"email-error-{index}\">{error}</p>\n            {/each}\n          {:else}\n            <p id=\"email-error-0\">{errors.email}</p>\n          {/if}\n        </div>\n      {/if}\n      {#if valid('email')}\n        <p>Email is valid!</p>\n      {/if}\n    </div>\n\n    {#if validating}\n      <p>Validating...</p>\n    {/if}\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Precognition/WithoutAllErrors.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <h1>Form Precognition - Array Errors</h1>\n\n  <Form\n    action=\"/precognition/with-all-errors\"\n    method=\"post\"\n    validationTimeout={100}\n    let:invalid\n    let:errors\n    let:validate\n    let:valid\n    let:validating\n  >\n    <div>\n      <input name=\"name\" placeholder=\"Name\" on:blur={() => validate('name')} />\n      {#if invalid('name')}\n        <p>{errors.name}</p>\n      {/if}\n      {#if valid('name')}\n        <p>Name is valid!</p>\n      {/if}\n    </div>\n\n    <div>\n      <input name=\"email\" placeholder=\"Email\" on:blur={() => validate('email')} />\n      {#if invalid('email')}\n        <p>{errors.email}</p>\n      {/if}\n      {#if valid('email')}\n        <p>Email is valid!</p>\n      {/if}\n    </div>\n\n    {#if validating}\n      <p>Validating...</p>\n    {/if}\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Progress.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n  import { onMount, onDestroy } from 'svelte'\n\n  let showProgress: boolean | undefined = undefined\n  let nprogressVisible = false\n  let nprogressAppearances = 0\n  let observer: MutationObserver | null = null\n\n  function disableProgress() {\n    showProgress = false\n  }\n\n  onMount(() => {\n    observer = new MutationObserver(() => {\n      const nprogressElement = document.querySelector('#nprogress') as HTMLElement | null\n      const nprogressIsCurrentlyVisible = nprogressElement && nprogressElement.style.display !== 'none'\n\n      if (nprogressIsCurrentlyVisible) {\n        if (!nprogressVisible) {\n          nprogressVisible = true\n          nprogressAppearances = nprogressAppearances + 1\n        }\n      } else {\n        nprogressVisible = false\n      }\n    })\n\n    observer.observe(document.body, { childList: true, subtree: true })\n  })\n\n  onDestroy(() => {\n    if (observer) {\n      observer.disconnect()\n    }\n  })\n</script>\n\n<Form action=\"/form-component/progress\" method=\"post\" {showProgress}>\n  <h1>Progress</h1>\n\n  <div>\n    Nprogress appearances: <span id=\"nprogress-appearances\">{nprogressAppearances}</span>\n  </div>\n\n  <div>\n    <button type=\"button\" on:click={disableProgress}>Disable Progress</button>\n    <button type=\"submit\">Submit</button>\n  </div>\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Ref.svelte",
    "content": "<script lang=\"ts\">\n  import type { FormComponentMethods } from '@inertiajs/core'\n  import { Form } from '@inertiajs/svelte'\n\n  // Svelte Form component ref exposes only methods via bind:this\n  let formRef: FormComponentMethods | null = null\n\n  function submitProgrammatically() {\n    formRef?.submit()\n  }\n\n  function resetNameField() {\n    formRef?.reset('name')\n  }\n\n  function resetForm() {\n    formRef?.reset()\n  }\n\n  function clearAllErrors() {\n    formRef?.clearErrors()\n  }\n\n  function setTestError() {\n    formRef?.setError('name', 'This is a test error')\n  }\n\n  function setCurrentAsDefaults() {\n    formRef?.defaults()\n  }\n\n  function callPrecognitionMethods() {\n    const validator = formRef?.validator()\n\n    if (validator && !formRef?.touched('company') && !formRef?.valid('company')) {\n      formRef?.validate({ only: ['company'] })\n    }\n  }\n</script>\n\n<div>\n  <h1>Form Ref Test</h1>\n\n  <Form bind:this={formRef} action=\"/dump/post\" method=\"post\" let:isDirty let:errors let:hasErrors>\n    <!-- State display for testing -->\n    <div>Form is {isDirty ? 'dirty' : 'clean'}</div>\n    {#if hasErrors}\n      <div>Form has errors</div>\n    {/if}\n    {#if errors.name}\n      <div id=\"error_name\">{errors.name}</div>\n    {/if}\n\n    <div>\n      <input type=\"text\" name=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n    </div>\n\n    <div>\n      <input type=\"email\" name=\"email\" placeholder=\"Email\" value=\"john@example.com\" />\n    </div>\n\n    <div>\n      <button type=\"submit\">Submit via Form</button>\n    </div>\n  </Form>\n\n  <div>\n    <button on:click={submitProgrammatically}> Submit Programmatically </button>\n    <button on:click={resetForm}> Reset Form </button>\n    <button on:click={resetNameField}> Reset Name Field </button>\n    <button on:click={clearAllErrors}> Clear Errors </button>\n    <button on:click={setTestError}> Set Test Error </button>\n    <button on:click={setCurrentAsDefaults}> Set Current as Defaults </button>\n    <button on:click={callPrecognitionMethods}> Call Precognition Methods </button>\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Reset.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  declare global {\n    interface Window {\n      resetForm: (...fields: string[]) => void\n    }\n  }\n</script>\n\n<script lang=\"ts\">\n  import type { FormComponentMethods } from '@inertiajs/core'\n  import { Form } from '@inertiajs/svelte'\n\n  let formRef: FormComponentMethods | null = null\n\n  // Expose reset function to window for testing\n  window.resetForm = (...fields: string[]) => {\n    formRef?.reset(...fields)\n  }\n\n  // Action to set defaultValue for disabled fields\n  function setDefaultValue(node: HTMLInputElement) {\n    node.defaultValue = node.value\n  }\n</script>\n\n<Form action=\"/dump/post\" method=\"post\" bind:this={formRef}>\n  <h1>Form Reset</h1>\n\n  <!-- Basic Text Inputs -->\n  <h2>Basic Text Inputs</h2>\n  <input type=\"text\" name=\"name\" id=\"name\" value=\"John Doe\" />\n  <input type=\"email\" name=\"email\" id=\"email\" value=\"john@example.com\" />\n\n  <!-- Select Elements -->\n  <h2>Select Elements</h2>\n  <select name=\"country\" id=\"country\">\n    <option value=\"us\">United States</option>\n    <option value=\"ca\">Canada</option>\n    <option value=\"uk\" selected>United Kingdom</option>\n  </select>\n  <select name=\"role\" id=\"role\">\n    <option value=\"\">Select a role</option>\n    <option value=\"user\">User</option>\n    <option value=\"admin\">Admin</option>\n    <option value=\"super\">Super</option>\n  </select>\n\n  <!-- Radio Buttons -->\n  <h2>Radio Buttons</h2>\n\n  <!-- Radio buttons with default checked -->\n  <div>\n    <label><input type=\"radio\" name=\"plan\" id=\"plan_free\" value=\"free\" /> Free</label>\n    <label><input type=\"radio\" name=\"plan\" id=\"plan_pro\" value=\"pro\" checked /> Pro</label>\n    <label><input type=\"radio\" name=\"plan\" id=\"plan_enterprise\" value=\"enterprise\" /> Enterprise</label>\n  </div>\n\n  <!-- Radio buttons without default -->\n  <div>\n    <label><input type=\"radio\" name=\"payment\" id=\"payment_card\" value=\"card\" /> Card</label>\n    <label><input type=\"radio\" name=\"payment\" id=\"payment_bank\" value=\"bank\" /> Bank</label>\n    <label><input type=\"radio\" name=\"payment\" id=\"payment_paypal\" value=\"paypal\" /> PayPal</label>\n  </div>\n\n  <!-- Radio buttons designed to test multiple defaults edge case -->\n  <div>\n    <label><input type=\"radio\" name=\"priority\" id=\"priority_low\" value=\"low\" checked /> Low</label>\n    <label><input type=\"radio\" name=\"priority\" id=\"priority_medium\" value=\"medium\" /> Medium</label>\n    <label><input type=\"radio\" name=\"priority\" id=\"priority_high\" value=\"high\" /> High</label>\n  </div>\n\n  <!-- Checkboxes -->\n  <h2>Checkboxes</h2>\n\n  <!-- Checkbox (single) with default checked -->\n  <div>\n    <input type=\"checkbox\" name=\"subscribe\" id=\"subscribe\" value=\"yes\" checked />\n    <label for=\"subscribe\">Subscribe to newsletter</label>\n  </div>\n\n  <!-- Checkbox (single) without default -->\n  <div>\n    <input type=\"checkbox\" name=\"terms\" id=\"terms\" value=\"accepted\" />\n    <label for=\"terms\">Accept terms</label>\n  </div>\n\n  <!-- Checkbox (multiple) with some checked -->\n  <div>\n    <label><input type=\"checkbox\" name=\"interests[]\" id=\"interests_sports\" value=\"sports\" checked /> Sports</label>\n    <label><input type=\"checkbox\" name=\"interests[]\" id=\"interests_music\" value=\"music\" /> Music</label>\n    <label><input type=\"checkbox\" name=\"interests[]\" id=\"interests_tech\" value=\"tech\" checked /> Tech</label>\n    <label><input type=\"checkbox\" name=\"interests[]\" id=\"interests_art\" value=\"art\" /> Art</label>\n  </div>\n\n  <!-- Multiple Select Elements -->\n  <h2>Multiple Select Elements</h2>\n  <select name=\"skills[]\" id=\"skills\" multiple>\n    <option value=\"vue\" selected>Vue</option>\n    <option value=\"react\">React</option>\n    <option value=\"angular\" selected>Angular</option>\n    <option value=\"svelte\">Svelte</option>\n  </select>\n  <select name=\"languages[]\" id=\"languages\" multiple>\n    <option value=\"javascript\">JavaScript</option>\n    <option value=\"typescript\">TypeScript</option>\n    <option value=\"python\">Python</option>\n    <option value=\"php\">PHP</option>\n  </select>\n  <select name=\"tools[]\" id=\"tools\" multiple>\n    <option value=\"vscode\" selected>VSCode</option>\n    <option value=\"webstorm\" selected>WebStorm</option>\n    <option value=\"sublime\" selected>Sublime</option>\n  </select>\n  <select name=\"editor\" id=\"editor\">\n    <option value=\"\">Select Editor</option>\n    <option value=\"vim\" selected>Vim</option>\n    <option value=\"emacs\">Emacs</option>\n    <option value=\"nano\">Nano</option>\n  </select>\n\n  <!-- File Inputs & Textareas -->\n  <h2>File Inputs & Textareas</h2>\n  <input type=\"file\" name=\"avatar\" id=\"avatar\" />\n  <input type=\"file\" name=\"documents[]\" id=\"documents\" multiple />\n  <textarea name=\"bio\" id=\"bio\" rows=\"3\">Default bio text here.</textarea>\n  <textarea name=\"notes\" id=\"notes\" rows=\"2\"></textarea>\n\n  <!-- HTML5 Input Types -->\n  <h2>HTML5 Input Types</h2>\n  <input type=\"hidden\" name=\"token\" id=\"token\" value=\"abc123\" />\n  <input type=\"number\" name=\"age\" id=\"age\" value=\"25\" />\n  <input type=\"number\" name=\"quantity\" id=\"quantity\" />\n  <input type=\"range\" name=\"volume\" id=\"volume\" min=\"0\" max=\"100\" value=\"50\" />\n  <input type=\"date\" name=\"birthdate\" id=\"birthdate\" value=\"1990-01-01\" />\n  <input type=\"time\" name=\"appointment\" id=\"appointment\" value=\"14:30\" />\n  <input type=\"color\" name=\"favorite_color\" id=\"favorite_color\" value=\"#ff0000\" />\n  <input type=\"url\" name=\"website\" id=\"website\" value=\"https://example.com\" />\n  <input type=\"tel\" name=\"phone\" id=\"phone\" value=\"+1234567890\" />\n  <input type=\"password\" name=\"password\" id=\"password\" value=\"secret123\" />\n\n  <!-- Complex Nested Fields -->\n  <h2>Complex Nested Fields</h2>\n  <input type=\"text\" name=\"user[address][street]\" id=\"nested_street\" value=\"123 Main St\" />\n  <input type=\"text\" name=\"user[address][city]\" id=\"nested_city\" value=\"New York\" />\n  <input type=\"text\" name=\"items[0][name]\" id=\"item_0_name\" value=\"Item A\" />\n  <input type=\"number\" name=\"items[0][quantity]\" id=\"item_0_quantity\" value=\"5\" />\n  <input type=\"text\" name=\"items[1][name]\" id=\"item_1_name\" value=\"Item B\" />\n  <input type=\"number\" name=\"items[1][quantity]\" id=\"item_1_quantity\" value=\"10\" />\n\n  <!-- Special Cases -->\n  <h2>Special Cases</h2>\n  <input type=\"text\" name=\"disabled_field\" id=\"disabled_field\" value=\"Ignore me\" disabled use:setDefaultValue />\n  <input type=\"button\" name=\"button_input\" value=\"Click me\" />\n  <input type=\"submit\" name=\"submit_input\" value=\"Submit Form\" />\n  <input type=\"reset\" name=\"reset_input\" value=\"Reset Form\" />\n  <button type=\"reset\" name=\"reset_button\">Reset Form</button>\n\n  <!-- Dotted & Array Notation -->\n  <h2>Dotted & Array Notation</h2>\n  <input type=\"text\" name=\"user.name\" id=\"user_name\" value=\"Default User\" />\n  <input type=\"text\" name=\"user.email\" id=\"user_email\" value=\"user@default.com\" />\n  <input type=\"text\" name=\"company.name\" id=\"company_name\" value=\"Default Corp\" />\n  <input type=\"text\" name=\"tags[]\" id=\"tag_0\" value=\"javascript\" />\n  <input type=\"text\" name=\"tags[]\" id=\"tag_1\" value=\"vue\" />\n  <input type=\"text\" name=\"tags[]\" id=\"tag_2\" value=\"inertia\" />\n\n  <!-- Numeric Values -->\n  <h2>Numeric Values</h2>\n  <div>\n    <label><input type=\"radio\" name=\"rating\" id=\"rating_1\" value=\"1\" checked /> 1 Star</label>\n    <label><input type=\"radio\" name=\"rating\" id=\"rating_2\" value=\"2\" /> 2 Stars</label>\n    <label><input type=\"radio\" name=\"rating\" id=\"rating_3\" value=\"3\" /> 3 Stars</label>\n  </div>\n  <div>\n    <label><input type=\"checkbox\" name=\"years[]\" id=\"years_2020\" value=\"2020\" checked /> 2020</label>\n    <label><input type=\"checkbox\" name=\"years[]\" id=\"years_2021\" value=\"2021\" /> 2021</label>\n    <label><input type=\"checkbox\" name=\"years[]\" id=\"years_2022\" value=\"2022\" checked /> 2022</label>\n  </div>\n  <select name=\"version\" id=\"version\">\n    <option value=\"1\" selected>Version 1</option>\n    <option value=\"2\">Version 2</option>\n    <option value=\"3\">Version 3</option>\n  </select>\n  <select name=\"ports[]\" id=\"ports\" multiple>\n    <option value=\"80\" selected>Port 80</option>\n    <option value=\"443\" selected>Port 443</option>\n    <option value=\"8080\">Port 8080</option>\n  </select>\n\n  <!-- Submit button -->\n  <h2>Submit</h2>\n  <button type=\"submit\">Submit</button>\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/ResetAttributes/ResetOnError.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<Form method=\"post\" action=\"/form-component/reset-on-error\" resetOnError let:errors>\n  <div>\n    <label for=\"name\">Name</label>\n    <input type=\"text\" name=\"name\" id=\"name\" value=\"John Doe\" />\n    <p id=\"error_name\">{errors.name || ''}</p>\n  </div>\n\n  <div>\n    <label for=\"email\">Email</label>\n    <input type=\"email\" name=\"email\" id=\"email\" value=\"john@doe.biz\" />\n    <p id=\"error_email\">{errors.email || ''}</p>\n  </div>\n\n  <button type=\"submit\">Submit</button>\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/ResetAttributes/ResetOnErrorFields.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<Form method=\"post\" action=\"/form-component/reset-on-error-fields\" resetOnError={['name']} let:errors>\n  <div>\n    <label for=\"name\">Name</label>\n    <input type=\"text\" name=\"name\" id=\"name\" value=\"John Doe\" />\n    <p id=\"error_name\">{errors.name || ''}</p>\n  </div>\n\n  <div>\n    <label for=\"email\">Email</label>\n    <input type=\"email\" name=\"email\" id=\"email\" value=\"john@doe.biz\" />\n    <p id=\"error_email\">{errors.email || ''}</p>\n  </div>\n\n  <button type=\"submit\">Submit</button>\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccess.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<Form method=\"post\" action=\"/form-component/reset-on-success\" resetOnSuccess let:errors>\n  <div>\n    <label for=\"name\">Name</label>\n    <input type=\"text\" name=\"name\" id=\"name\" value=\"John Doe\" />\n    <p id=\"error_name\">{errors.name || ''}</p>\n  </div>\n\n  <div>\n    <label for=\"email\">Email</label>\n    <input type=\"email\" name=\"email\" id=\"email\" value=\"john@doe.biz\" />\n    <p id=\"error_email\">{errors.email || ''}</p>\n  </div>\n\n  <button type=\"submit\">Submit</button>\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccessFields.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<Form method=\"post\" action=\"/form-component/reset-on-success-fields\" resetOnSuccess={['name']} let:errors>\n  <div>\n    <label for=\"name\">Name</label>\n    <input type=\"text\" name=\"name\" id=\"name\" value=\"John Doe\" />\n    <p id=\"error_name\">{errors.name || ''}</p>\n  </div>\n\n  <div>\n    <label for=\"email\">Email</label>\n    <input type=\"email\" name=\"email\" id=\"email\" value=\"john@doe.biz\" />\n    <p id=\"error_email\">{errors.email || ''}</p>\n  </div>\n\n  <button type=\"submit\">Submit</button>\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/SetDefaultsOnSuccess.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<Form method=\"post\" action=\"/form-component/set-defaults-on-success\" setDefaultsOnSuccess let:isDirty let:errors>\n  <p id=\"dirty-status\">{isDirty ? 'Form is dirty' : 'Form is clean'}</p>\n\n  <div>\n    <label for=\"name\">Name</label>\n    <input type=\"text\" name=\"name\" id=\"name\" value=\"John Doe\" />\n    <p id=\"error_name\">{errors.name || ''}</p>\n  </div>\n\n  <div>\n    <label for=\"email\">Email</label>\n    <input type=\"email\" name=\"email\" id=\"email\" value=\"john@doe.biz\" />\n    <p id=\"error_email\">{errors.email || ''}</p>\n  </div>\n\n  <button type=\"submit\">Submit</button>\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/SubmitButton.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<Form action=\"/dump/post\" method=\"post\">\n  <h1>Submit Button Test</h1>\n\n  <input type=\"text\" name=\"name\" id=\"name\" value=\"John Doe\" />\n\n  <button type=\"submit\" name=\"action\" value=\"save\" id=\"save-button\">Save</button>\n  <button type=\"submit\" name=\"action\" value=\"draft\" id=\"draft-button\">Save as Draft</button>\n  <button type=\"submit\" id=\"no-name-button\">Submit Without Name</button>\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/SubmitComplete/Defaults.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <h1>OnSubmitComplete Defaults Test</h1>\n\n  <Form method=\"post\" let:errors let:isDirty onSubmitComplete={(props) => props.defaults()}>\n    <div>\n      <p id=\"dirty-status\">{isDirty ? 'Form is dirty' : 'Form is clean'}</p>\n    </div>\n\n    <div>\n      <input type=\"text\" name=\"name\" id=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n      {#if errors.name}\n        <p id=\"error_name\">{errors.name}</p>\n      {/if}\n    </div>\n\n    <div>\n      <input type=\"email\" name=\"email\" id=\"email\" placeholder=\"Email\" value=\"john@doe.biz\" />\n      {#if errors.email}\n        <p id=\"error_email\">{errors.email}</p>\n      {/if}\n    </div>\n\n    <div>\n      <button type=\"submit\">Submit</button>\n    </div>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/SubmitComplete/Redirect.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <h1>Form Empty Action Test</h1>\n\n  <Form method=\"post\" let:errors onSubmitComplete={(props) => props.reset('name')}>\n    <div>\n      <input type=\"text\" name=\"name\" id=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n      {#if errors.name}\n        <p id=\"error_name\">{errors.name}</p>\n      {/if}\n    </div>\n\n    <div>\n      <button type=\"submit\">Submit</button>\n    </div>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/SubmitComplete/Reset.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <h1>OnSubmitComplete Reset Test</h1>\n\n  <Form method=\"post\" let:errors onSubmitComplete={(props) => props.reset('name')}>\n    <div>\n      <input type=\"text\" name=\"name\" id=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n      {#if errors.name}\n        <p id=\"error_name\">{errors.name}</p>\n      {/if}\n    </div>\n\n    <div>\n      <input type=\"email\" name=\"email\" id=\"email\" placeholder=\"Email\" value=\"john@doe.biz\" />\n      {#if errors.email}\n        <p id=\"error_email\">{errors.email}</p>\n      {/if}\n    </div>\n\n    <div>\n      <button type=\"submit\">Submit</button>\n    </div>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Transform.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n  import type { FormDataConvertible } from '@inertiajs/core'\n\n  let transformType = 'none'\n\n  const getTransform = (type: string) => {\n    switch (type) {\n      case 'uppercase':\n        return (data: Record<string, FormDataConvertible>) => ({\n          ...data,\n          name: typeof data.name === 'string' ? data.name.toUpperCase() : data.name,\n        })\n      case 'format':\n        return (data: Record<string, FormDataConvertible>) => ({\n          ...data,\n          fullName: `${data.firstName} ${data.lastName}`,\n        })\n      default:\n        return (data: Record<string, FormDataConvertible>) => data\n    }\n  }\n\n  $: transform = getTransform(transformType)\n</script>\n\n<div>\n  <h1>Transform Function</h1>\n\n  <div>\n    <button on:click={() => (transformType = 'none')}>None</button>\n    <button on:click={() => (transformType = 'uppercase')}>Uppercase</button>\n    <button on:click={() => (transformType = 'format')}>Format</button>\n  </div>\n\n  <div>Current transform: {transformType}</div>\n\n  <Form action=\"/dump/post\" method=\"post\" {transform}>\n    <div>\n      <input type=\"text\" name=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n    </div>\n\n    <div>\n      <input type=\"text\" name=\"firstName\" placeholder=\"First Name\" value=\"John\" />\n    </div>\n\n    <div>\n      <input type=\"text\" name=\"lastName\" placeholder=\"Last Name\" value=\"Doe\" />\n    </div>\n\n    <div>\n      <button type=\"submit\"> Submit with Transform </button>\n    </div>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/UppercaseMethod.svelte",
    "content": "<script>\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <h1>Uppercase Method Test</h1>\n\n  <!-- Test with uppercase POST -->\n  <Form action=\"/dump/post\" method=\"POST\">\n    <div>\n      <input type=\"text\" name=\"name\" placeholder=\"Name\" value=\"Test POST\" />\n    </div>\n    <button type=\"submit\">Submit POST</button>\n  </Form>\n\n  <!-- Test with uppercase GET -->\n  <Form action=\"/dump/get\" method=\"GET\">\n    <div>\n      <input type=\"text\" name=\"query\" placeholder=\"Query\" value=\"Test GET\" />\n    </div>\n    <button type=\"submit\">Submit GET</button>\n  </Form>\n\n  <!-- Test with uppercase PUT -->\n  <Form action=\"/dump/put\" method=\"PUT\">\n    <div>\n      <input type=\"text\" name=\"data\" placeholder=\"Data\" value=\"Test PUT\" />\n    </div>\n    <button type=\"submit\">Submit PUT</button>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/ViewTransition.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n</script>\n\n<Form\n  action=\"/form-component/view-transition\"\n  method=\"post\"\n  options={{\n    viewTransition: (viewTransition) => {\n      viewTransition.ready.then(() => console.log('ready'))\n      viewTransition.updateCallbackDone.then(() => console.log('updateCallbackDone'))\n      viewTransition.finished.then(() => console.log('finished'))\n    },\n  }}\n>\n  <button type=\"submit\">Submit with View Transition</button>\n</Form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormComponent/Wayfinder.svelte",
    "content": "<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n\n  const wayfinderUrl = (): {\n    url: string\n    method: 'post'\n  } => ({\n    url: '/dump/post',\n    method: 'post',\n  })\n</script>\n\n<div>\n  <h1>Wayfinder Example</h1>\n\n  <Form action={wayfinderUrl()}>\n    <div>\n      <input type=\"text\" name=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n    </div>\n\n    <div>\n      <input type=\"checkbox\" name=\"active\" value=\"true\" checked />\n      <label for=\"active\">Active</label>\n    </div>\n\n    <div>\n      <button type=\"submit\">Submit</button>\n    </div>\n  </Form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Data.svelte",
    "content": "<script lang=\"ts\">\n  import { page, useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    name: 'foo',\n    handle: 'example',\n    remember: false,\n  })\n\n  const submit = () => {\n    $form.post($page.url)\n  }\n\n  const submitAndReset = () => {\n    $form.post('/form-helper/data/redirect-back', {\n      onSuccess: () => $form.reset(),\n    })\n  }\n\n  const resetAll = () => {\n    $form.reset()\n  }\n\n  const resetOne = () => {\n    $form.reset('handle')\n  }\n\n  const reassign = () => {\n    $form.defaults()\n  }\n\n  const reassignObject = () => {\n    $form.defaults({\n      handle: 'updated handle',\n      remember: true,\n    })\n  }\n\n  const reassignSingle = () => {\n    $form.defaults('name', 'single value')\n  }\n</script>\n\n<div>\n  <label>\n    Full Name\n    <input type=\"text\" id=\"name\" name=\"name\" bind:value={$form.name} />\n  </label>\n  {#if $form.errors.name}\n    <span class=\"name_error\">{$form.errors.name}</span>\n  {/if}\n  <label>\n    Handle\n    <input type=\"text\" id=\"handle\" name=\"handle\" bind:value={$form.handle} />\n  </label>\n  {#if $form.errors.handle}\n    <span class=\"handle_error\">{$form.errors.handle}</span>\n  {/if}\n  <label>\n    Remember Me\n    <input type=\"checkbox\" id=\"remember\" name=\"remember\" bind:checked={$form.remember} />\n  </label>\n  {#if $form.errors.remember}\n    <span class=\"remember_error\">{$form.errors.remember}</span>\n  {/if}\n\n  <button on:click={submit} class=\"submit\">Submit form</button>\n  <button on:click={submitAndReset} class=\"submit\">Submit form and reset</button>\n\n  <button on:click={resetAll} class=\"reset\">Reset all data</button>\n  <button on:click={resetOne} class=\"reset-one\">Reset one field</button>\n\n  <button on:click={reassign} class=\"reassign\">Reassign current as defaults</button>\n  <button on:click={reassignObject} class=\"reassign-object\">Reassign default values</button>\n  <button on:click={reassignSingle} class=\"reassign-single\">Reassign single default</button>\n\n  <span class=\"errors-status\">Form has {$form.hasErrors ? '' : 'no '}errors</span>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Dirty.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    name: 'foo',\n    foo: [] as string[],\n  })\n\n  const submit = () => {\n    $form.post('')\n  }\n\n  const defaults = () => {\n    $form.defaults()\n  }\n\n  const pushValue = () => {\n    $form.foo.push('bar')\n  }\n\n  const dataAndDefaults = () => {\n    pushValue()\n    defaults()\n  }\n\n  const submitAndSetDefaults = () => {\n    $form.post('/form-helper/dirty/redirect-back', {\n      onSuccess: () => $form.defaults(),\n    })\n  }\n\n  const submitAndSetCustomDefaults = () => {\n    $form.post('/form-helper/dirty/redirect-back', {\n      onSuccess: () => $form.defaults({ name: 'Custom Default', foo: [] }),\n    })\n  }\n</script>\n\n<div>\n  <div>\n    Form is {#if $form.isDirty}dirty{:else}clean{/if}\n  </div>\n  <label>\n    Full Name\n    <input type=\"text\" id=\"name\" name=\"name\" bind:value={$form.name} />\n  </label>\n\n  <button on:click={submit} class=\"submit\">Submit form</button>\n  <button on:click={defaults} class=\"defaults\">Defaults</button>\n  <button on:click={dataAndDefaults} class=\"data-and-defaults\">Data and Defaults</button>\n  <button on:click={pushValue} class=\"push\">Push value</button>\n\n  <button on:click={submitAndSetDefaults} class=\"submit-and-set-defaults\"> Submit and setDefaults </button>\n\n  <button on:click={submitAndSetCustomDefaults} class=\"submit-and-set-custom-defaults\">\n    Submit and setDefaults custom\n  </button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/EmptyForm.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  interface FormData {\n    name: string\n    email: string\n  }\n\n  const form = useForm<FormData>()\n\n  const submit = () => {\n    $form.transform(() => ({\n      name: 'John Doe',\n      email: 'john@example.com',\n    }))\n    $form.post('/dump/post')\n  }\n</script>\n\n<div>\n  <button on:click={submit}>Submit</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Errors.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    name: 'foo',\n    handle: 'example',\n    remember: false,\n  })\n\n  const submit = () => {\n    $form.post('/form-helper/errors')\n  }\n\n  const clearErrors = () => {\n    $form.clearErrors()\n  }\n\n  const clearError = () => {\n    $form.clearErrors('handle')\n  }\n\n  const setErrors = () => {\n    $form.setError({\n      name: 'Manually set Name error',\n      handle: 'Manually set Handle error',\n    })\n  }\n\n  const setError = () => {\n    $form.setError('handle', 'Manually set Handle error')\n  }\n\n  const resetAndClearErrors = () => {\n    $form.resetAndClearErrors()\n  }\n\n  const resetHandle = () => {\n    $form.resetAndClearErrors('handle')\n  }\n</script>\n\n<div>\n  <label>\n    Full Name\n    <input type=\"text\" id=\"name\" name=\"name\" bind:value={$form.name} />\n  </label>\n  {#if $form.errors.name}\n    <span class=\"name_error\">{$form.errors.name}</span>\n  {/if}\n  <label>\n    Handle\n    <input type=\"text\" id=\"handle\" name=\"handle\" bind:value={$form.handle} />\n  </label>\n  {#if $form.errors.handle}\n    <span class=\"handle_error\">{$form.errors.handle}</span>\n  {/if}\n  <label>\n    Remember Me\n    <input type=\"checkbox\" id=\"remember\" name=\"remember\" bind:checked={$form.remember} />\n  </label>\n  {#if $form.errors.remember}\n    <span class=\"remember_error\">{$form.errors.remember}</span>\n  {/if}\n\n  <button on:click={submit} class=\"submit\">Submit form</button>\n\n  <button on:click={clearErrors} class=\"clear\">Clear all errors</button>\n  <button on:click={clearError} class=\"clear-one\">Clear one error</button>\n  <button on:click={setErrors} class=\"set\">Set errors</button>\n  <button on:click={setError} class=\"set-one\">Set one error</button>\n  <button on:click={resetAndClearErrors} class=\"reset-all\">Reset all</button>\n  <button on:click={resetHandle} class=\"reset-handle\">Reset handle</button>\n\n  <span class=\"errors-status\">Form has {$form.hasErrors ? '' : 'no '}errors</span>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/ErrorsClearOnResubmit.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    name: '',\n    handle: '',\n  })\n\n  const submit = () => {\n    $form.post('/form-helper/errors/clear-on-resubmit')\n  }\n</script>\n\n<div>\n  <label>\n    Name\n    <input type=\"text\" id=\"name\" name=\"name\" bind:value={$form.name} />\n  </label>\n  {#if $form.errors.name}\n    <span id=\"name-error\">{$form.errors.name}</span>\n  {/if}\n\n  <label>\n    Handle\n    <input type=\"text\" id=\"handle\" name=\"handle\" bind:value={$form.handle} />\n  </label>\n  {#if $form.errors.handle}\n    <span id=\"handle-error\">{$form.errors.handle}</span>\n  {/if}\n\n  <button on:click={submit} id=\"submit\">Submit</button>\n\n  <span class=\"errors-status\">Form has {$form.hasErrors ? '' : 'no '}errors</span>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Events.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  declare global {\n    interface Window {\n      events: string[]\n      data: Array<{ type: string; data: unknown; event: string | null }>\n    }\n  }\n</script>\n\n<script lang=\"ts\">\n  import { page, useForm } from '@inertiajs/svelte'\n  import type { ActiveVisit, Page, Progress, Errors } from '@inertiajs/core'\n  import type { CancelTokenSource } from 'axios'\n\n  window.events = []\n  window.data = []\n\n  const form = useForm({\n    name: 'foo',\n    remember: false,\n  })\n\n  const pushEvent = (message: string) => {\n    window.events.push(message)\n  }\n\n  const pushData = (event: string | null, type: string, data: unknown) => {\n    window.data.push({\n      type,\n      data,\n      event,\n    })\n  }\n\n  pushData(null, 'processing', $form.processing)\n  pushData(null, 'progress', $form.progress)\n  pushData(null, 'errors', $form.errors)\n\n  const callbacks = (overrides = {}) => {\n    const defaults = {\n      onBefore: () => pushEvent('onBefore'),\n      onCancelToken: () => pushEvent('onCancelToken'),\n      onStart: () => pushEvent('onStart'),\n      onProgress: () => pushEvent('onProgress'),\n      onFinish: () => pushEvent('onFinish'),\n      onCancel: () => pushEvent('onCancel'),\n      onSuccess: () => pushEvent('onSuccess'),\n      onError: () => pushEvent('onError'),\n    }\n\n    return {\n      ...defaults,\n      ...overrides,\n    }\n  }\n\n  const submit = () => {\n    $form.post($page.url)\n  }\n\n  const successfulRequest = () => {\n    $form.post($page.url, {\n      ...callbacks(),\n    })\n  }\n\n  const onSuccessResetErrors = () => {\n    $form.post('/form-helper/events/errors', {\n      onError: () => {\n        pushEvent('onError')\n\n        $form.post('/form-helper/events', {\n          ...callbacks({\n            onStart: () => {\n              pushEvent('onStart')\n              pushData('onStart', 'errors', $form.errors)\n            },\n            onSuccess: () => {\n              pushEvent('onSuccess')\n              pushData('onSuccess', 'errors', $form.errors)\n            },\n            onFinish: () => {\n              pushEvent('onFinish')\n              pushData('onFinish', 'errors', $form.errors)\n            },\n          }),\n        })\n      },\n    })\n  }\n\n  const errorsSetOnError = () => {\n    $form.post('/form-helper/events/errors', {\n      ...callbacks({\n        onStart: () => {\n          pushEvent('onStart')\n          pushData('onStart', 'errors', $form.errors)\n        },\n        onError: () => {\n          pushEvent('onError')\n          pushData('onError', 'errors', $form.errors)\n        },\n        onFinish: () => {\n          pushEvent('onFinish')\n          pushData('onFinish', 'errors', $form.errors)\n        },\n      }),\n    })\n  }\n\n  const onBeforeVisit = () => {\n    $form.post('/sleep', {\n      ...callbacks({\n        onBefore: (visit: ActiveVisit) => {\n          pushEvent('onBefore')\n          pushData('onBefore', 'visit', visit)\n        },\n      }),\n    })\n  }\n\n  const onBeforeVisitCancelled = () => {\n    $form.post('/sleep', {\n      ...callbacks({\n        onBefore: () => {\n          pushEvent('onBefore')\n          return false\n        },\n      }),\n    })\n  }\n\n  const onStartVisit = () => {\n    $form.post('/form-helper/events', {\n      ...callbacks({\n        onStart: (visit: ActiveVisit) => {\n          pushEvent('onStart')\n          pushData('onStart', 'visit', visit)\n        },\n      }),\n    })\n  }\n\n  const onProgressVisit = () => {\n    $form\n      .transform((data) => ({\n        ...data,\n        file: new File(['foobar'], 'example.bin'),\n      }))\n      .post('/dump/post', {\n        ...callbacks({\n          onProgress: (event: Progress) => {\n            pushEvent('onProgress')\n            pushData('onProgress', 'progressEvent', event)\n          },\n        }),\n      })\n  }\n\n  const cancelledVisit = () => {\n    $form.post('/sleep', {\n      ...callbacks({\n        onCancelToken: (token: CancelTokenSource) => {\n          pushEvent('onCancelToken')\n\n          setTimeout(() => {\n            pushEvent('CANCELLING!')\n            token.cancel()\n          }, 10)\n        },\n      }),\n    })\n  }\n\n  const onSuccessVisit = () => {\n    $form.post('/dump/post', {\n      ...callbacks({\n        onSuccess: (page: Page) => {\n          pushEvent('onSuccess')\n          pushData('onSuccess', 'page', page)\n        },\n      }),\n    })\n  }\n\n  const onSuccessPromiseVisit = () => {\n    $form.post('/dump/post', {\n      ...callbacks({\n        onSuccess: () => {\n          pushEvent('onSuccess')\n\n          setTimeout(() => pushEvent('onFinish should have been fired by now if Promise functionality did not work'), 5)\n          return new Promise((resolve) => setTimeout(resolve, 20))\n        },\n      }),\n    })\n  }\n\n  const onSuccessResetValue = () => {\n    $form.post($page.url, {\n      ...callbacks({\n        onSuccess: () => {\n          $form.reset()\n        },\n      }),\n    })\n  }\n\n  const onErrorVisit = () => {\n    $form.post('/form-helper/events/errors', {\n      ...callbacks({\n        onError: (errors: Errors) => {\n          pushEvent('onError')\n          pushData('onError', 'errors', errors)\n        },\n      }),\n    })\n  }\n\n  const onErrorPromiseVisit = () => {\n    $form.post('/form-helper/events/errors', {\n      ...callbacks({\n        onError: () => {\n          pushEvent('onError')\n\n          setTimeout(() => pushEvent('onFinish should have been fired by now if Promise functionality did not work'), 5)\n          return new Promise((resolve) => setTimeout(resolve, 20))\n        },\n      }),\n    })\n  }\n\n  const onSuccessProcessing = () => {\n    $form.post($page.url, {\n      ...callbacks({\n        onBefore: () => {\n          pushEvent('onBefore')\n          pushData('onBefore', 'processing', $form.processing)\n        },\n        onCancelToken: () => {\n          pushEvent('onCancelToken')\n          pushData('onCancelToken', 'processing', $form.processing)\n        },\n        onStart: () => {\n          pushEvent('onStart')\n          pushData('onStart', 'processing', $form.processing)\n        },\n        onSuccess: () => {\n          pushEvent('onSuccess')\n          pushData('onSuccess', 'processing', $form.processing)\n        },\n        onFinish: () => {\n          pushEvent('onFinish')\n          pushData('onFinish', 'processing', $form.processing)\n        },\n      }),\n    })\n  }\n\n  const onErrorProcessing = () => {\n    $form.post('/form-helper/events/errors', {\n      ...callbacks({\n        onBefore: () => {\n          pushEvent('onBefore')\n          pushData('onBefore', 'processing', $form.processing)\n        },\n        onCancelToken: () => {\n          pushEvent('onCancelToken')\n          pushData('onCancelToken', 'processing', $form.processing)\n        },\n        onStart: () => {\n          pushEvent('onStart')\n          pushData('onStart', 'processing', $form.processing)\n        },\n        onError: () => {\n          pushEvent('onError')\n          pushData('onError', 'processing', $form.processing)\n        },\n        onFinish: () => {\n          pushEvent('onFinish')\n          pushData('onFinish', 'processing', $form.processing)\n        },\n      }),\n    })\n  }\n\n  const onSuccessProgress = () => {\n    $form\n      .transform((data) => ({\n        ...data,\n        file: new File(['foobar'], 'example.bin'),\n      }))\n      .post('/sleep', {\n        ...callbacks({\n          onBefore: () => {\n            pushEvent('onBefore')\n            pushData('onBefore', 'progress', $form.progress)\n          },\n          onCancelToken: () => {\n            pushEvent('onCancelToken')\n            pushData('onCancelToken', 'progress', $form.progress)\n          },\n          onStart: () => {\n            pushEvent('onStart')\n            pushData('onStart', 'progress', $form.progress)\n          },\n          onProgress: () => {\n            pushEvent('onProgress')\n            pushData('onProgress', 'progress', $form.progress)\n          },\n          onSuccess: () => {\n            pushEvent('onSuccess')\n            pushData('onSuccess', 'progress', $form.progress)\n          },\n          onFinish: () => {\n            pushEvent('onFinish')\n            pushData('onFinish', 'progress', $form.progress)\n          },\n        }),\n      })\n  }\n\n  const onErrorProgress = () => {\n    $form\n      .transform((data) => ({\n        ...data,\n        file: new File(['foobar'], 'example.bin'),\n      }))\n      .post('/form-helper/events/errors', {\n        ...callbacks({\n          onBefore: () => {\n            pushEvent('onBefore')\n            pushData('onBefore', 'progress', $form.progress)\n          },\n          onCancelToken: () => {\n            pushEvent('onCancelToken')\n            pushData('onCancelToken', 'progress', $form.progress)\n          },\n          onStart: () => {\n            pushEvent('onStart')\n            pushData('onStart', 'progress', $form.progress)\n          },\n          onProgress: () => {\n            pushEvent('onProgress')\n            pushData('onProgress', 'progress', $form.progress)\n          },\n          onError: () => {\n            pushEvent('onError')\n            pushData('onError', 'progress', $form.progress)\n          },\n          onFinish: () => {\n            pushEvent('onFinish')\n            pushData('onFinish', 'progress', $form.progress)\n          },\n        }),\n      })\n  }\n\n  const progressNoFiles = () => {\n    $form.post($page.url, {\n      ...callbacks({\n        onBefore: () => {\n          pushEvent('onBefore')\n          pushData('onBefore', 'progress', $form.progress)\n        },\n        onCancelToken: () => {\n          pushEvent('onCancelToken')\n          pushData('onCancelToken', 'progress', $form.progress)\n        },\n        onStart: () => {\n          pushEvent('onStart')\n          pushData('onStart', 'progress', $form.progress)\n        },\n        onProgress: () => {\n          pushEvent('onProgress')\n          pushData('onProgress', 'progress', $form.progress)\n        },\n        onSuccess: () => {\n          pushEvent('onSuccess')\n          pushData('onSuccess', 'progress', $form.progress)\n        },\n        onFinish: () => {\n          pushEvent('onFinish')\n          pushData('onFinish', 'progress', $form.progress)\n        },\n      }),\n    })\n  }\n</script>\n\n<div>\n  <button on:click|preventDefault={submit} class=\"submit\">Submit form</button>\n\n  <button on:click|preventDefault={successfulRequest} class=\"successful-request\">Successful request</button>\n  <button on:click|preventDefault={cancelledVisit} class=\"cancel\">Cancellable Visit</button>\n\n  <button on:click|preventDefault={onBeforeVisit} class=\"before\">onBefore</button>\n  <button on:click|preventDefault={onBeforeVisitCancelled} class=\"before-cancel\">onBefore cancellation</button>\n  <button on:click|preventDefault={onStartVisit} class=\"start\">onStart</button>\n  <button on:click|preventDefault={onProgressVisit} class=\"progress\">onProgress</button>\n\n  <button on:click|preventDefault={onSuccessVisit} class=\"success\">onSuccess</button>\n  <button on:click|preventDefault={onSuccessProgress} class=\"success-progress\">onSuccess progress property</button>\n  <button on:click|preventDefault={onSuccessProcessing} class=\"success-processing\">onSuccess resets processing</button>\n  <button on:click|preventDefault={onSuccessResetErrors} class=\"success-reset-errors\">onSuccess resets errors</button>\n  <button on:click|preventDefault={onSuccessPromiseVisit} class=\"success-promise\">onSuccess promise</button>\n  <button on:click|preventDefault={onSuccessResetValue} class=\"success-reset-value\">onSuccess resets value</button>\n\n  <button on:click|preventDefault={onErrorVisit} class=\"error\">onError</button>\n  <button on:click|preventDefault={onErrorProgress} class=\"error-progress\">onError progress property</button>\n  <button on:click|preventDefault={onErrorProcessing} class=\"error-processing\">onError resets processing</button>\n  <button on:click|preventDefault={errorsSetOnError} class=\"errors-set-on-error\">Errors set on error</button>\n  <button on:click|preventDefault={onErrorPromiseVisit} class=\"error-promise\">onError promise</button>\n\n  <button on:click|preventDefault={progressNoFiles} class=\"no-progress\">progress no files</button>\n\n  <span class=\"success-status\">Form was {$form.wasSuccessful ? '' : 'not '}successful</span>\n  <span class=\"recently-status\">Form was {$form.recentlySuccessful ? '' : 'not '}recently successful</span>\n\n  <input type=\"text\" class=\"name-input\" bind:value={$form.name} />\n  <input type=\"checkbox\" class=\"remember-input\" bind:checked={$form.remember} />\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Methods.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    name: 'foo',\n    remember: false,\n  })\n\n  const postForm = () => {\n    $form.post('/dump/post')\n  }\n\n  const putForm = () => {\n    $form.put('/dump/put')\n  }\n\n  const patchForm = () => {\n    $form.patch('/dump/patch')\n  }\n\n  const deleteForm = () => {\n    $form.delete('/dump/delete')\n  }\n\n  const submitForm = () => {\n    $form.submit('post', '/dump/post')\n  }\n\n  const submitFormObject = () => {\n    $form.submit({\n      method: 'post',\n      url: '/dump/post',\n    })\n  }\n</script>\n\n<div>\n  <label>\n    Full Name\n    <input type=\"text\" id=\"name\" name=\"name\" bind:value={$form.name} />\n  </label>\n  <label>\n    Remember Me\n    <input type=\"checkbox\" id=\"remember\" name=\"remember\" bind:checked={$form.remember} />\n  </label>\n\n  <button on:click={postForm} class=\"post\">POST form</button>\n  <button on:click={putForm} class=\"put\">PUT form</button>\n  <button on:click={patchForm} class=\"patch\">PATCH form</button>\n  <button on:click={deleteForm} class=\"delete\">DELETE form</button>\n  <button on:click={submitForm} class=\"submit\">SUBMIT form</button>\n  <button on:click={submitFormObject} class=\"submit-object\">SUBMIT OBJECT form</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Nested.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    name: 'foo',\n    address: {\n      street: '123 Main St',\n      city: 'New York',\n    },\n    organization: {\n      name: 'Inertia',\n      repo: {\n        name: 'inertiajs/inertia',\n        tags: ['v0.1', 'v0.2'],\n      },\n    },\n    checked: ['foo', 'bar'],\n  })\n\n  const submit = () => {\n    $form.submit('post', '/dump/post')\n  }\n</script>\n\n<div>\n  <label>\n    Full Name\n    <input type=\"text\" id=\"name\" bind:value={$form.name} />\n  </label>\n  <label>\n    Street\n    <input type=\"text\" id=\"street\" bind:value={$form.address.street} />\n  </label>\n  <label>\n    City\n    <input type=\"text\" id=\"city\" bind:value={$form.address.city} />\n  </label>\n  <label>\n    Foo\n    <input type=\"checkbox\" id=\"foo\" value=\"foo\" bind:group={$form.checked} />\n  </label>\n  <label>\n    Bar\n    <input type=\"checkbox\" id=\"bar\" value=\"bar\" bind:group={$form.checked} />\n  </label>\n  <label>\n    Baz\n    <input type=\"checkbox\" id=\"baz\" value=\"baz\" bind:group={$form.checked} />\n  </label>\n  <label>\n    Organization Name\n    <input type=\"text\" id=\"organization-name\" bind:value={$form.organization.name} />\n  </label>\n  <label>\n    Repository Name\n    <input type=\"text\" id=\"repo-name\" bind:value={$form.organization.repo.name} />\n  </label>\n  Repository Tags\n  <label>\n    v0.1\n    <input type=\"checkbox\" id=\"tag-0\" value=\"v0.1\" bind:group={$form.organization.repo.tags} />\n  </label>\n  <label>\n    v0.2\n    <input type=\"checkbox\" id=\"tag-1\" value=\"v0.2\" bind:group={$form.organization.repo.tags} />\n  </label>\n  <label>\n    v0.3\n    <input type=\"checkbox\" id=\"tag-2\" value=\"v0.3\" bind:group={$form.organization.repo.tags} />\n  </label>\n  <button on:click={submit} class=\"submit\">Submit form</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Precognition/BeforeValidation.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n  import { isEqual } from 'lodash-es'\n\n  const form = useForm({\n    name: '',\n    email: '',\n  })\n    .withPrecognition('post', '/precognition/default')\n    .setValidationTimeout(100)\n\n  const handleBeforeValidation = (\n    newRequest: { data: Record<string, unknown> | null; touched: string[] },\n    oldRequest: { data: Record<string, unknown> | null; touched: string[] },\n  ) => {\n    const payloadIsCorrect =\n      isEqual(newRequest, { data: { name: 'block' }, touched: ['name'] }) &&\n      isEqual(oldRequest, { data: {}, touched: [] })\n\n    if (payloadIsCorrect && newRequest.data?.name === 'block') {\n      return false\n    }\n\n    return true\n  }\n</script>\n\n<div>\n  <div>\n    <input\n      bind:value={$form.name}\n      name=\"name\"\n      placeholder=\"Name\"\n      on:blur={() =>\n        $form.validate('name', {\n          onBeforeValidation: handleBeforeValidation,\n        })}\n    />\n    {#if $form.invalid('name')}\n      <p>\n        {$form.errors.name}\n      </p>\n    {/if}\n    {#if $form.valid('name')}<p>Name is valid!</p>{/if}\n  </div>\n\n  <div>\n    <input bind:value={$form.email} name=\"email\" placeholder=\"Email\" on:blur={() => $form.validate('email')} />\n    {#if $form.invalid('email')}\n      <p>\n        {$form.errors.email}\n      </p>\n    {/if}\n    {#if $form.valid('email')}<p>Email is valid!</p>{/if}\n  </div>\n\n  {#if $form.validating}<p>Validating...</p>{/if}\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Precognition/Callbacks.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    name: '',\n    email: '',\n  })\n    .withPrecognition('post', '/precognition/default')\n    .setValidationTimeout(100)\n\n  let successCalled = false\n  let errorCalled = false\n  let finishCalled = false\n</script>\n\n<div>\n  <div>\n    <input bind:value={$form.name} name=\"name\" placeholder=\"Name\" on:blur={() => $form.touch('name')} />\n    {#if $form.invalid('name')}\n      <p>\n        {$form.errors.name}\n      </p>\n    {/if}\n    {#if $form.valid('name')}<p>Name is valid!</p>{/if}\n  </div>\n\n  {#if $form.validating}<p>Validating...</p>{/if}\n  {#if successCalled}<p>onPrecognitionSuccess called!</p>{/if}\n  {#if errorCalled}<p>onValidationError called!</p>{/if}\n  {#if finishCalled}<p>onFinish called!</p>{/if}\n\n  <button\n    type=\"button\"\n    on:click={() => {\n      successCalled = false\n      errorCalled = false\n      finishCalled = false\n      $form.validate({\n        onPrecognitionSuccess: () => {\n          successCalled = true\n        },\n        onValidationError: () => {\n          errorCalled = true\n        },\n        onFinish: () => {\n          finishCalled = true\n        },\n      })\n    }}\n  >\n    Validate\n  </button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Precognition/Cancel.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    name: '',\n  })\n    .withPrecognition('post', '/precognition/default?slow=1')\n    .setValidationTimeout(100)\n</script>\n\n<div>\n  <div>\n    <input\n      id=\"auto-cancel-name-input\"\n      bind:value={$form.name}\n      name=\"name\"\n      placeholder=\"Name\"\n      on:blur={() => $form.validate('name')}\n    />\n    {#if $form.invalid('name')}\n      <p>\n        {$form.errors.name}\n      </p>\n    {/if}\n    {#if $form.valid('name')}<p>Name is valid!</p>{/if}\n  </div>\n\n  {#if $form.validating}<p>Validating...</p>{/if}\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Precognition/Compatibility.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n  import type { NamedInputEvent } from 'laravel-precognition'\n\n  const form = useForm({\n    name: '',\n    email: '',\n    company: '',\n  })\n    .withPrecognition('post', '/precognition/default')\n    .setValidationTimeout(100)\n\n  const onCompanyFocus = (e: FocusEvent) => {\n    const event = e as any as NamedInputEvent // eslint-disable-line @typescript-eslint/no-explicit-any\n    form.forgetError(event)\n    form.touch(event)\n  }\n</script>\n\n<div>\n  <h1>Compatibility Test Page</h1>\n\n  <div>\n    <input bind:value={$form.name} name=\"name\" placeholder=\"Name\" on:blur={() => $form.validate('name')} />\n    {#if $form.invalid('name')}\n      <p id=\"name-error\">{$form.errors.name}</p>\n    {/if}\n    {#if $form.valid('name')}\n      <p id=\"name-valid\">Name is valid!</p>\n    {/if}\n  </div>\n\n  <div>\n    <input bind:value={$form.email} name=\"email\" placeholder=\"Email\" on:blur={() => $form.validate('email')} />\n    {#if $form.invalid('email')}\n      <p id=\"email-error\">{$form.errors.email}</p>\n    {/if}\n    {#if $form.valid('email')}\n      <p id=\"email-valid\">Email is valid!</p>\n    {/if}\n  </div>\n\n  <div>\n    <input\n      bind:value={$form.company}\n      name=\"company\"\n      placeholder=\"Company\"\n      on:focus={onCompanyFocus}\n      on:blur={() => $form.validate('company')}\n    />\n    {#if $form.invalid('company')}\n      <p id=\"company-error\">{$form.errors.company}</p>\n    {/if}\n    {#if $form.valid('company')}\n      <p id=\"company-valid\">company is valid!</p>\n    {/if}\n  </div>\n\n  {#if $form.validating}\n    <p id=\"validating\">Validating...</p>\n  {/if}\n\n  <!-- Test compatibility methods -->\n  <div style=\"margin-top: 20px\">\n    <button\n      type=\"button\"\n      id=\"test-setErrors\"\n      on:click={() =>\n        $form.setErrors({ name: 'setErrors test', email: 'setErrors email test', company: 'setErrors company test' })}\n    >\n      Test setErrors()\n    </button>\n\n    <button type=\"button\" id=\"test-forgetError\" on:click={() => $form.forgetError('name')}> Test forgetError() </button>\n\n    <button type=\"button\" id=\"test-touch-array\" on:click={() => $form.touch(['name', 'email'])}>\n      Test touch([])\n    </button>\n\n    <button type=\"button\" id=\"test-touch-spread\" on:click={() => $form.touch('name', 'email')}>\n      Test touch(...args)\n    </button>\n  </div>\n\n  <div style=\"margin-top: 20px\">\n    <p id=\"touched-name\">Name touched: {$form.touched('name') ? 'yes' : 'no'}</p>\n    <p id=\"touched-email\">Email touched: {$form.touched('email') ? 'yes' : 'no'}</p>\n    <p id=\"touched-company\">Company touched: {$form.touched('company') ? 'yes' : 'no'}</p>\n    <p id=\"touched-any\">Any touched: {$form.touched() ? 'yes' : 'no'}</p>\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Precognition/Default.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    name: '',\n    email: '',\n  })\n    .withPrecognition('post', '/precognition/default')\n    .setValidationTimeout(100)\n</script>\n\n<div>\n  <div>\n    <input bind:value={$form.name} name=\"name\" placeholder=\"Name\" on:blur={() => $form.validate('name')} />\n    {#if $form.invalid('name')}\n      <p>\n        {$form.errors.name}\n      </p>\n    {/if}\n    {#if $form.valid('name')}<p>Name is valid!</p>{/if}\n  </div>\n\n  <div>\n    <input bind:value={$form.email} name=\"email\" placeholder=\"Email\" on:blur={() => $form.validate('email')} />\n    {#if $form.invalid('email')}\n      <p>\n        {$form.errors.email}\n      </p>\n    {/if}\n    {#if $form.valid('email')}<p>Email is valid!</p>{/if}\n  </div>\n\n  {#if $form.validating}<p>Validating...</p>{/if}\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Precognition/DynamicArrayInputs.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    items: [] as Array<{ name: string }>,\n  })\n    .withPrecognition('post', '/precognition/dynamic-array-inputs')\n    .setValidationTimeout(100)\n\n  function addItem() {\n    $form.items = [...$form.items, { name: '' }]\n  }\n</script>\n\n<div>\n  <button id=\"add-item\" on:click={addItem}>Add Item</button>\n\n  {#each $form.items as item, idx (idx)}\n    <div>\n      <input bind:value={item.name} name={`items.${idx}.name`} on:blur={() => $form.validate(`items.${idx}.name`)} />\n      {#if $form.invalid(`items.${idx}.name`)}<p id={`items.${idx}.name-error`}>\n          {$form.errors[`items.${idx}.name`]}\n        </p>{/if}\n      {#if $form.valid(`items.${idx}.name`)}<p>Valid!</p>{/if}\n    </div>\n  {/each}\n\n  {#if $form.validating}<p>Validating...</p>{/if}\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Precognition/ErrorSync.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    name: '',\n    email: '',\n  })\n    .withPrecognition('post', '/precognition/error-sync')\n    .setValidationTimeout(100)\n\n  const handleSubmit = (e: Event) => {\n    e.preventDefault()\n    $form.submit()\n  }\n</script>\n\n<div>\n  <h1>Precognition Error Sync Test (Form Helper)</h1>\n\n  <form on:submit={handleSubmit}>\n    <div>\n      <input bind:value={$form.name} name=\"name\" placeholder=\"Name\" on:blur={() => $form.validate('name')} />\n      {#if $form.invalid('name')}\n        <p id=\"name-error\">\n          {$form.errors.name}\n        </p>\n      {/if}\n    </div>\n\n    <div>\n      <input bind:value={$form.email} name=\"email\" placeholder=\"Email\" on:blur={() => $form.validate('email')} />\n      {#if $form.invalid('email')}\n        <p id=\"email-error\">\n          {$form.errors.email}\n        </p>\n      {/if}\n    </div>\n\n    {#if $form.validating}<p id=\"validating\">Validating...</p>{/if}\n\n    <button type=\"submit\" id=\"submit-btn\">Submit</button>\n  </form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Precognition/Files.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm<{\n    name: string\n    avatar: File | null\n  }>({\n    name: '',\n    avatar: null,\n  })\n    .withPrecognition('post', '/precognition/files')\n    .setValidationTimeout(100)\n\n  let validateFiles = false\n\n  $: {\n    if (validateFiles && typeof $form.validateFiles === 'function') {\n      $form.validateFiles()\n    } else if (!validateFiles && typeof $form.withoutFileValidation === 'function') {\n      $form.withoutFileValidation()\n    }\n  }\n\n  const handleFileChange = (e: Event) => {\n    const target = e.target as HTMLInputElement\n    $form.avatar = target.files?.[0] || null\n  }\n</script>\n\n<div>\n  <div>\n    <input bind:value={$form.name} name=\"name\" placeholder=\"Name\" on:blur={() => $form.validate('name')} />\n    {#if $form.invalid('name')}\n      <p>\n        {$form.errors.name}\n      </p>\n    {/if}\n    {#if $form.valid('name')}<p>Name is valid!</p>{/if}\n  </div>\n\n  <div>\n    <input type=\"file\" name=\"avatar\" id=\"avatar\" on:change={handleFileChange} />\n    {#if $form.invalid('avatar')}\n      <p>\n        {$form.errors.avatar}\n      </p>\n    {/if}\n    {#if $form.valid('avatar')}<p>Avatar is valid!</p>{/if}\n  </div>\n\n  {#if $form.validating}<p>Validating...</p>{/if}\n\n  <button type=\"button\" on:click={() => (validateFiles = !validateFiles)}>\n    Toggle Validate Files ({validateFiles ? 'enabled' : 'disabled'})\n  </button>\n\n  <button type=\"button\" on:click={() => $form.validate({ only: ['name', 'avatar'] })}>Validate Both</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Precognition/Headers.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    name: '',\n  })\n    .withPrecognition('post', '/precognition/headers')\n    .setValidationTimeout(100)\n</script>\n\n<div>\n  <div>\n    <input\n      bind:value={$form.name}\n      name=\"name\"\n      placeholder=\"Name\"\n      on:blur={() =>\n        $form.validate('name', {\n          headers: { 'X-Custom-Header': 'custom-value' },\n        })}\n    />\n    {#if $form.invalid('name')}\n      <p>\n        {$form.errors.name}\n      </p>\n    {/if}\n    {#if $form.valid('name')}<p>Name is valid!</p>{/if}\n  </div>\n\n  {#if $form.validating}<p>Validating...</p>{/if}\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Precognition/Instantiate.svelte",
    "content": "<script lang=\"ts\">\n  import type { Method, UrlMethodPair } from '@inertiajs/core'\n  import { useForm } from '@inertiajs/svelte'\n  import { get, writable } from 'svelte/store'\n\n  const wayfinderUrl = (): UrlMethodPair => ({\n    url: '/precognition/default',\n    method: 'post',\n  })\n\n  const formName = writable<keyof typeof forms>('default')\n  const data = () => ({ name: 'a' })\n\n  const forms = {\n    // Forms that use the new withPrecognition() method\n    default: useForm(data()).withPrecognition('post', '/precognition/default'),\n    dynamic: useForm(data()).withPrecognition(\n      () => 'post',\n      () => '/precognition/default',\n    ),\n    wayfinder: useForm(data()).withPrecognition(wayfinderUrl()),\n    dynamicWayfinder: useForm(data()).withPrecognition(() => wayfinderUrl()),\n\n    // Forms that use the original useForm() parameters from the 0.x Precognition implementation\n    legacy: useForm('post', '/precognition/default', data()),\n    legacyDynamic: useForm(\n      () => 'post' as Method,\n      () => '/precognition/default',\n      data(),\n    ),\n    legacyWayfinder: useForm(wayfinderUrl(), data()),\n    legacyDynamicWayfinder: useForm(() => wayfinderUrl(), data()),\n  }\n\n  // Get the current form store reactively\n  $: currentFormStore = forms[$formName]\n\n  const validateForm = (formName: keyof typeof forms) => {\n    const form = forms[formName]\n    get(form).touch('name')\n    get(form).validate()\n  }\n\n  const submitWithoutArgs = (formName: keyof typeof forms) => {\n    const form = forms[formName]\n    get(form).submit()\n  }\n\n  const submitWithArgs = (formName: keyof typeof forms) => {\n    const form = forms[formName]\n    get(form).submit('patch', '/dump/patch')\n  }\n\n  const submitWithMethod = (formName: keyof typeof forms) => {\n    const form = forms[formName]\n    get(form).put('/dump/put')\n  }\n\n  const submitWithWayfinder = (formName: keyof typeof forms) => {\n    const form = forms[formName]\n    get(form).submit({ url: '/dump/post', method: 'post' })\n  }\n</script>\n\n<select bind:value={$formName}>\n  <option value=\"default\">withPrecognition()</option>\n  <option value=\"dynamic\">withPrecognition() dynamic</option>\n  <option value=\"wayfinder\">withPrecognition() Wayfinder</option>\n  <option value=\"dynamicWayfinder\">withPrecognition() dynamic Wayfinder</option>\n  <option value=\"legacy\">useForm() legacy</option>\n  <option value=\"legacyDynamic\">useForm() legacy dynamic</option>\n  <option value=\"legacyWayfinder\">useForm() legacy Wayfinder</option>\n  <option value=\"legacyDynamicWayfinder\">useForm() legacy dynamic Wayfinder</option>\n</select>\n\n<button on:click={() => validateForm($formName)}>Validate</button>\n<button on:click={() => submitWithoutArgs($formName)}>Submit without args</button>\n<button on:click={() => submitWithArgs($formName)}>Submit with args</button>\n<button on:click={() => submitWithMethod($formName)}>Submit with method</button>\n<button on:click={() => submitWithWayfinder($formName)}>Submit with Wayfinder</button>\n\n{#if $currentFormStore && $currentFormStore.validating}<p>Validating...</p>{/if}\n{#if $currentFormStore && $currentFormStore.errors && $currentFormStore.errors.name}<p>\n    {$currentFormStore.errors.name}\n  </p>{/if}\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Precognition/Methods.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    name: '',\n    email: '',\n  })\n    .withPrecognition('post', '/precognition/default')\n    .setValidationTimeout(100)\n</script>\n\n<div>\n  <div>\n    <input name=\"name\" bind:value={$form.name} placeholder=\"Name\" on:blur={() => $form.touch('name')} />\n    {#if $form.invalid('name')}\n      <p>\n        {$form.errors.name}\n      </p>\n    {/if}\n  </div>\n\n  <div>\n    <input name=\"email\" bind:value={$form.email} placeholder=\"Email\" on:blur={() => $form.touch('email')} />\n    {#if $form.invalid('email')}\n      <p>\n        {$form.errors.email}\n      </p>\n    {/if}\n  </div>\n\n  {#if $form.validating}<p>Validating...</p>{/if}\n\n  <p id=\"name-touched\">{$form.touched('name') ? 'Name is touched' : 'Name is not touched'}</p>\n  <p id=\"email-touched\">{$form.touched('email') ? 'Email is touched' : 'Email is not touched'}</p>\n  <p id=\"any-touched\">{$form.touched() ? 'Form has touched fields' : 'Form has no touched fields'}</p>\n\n  <button type=\"button\" on:click={() => $form.validate()}>Validate All Touched</button>\n  <button type=\"button\" on:click={() => $form.validate('name')}>Validate Name</button>\n  <button type=\"button\" on:click={() => $form.validate({ only: ['name', 'email'] })}>Validate Name and Email</button>\n  <button type=\"button\" on:click={() => $form.touch('name', 'email')}>Touch Name and Email</button>\n  <button\n    type=\"button\"\n    on:click={() => {\n      $form.touch('name')\n      $form.touch('name')\n    }}\n  >\n    Touch Name Twice\n  </button>\n  <button type=\"button\" on:click={() => $form.reset()}>Reset All</button>\n  <button type=\"button\" on:click={() => $form.reset('name')}>Reset Name</button>\n  <button type=\"button\" on:click={() => $form.reset('name', 'email')}>Reset Name and Email</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Precognition/Transform.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    name: '',\n  })\n    .withPrecognition('post', '/precognition/default')\n    .setValidationTimeout(100)\n    .transform((data) => ({ name: String(data.name || '').repeat(2) }))\n</script>\n\n<div>\n  <div>\n    <input bind:value={$form.name} name=\"name\" placeholder=\"Name\" on:blur={() => $form.validate('name')} />\n    {#if $form.invalid('name')}\n      <p>\n        {$form.errors.name}\n      </p>\n    {/if}\n    {#if $form.valid('name')}<p>Name is valid!</p>{/if}\n  </div>\n\n  {#if $form.validating}<p>Validating...</p>{/if}\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Precognition/TransformKeys.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    document: {\n      customer: { email: '' },\n    },\n  })\n    .withPrecognition('post', '/precognition/transform-keys')\n    .setValidationTimeout(100)\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    .transform((data) => ({ ...data.document })) as any\n</script>\n\n<div>\n  <div>\n    <input\n      id=\"email-input\"\n      bind:value={$form.document.customer.email}\n      name=\"customer.email\"\n      placeholder=\"Email\"\n      on:blur={() => $form.validate('customer.email')}\n    />\n    {#if $form.invalid('customer.email')}\n      <p>{$form.errors['customer.email']}</p>\n    {/if}\n    {#if $form.valid('customer.email')}<p>Email is valid!</p>{/if}\n  </div>\n\n  {#if $form.validating}<p>Validating...</p>{/if}\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Precognition/WithAllErrors.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    name: '',\n    email: '',\n  })\n    .withPrecognition('post', '/precognition/with-all-errors')\n    .setValidationTimeout(100)\n    .withAllErrors()\n</script>\n\n<div>\n  <div>\n    <input bind:value={$form.name} name=\"name\" placeholder=\"Name\" on:blur={() => $form.validate('name')} />\n    {#if $form.invalid('name')}\n      <div>\n        {#if Array.isArray($form.errors.name)}\n          {#each $form.errors.name as error, index (index)}\n            <p id=\"name-error-{index}\">\n              {error}\n            </p>\n          {/each}\n        {:else}\n          <p id=\"name-error-0\">{$form.errors.name}</p>\n        {/if}\n      </div>\n    {/if}\n    {#if $form.valid('name')}<p>Name is valid!</p>{/if}\n  </div>\n\n  <div>\n    <input bind:value={$form.email} name=\"email\" placeholder=\"Email\" on:blur={() => $form.validate('email')} />\n    {#if $form.invalid('email')}\n      <div>\n        {#if Array.isArray($form.errors.email)}\n          {#each $form.errors.email as error, index (index)}\n            <p id=\"email-error-{index}\">\n              {error}\n            </p>\n          {/each}\n        {:else}\n          <p id=\"email-error-0\">{$form.errors.email}</p>\n        {/if}\n      </div>\n    {/if}\n    {#if $form.valid('email')}<p>Email is valid!</p>{/if}\n  </div>\n\n  {#if $form.validating}<p>Validating...</p>{/if}\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Precognition/WithAllErrorsConfig.svelte",
    "content": "<script lang=\"ts\">\n  import { config, useForm } from '@inertiajs/svelte'\n\n  // Set global config for withAllErrors (no .withAllErrors() call on the form)\n  config.set('form.withAllErrors', true)\n\n  const form = useForm({\n    name: '',\n    email: '',\n  })\n    .withPrecognition('post', '/precognition/with-all-errors')\n    .setValidationTimeout(100)\n</script>\n\n<div>\n  <div>\n    <input bind:value={$form.name} name=\"name\" placeholder=\"Name\" on:blur={() => form.validate('name')} />\n    {#if $form.invalid('name')}\n      <div>\n        {#if Array.isArray($form.errors.name)}\n          {#each $form.errors.name as error, index (index)}\n            <p id=\"name-error-{index}\">{error}</p>\n          {/each}\n        {:else}\n          <p id=\"name-error-0\">{$form.errors.name}</p>\n        {/if}\n      </div>\n    {/if}\n    {#if $form.valid('name')}\n      <p>Name is valid!</p>\n    {/if}\n  </div>\n\n  <div>\n    <input bind:value={$form.email} name=\"email\" placeholder=\"Email\" on:blur={() => form.validate('email')} />\n    {#if $form.invalid('email')}\n      <div>\n        {#if Array.isArray($form.errors.email)}\n          {#each $form.errors.email as error, index (index)}\n            <p id=\"email-error-{index}\">{error}</p>\n          {/each}\n        {:else}\n          <p id=\"email-error-0\">{$form.errors.email}</p>\n        {/if}\n      </div>\n    {/if}\n    {#if $form.valid('email')}\n      <p>Email is valid!</p>\n    {/if}\n  </div>\n\n  {#if $form.validating}\n    <p>Validating...</p>\n  {/if}\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Precognition/WithoutAllErrors.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    name: '',\n    email: '',\n  })\n    .withPrecognition('post', '/precognition/with-all-errors')\n    .setValidationTimeout(100)\n</script>\n\n<div>\n  <div>\n    <input bind:value={$form.name} name=\"name\" placeholder=\"Name\" on:blur={() => $form.validate('name')} />\n    {#if $form.invalid('name')}\n      <p>\n        {$form.errors.name}\n      </p>\n    {/if}\n    {#if $form.valid('name')}<p>Name is valid!</p>{/if}\n  </div>\n\n  <div>\n    <input bind:value={$form.email} name=\"email\" placeholder=\"Email\" on:blur={() => $form.validate('email')} />\n    {#if $form.invalid('email')}\n      <p>\n        {$form.errors.email}\n      </p>\n    {/if}\n    {#if $form.valid('email')}<p>Email is valid!</p>{/if}\n  </div>\n\n  {#if $form.validating}<p>Validating...</p>{/if}\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/RememberEdit.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  interface User {\n    id: number\n    name: string\n    email: string\n  }\n\n  export let user: User\n\n  const form = useForm('EditUserForm', {\n    name: user.name,\n    email: user.email,\n  })\n</script>\n\n<div>\n  <h1>Edit User {user.id}</h1>\n  <form>\n    <div>\n      <label for=\"name\">Name:</label>\n      <input id=\"name\" type=\"text\" bind:value={$form.name} />\n    </div>\n    <div>\n      <label for=\"email\">Email:</label>\n      <input id=\"email\" type=\"email\" bind:value={$form.email} />\n    </div>\n  </form>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/RememberIndex.svelte",
    "content": "<script lang=\"ts\">\n  import { Link } from '@inertiajs/svelte'\n\n  interface User {\n    id: number\n    name: string\n    email: string\n  }\n\n  export let users: User[]\n</script>\n\n<div>\n  <h1>Users Index</h1>\n  <ul>\n    {#each users as user (user.id)}\n      <li>\n        <Link href=\"/remember/users/{user.id}/edit\">Edit {user.name}</Link>\n      </li>\n    {/each}\n  </ul>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/ReservedKeys.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  // @ts-expect-error - Intentionally using reserved key to test validation\n  const form = useForm({ progress: 0 })\n</script>\n\n<div>\n  <div id=\"form-created\">Form created with progress value: {$form.progress}</div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/Transform.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({\n    name: 'foo',\n    remember: false,\n  })\n\n  const postForm = () => {\n    $form\n      .transform((data) => ({\n        ...data,\n        name: 'bar',\n      }))\n      .post('/dump/post')\n  }\n\n  const putForm = () => {\n    $form\n      .transform((data) => ({\n        ...data,\n        name: 'baz',\n      }))\n      .put('/dump/put')\n  }\n\n  const patchForm = () => {\n    $form\n      .transform((data) => ({\n        ...data,\n        name: 'foo',\n      }))\n      .patch('/dump/patch')\n  }\n\n  const deleteForm = () => {\n    $form\n      .transform((data) => ({\n        ...data,\n        name: 'bar',\n      }))\n      .delete('/dump/delete')\n  }\n</script>\n\n<div>\n  <label>\n    Full Name\n    <input type=\"text\" id=\"name\" name=\"name\" bind:value={$form.name} />\n  </label>\n  <label>\n    Remember Me\n    <input type=\"checkbox\" id=\"remember\" name=\"remember\" bind:checked={$form.remember} />\n  </label>\n\n  <button on:click={postForm} class=\"post\">POST form</button>\n  <button on:click={putForm} class=\"put\">PUT form</button>\n  <button on:click={patchForm} class=\"patch\">PATCH form</button>\n  <button on:click={deleteForm} class=\"delete\">DELETE form</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/TypeScript/Any.svelte",
    "content": "<script lang=\"ts\">\n  // This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm<{ name: any }>({ name: null }) // eslint-disable-line @typescript-eslint/no-explicit-any\n\n  $form.name = 0\n  $form.name = 'test'\n  $form.name = true\n  $form.name = null\n  $form.name = {\n    key: 'value',\n  }\n</script>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/TypeScript/Child.svelte",
    "content": "<script lang=\"ts\">\n  // This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\n  import type { InertiaForm } from '@inertiajs/svelte'\n\n  export let form: InertiaForm<{\n    name: string\n    email?: string\n  }>\n</script>\n\n<p>Name: {form.name}</p>\n<p>Email: {form.email}</p>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/TypeScript/CircularReferences.svelte",
    "content": "<script lang=\"ts\">\n  // This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\n  import { useForm } from '@inertiajs/svelte'\n\n  type SubData = {\n    foo: string\n    items?: SubData[]\n  }\n\n  type Data = {\n    items: SubData[]\n  }\n\n  const form = useForm<Data>({\n    items: [],\n  })\n\n  $form.items = []\n  $form.items = [\n    {\n      foo: 'bar',\n      items: [\n        {\n          foo: 'baz',\n          items: [\n            {\n              foo: 'qux',\n            },\n          ],\n        },\n      ],\n    },\n  ]\n\n  // @ts-expect-error - items should be an array of SubData\n  $form.items = {}\n  // @ts-expect-error - foo should be a string\n  $form.items = [{ foo: 123 }]\n  // @ts-expect-error - items should be an array of SubData\n  $form.items = [{ foo: 'bar', items: {} }]\n  // @ts-expect-error - foo should be a string\n  $form.items = [{ foo: 'bar', items: [{ foo: 123 }] }]\n</script>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/TypeScript/Data.svelte",
    "content": "<script lang=\"ts\">\n  // This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\n  import { useForm } from '@inertiajs/svelte'\n\n  type FormData = {\n    name: string\n    company: { name: string }\n    users: { name: string }[]\n  }\n\n  const defaultData = {\n    name: '',\n    company: { name: '' },\n    users: [],\n  }\n\n  const form = useForm<FormData>(defaultData)\n  $form.name = 'John Doe'\n  $form.company.name = 'Acme Corp'\n  $form.users = [{ name: 'Jane Doe' }]\n  // @ts-expect-error - A form has no email field\n  $form.email = 'john@example.com'\n  // @ts-expect-error - A company has no street field\n  $form.company.street = '123 Main St'\n  // @ts-expect-error - A company has no street field\n  $form.company = { name: 'Acme Corp', street: '123 Main St' }\n  // @ts-expect-error - A form has no email field\n  $form.users = [{ name: 'Jane Doe', email: 'jane@example.com' }]\n</script>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/TypeScript/DynamicInputName.svelte",
    "content": "<script lang=\"ts\">\n  // This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\n  import { useForm } from '@inertiajs/svelte'\n\n  interface ClientForm {\n    name: string\n    [key: string]: any // eslint-disable-line @typescript-eslint/no-explicit-any\n  }\n\n  const form = useForm<ClientForm>({\n    name: '',\n  })\n\n  const handleChange = (e: Event) => {\n    const target = e.target as HTMLInputElement\n    const { name, value } = target\n    $form[name] = value\n  }\n</script>\n\n<input name=\"name\" type=\"text\" value={$form.name} on:input={handleChange} />\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/TypeScript/Errors.svelte",
    "content": "<script lang=\"ts\">\n  // This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\n  import { useForm } from '@inertiajs/svelte'\n\n  type FormData = {\n    name: string\n    company: { name: string }\n    users: { name: string }[]\n  }\n\n  const defaultData = {\n    name: '',\n    company: { name: '' },\n    users: [],\n  }\n\n  const form = useForm<FormData>(defaultData)\n\n  // Get Errors\n  console.log(form.errors.name)\n  console.log(form.errors['company.name'])\n\n  // Clear Errors\n  $form.clearErrors('name')\n  $form.clearErrors('company')\n  $form.clearErrors('company.name')\n  $form.clearErrors('users')\n  $form.clearErrors('users.0')\n  $form.clearErrors('users.0.name')\n\n  // Reset and Clear Errors\n  $form.resetAndClearErrors('name')\n  $form.resetAndClearErrors('company')\n  $form.resetAndClearErrors('company.name')\n  $form.resetAndClearErrors('users')\n  $form.resetAndClearErrors('users.0')\n  $form.resetAndClearErrors('users.0.name')\n\n  // Set error by key\n  $form.setError('name', 'Validation error')\n  $form.setError('company', 'Validation error')\n  $form.setError('company.name', 'Validation error')\n  $form.setError('users', 'Validation error')\n  $form.setError('users.0', 'Validation error')\n  $form.setError('users.0.name', 'Validation error')\n\n  // Set error by object\n  $form.setError({ name: 'Validation error' })\n  $form.setError({ company: 'Validation error' })\n  $form.setError({ 'company.name': 'Validation error' })\n  $form.setError({ users: 'Validation error' })\n  $form.setError({ 'users.0': 'Validation error' })\n  $form.setError({ 'users.0.name': 'Validation error' })\n\n  // @ts-expect-error - Form has no email field\n  console.log(form.errors.email)\n  // @ts-expect-error - Company has no email field\n  console.log(form.errors['company.email'])\n\n  // @ts-expect-error - Form has no email field\n  $form.clearErrors('email')\n  // @ts-expect-error - Form has no email field\n  $form.resetAndClearErrors('email')\n  // @ts-expect-error - Form has no email field\n  $form.setError('email', 'Validation error')\n  // @ts-expect-error - Form has no email field\n  $form.setError({ email: 'Validation error' })\n\n  // @ts-expect-error - Company has no email field\n  $form.clearErrors('company.email')\n  // @ts-expect-error - Company has no email field\n  $form.resetAndClearErrors('company.email')\n  // @ts-expect-error - Company has no email field\n  $form.setError('company.email', 'Validation error')\n  // @ts-expect-error - Company has no email field\n  $form.setError({ 'company.email': 'Validation error' })\n\n  // @ts-expect-error - A user has no email field\n  $form.clearErrors('users.0.email')\n  // @ts-expect-error - A user has no email field\n  $form.resetAndClearErrors('users.0.email')\n  // @ts-expect-error - A user has no email field\n  $form.setError('users.0.email', 'Validation error')\n  // @ts-expect-error - A user has no email field\n  $form.setError({ 'users.0.email': 'Validation error' })\n</script>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/TypeScript/FormDataCallback.svelte",
    "content": "<script lang=\"ts\">\n  // This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\n  import { useForm } from '@inertiajs/svelte'\n\n  type FormData = {\n    name: string\n    company: { name: string }\n    users: { name: string }[]\n  }\n\n  const defaultData = {\n    name: '',\n    company: { name: '' },\n    users: [],\n  }\n\n  const form = useForm<FormData>(() => defaultData)\n  $form.name = 'John Doe'\n  $form.company.name = 'Acme Corp'\n  $form.users = [{ name: 'Jane Doe' }]\n  // @ts-expect-error - A form has no email field\n  $form.email = 'john@example.com'\n  // @ts-expect-error - A company has no street field\n  $form.company.street = '123 Main St'\n  // @ts-expect-error - A company has no street field\n  $form.company = { name: 'Acme Corp', street: '123 Main St' }\n  // @ts-expect-error - A form has no email field\n  $form.users = [{ name: 'Jane Doe', email: 'jane@example.com' }]\n\n  const inferredData = {\n    name: '',\n    company: { name: '' },\n    users: [{ name: '' }],\n  }\n\n  const inferred = useForm(() => inferredData)\n  $inferred.name = 'John Doe'\n  $inferred.company.name = 'Acme Corp'\n  $inferred.users = [{ name: 'Jane Doe' }]\n  // @ts-expect-error - A form has no email field\n  $inferred.email = 'john@example.com'\n\n  const withRememberKey = useForm<FormData>('myKey', () => defaultData)\n  $withRememberKey.name = 'John Doe'\n  // @ts-expect-error - A form has no email field\n  $withRememberKey.email = 'john@example.com'\n\n  // @ts-expect-error - progress is a reserved form key\n  useForm(() => ({ progress: 1 }))\n</script>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/TypeScript/Generic.svelte",
    "content": "<script lang=\"ts\" generics=\"TFormData extends Record<string, FormDataConvertible>\">\n  // This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\n  import type { FormDataConvertible } from '@inertiajs/core'\n  import type { InertiaForm } from '@inertiajs/svelte'\n\n  export let form: InertiaForm<TFormData>\n</script>\n\n<div>{form}</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/TypeScript/Nullable.svelte",
    "content": "<script lang=\"ts\">\n  // This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\n  import { useForm } from '@inertiajs/svelte'\n\n  useForm<{ object: { x: number } | null }>({\n    object: null,\n  })\n\n  useForm<{ object: { x: number } | null }>({\n    object: { x: 1 },\n  })\n</script>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/TypeScript/NullableNestedObject.svelte",
    "content": "<script lang=\"ts\">\n  // This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\n  import { useForm } from '@inertiajs/svelte'\n\n  interface FormData {\n    foo: null | {\n      bar: string\n    }\n  }\n\n  const form = useForm<FormData>({\n    foo: null,\n  })\n\n  console.log($form.errors['foo.bar'])\n</script>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/TypeScript/OptionalProps.svelte",
    "content": "<script lang=\"ts\">\n  // This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\n  import { useForm } from '@inertiajs/svelte'\n\n  interface LoginData {\n    username: string\n    password: string\n    remember: boolean\n  }\n\n  export let user: {\n    username?: string | null\n  } | null = null\n\n  useForm<LoginData>({\n    username: user?.username ?? '',\n    password: '',\n    remember: true,\n  })\n</script>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/TypeScript/Parent.svelte",
    "content": "<script lang=\"ts\">\n  // This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\n  import { useForm } from '@inertiajs/svelte'\n  import Child from './Child.svelte'\n\n  const form = useForm({\n    name: 'foo',\n    remember: false,\n  })\n</script>\n\n<Child form={$form} />\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/TypeScript/Precognition.svelte",
    "content": "<script lang=\"ts\">\n  // This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\n  import { useForm } from '@inertiajs/svelte'\n\n  const defaultForm = useForm({})\n  const rememberForm = useForm('id', {})\n\n  // @ts-expect-error - No Precognition...\n  defaultForm.validate()\n  // @ts-expect-error - No Precognition...\n  rememberForm.validate()\n\n  const precognitionForm = useForm({ name: '', company: '' }).withPrecognition('post', '/precognition/default')\n  const originalPrecognitionForm = useForm('post', '/', {})\n\n  precognitionForm.validate()\n  originalPrecognitionForm.validate()\n\n  precognitionForm.validate('name')\n  precognitionForm.validate({ only: ['name'] })\n  precognitionForm.touch('name')\n  precognitionForm.touch('name', 'company')\n  precognitionForm.touched()\n  precognitionForm.touched('name')\n  precognitionForm.invalid('name')\n  precognitionForm.valid('name')\n\n  // @ts-expect-error - Field does not exist\n  precognitionForm.validate('email')\n  // @ts-expect-error - Field does not exist\n  precognitionForm.validate({ only: ['email'] })\n  // @ts-expect-error - Field does not exist\n  precognitionForm.touch('email')\n  // @ts-expect-error - Field does not exist\n  precognitionForm.touched('email')\n  // @ts-expect-error - Field does not exist\n  precognitionForm.invalid('email')\n  // @ts-expect-error - Field does not exist\n  precognitionForm.valid('email')\n\n  const nestedForm = useForm({ user: { name: '', company: '' } }).withPrecognition('post', '/precognition/nested')\n\n  nestedForm.validate('user.name')\n  nestedForm.validate({ only: ['user.name'] })\n  nestedForm.valid('user.name')\n  nestedForm.invalid('user.name')\n\n  // @ts-expect-error - Field does not exist\n  nestedForm.validate('user.email')\n  // @ts-expect-error - Field does not exist\n  nestedForm.validate({ only: ['user.email'] })\n  // @ts-expect-error - Field does not exist\n  nestedForm.valid('user.email')\n  // @ts-expect-error - Field does not exist\n  nestedForm.invalid('user.email')\n\n  // Wildcard path support (PrecognitionPath)\n  const wildcardForm = useForm({\n    users: [] as Array<{ name: string; email: string }>,\n    profile: { age: 0, city: '' },\n    company: { name: '', addresses: [] as string[] },\n    nested: { companies: [] as Array<{ name: string; addresses: string[] }> },\n  }).withPrecognition('post', '/precognition/wildcard')\n\n  // Valid array field paths\n  wildcardForm.validate('users')\n  wildcardForm.validate('users.*')\n  wildcardForm.validate('users.*.name')\n  wildcardForm.validate('users.*.email')\n  wildcardForm.validate('users.*.*')\n\n  // Valid object field paths\n  wildcardForm.validate('profile')\n  wildcardForm.validate('profile.*')\n  wildcardForm.validate('profile.age')\n\n  // Valid nested paths\n  wildcardForm.validate('company')\n  wildcardForm.validate('company.addresses')\n  wildcardForm.validate('nested')\n  wildcardForm.validate('nested.companies')\n  wildcardForm.validate('nested.companies.*')\n  wildcardForm.validate('nested.companies.*.name')\n  wildcardForm.validate('nested.companies.*.addresses')\n  wildcardForm.validate('nested.companies.*.*')\n\n  // @ts-expect-error - nonexistent property in array items\n  wildcardForm.validate('users.*.unknown')\n  // @ts-expect-error - missing wildcard for array access\n  wildcardForm.validate('users.email')\n  // @ts-expect-error - invalid deep nesting\n  wildcardForm.validate('profile.age.foo')\n  // @ts-expect-error - field does not exist\n  wildcardForm.validate('nonexistent')\n  // @ts-expect-error - no such field\n  wildcardForm.validate('profile.country')\n</script>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/TypeScript/ValidationKey.svelte",
    "content": "<script lang=\"ts\">\n  // This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\n  import type { FormDataConvertible } from '@inertiajs/core'\n  import type { InertiaFormProps } from '@inertiajs/svelte'\n\n  const validation = <T extends Record<string, FormDataConvertible>>(errors: () => InertiaFormProps<T>['errors']) => {\n    type Key = keyof ReturnType<typeof errors>\n\n    const filterAndMap = (key: Key) => {\n      const err = errors()\n\n      return (Object.keys(err).filter((k) => k.startsWith(key)) as [keyof ReturnType<typeof errors>]).map((k) => err[k])\n    }\n\n    const unique = (key: Key) => {\n      return filterAndMap(key).filter((error, index, self) => self.indexOf(error) === index)\n    }\n\n    return { filterAndMap, unique }\n  }\n</script>\n\n<button on:click={() => validation(() => ({ name: 'Validation error' }))}> Handle </button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/TypeScript/WrapperChild.svelte",
    "content": "<!-- eslint-disable @typescript-eslint/no-explicit-any -->\n<script lang=\"ts\" generics=\"T extends Record<string, any>\">\n  import { useForm } from '@inertiajs/svelte'\n\n  export let data: T\n\n  const form = useForm(data)\n</script>\n\n<form>\n  <slot form={$form} />\n</form>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/FormHelper/TypeScript/WrapperParent.svelte",
    "content": "<script lang=\"ts\">\n  // This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\n  import WrapperChild from './WrapperChild.svelte'\n\n  const dummyForm = {\n    header: '',\n    children: [\n      {\n        title: '',\n        active: false,\n      },\n    ],\n  }\n</script>\n\n<WrapperChild data={dummyForm} let:form>\n  {form.children.map((child) => child.title)}\n</WrapperChild>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/History/Page.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia, router } from '@inertiajs/svelte'\n\n  export let pageNumber\n  export let multiByte\n</script>\n\n<a href=\"/history/1\" use:inertia>Page 1</a>\n<a href=\"/history/2\" use:inertia>Page 2</a>\n<a href=\"/history/3\" use:inertia>Page 3</a>\n<a href=\"/history/4\" use:inertia>Page 4</a>\n<a href=\"/history/5\" use:inertia>Page 5</a>\n\n<button on:click={() => router.clearHistory()}>Clear History</button>\n\n<div>This is page {pageNumber}.</div>\n<div>Multi byte character: {multiByte}</div>\n\n<div style=\"height: 5000px\"></div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/History/Version.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n</script>\n\n<a href=\"/history/version/1\" use:inertia>Page 1</a>\n<a href=\"/history/version/2\" use:inertia>Page 2</a>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/HistoryQuota/Page.svelte",
    "content": "<script>\n  import { Link } from '@inertiajs/svelte'\n\n  export let pageNumber\n  export let largeData\n</script>\n\n<div>\n  <h1>History Quota Test - Page {pageNumber}</h1>\n  <p>Data size: {largeData?.length?.toLocaleString()} bytes</p>\n\n  <div style=\"margin-top: 20px\">\n    {#each Array.from({ length: 20 }, (_, i) => i + 1) as n (n)}\n      <Link href={`/history-quota/${n}`} style=\"margin-right: 10px\">\n        Page {n}\n      </Link>\n    {/each}\n  </div>\n\n  <div style=\"height: 5000px\"></div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/HistoryThrottle.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia, router } from '@inertiajs/svelte'\n\n  let callCount = 0\n\n  function triggerRapidStateUpdates() {\n    for (let i = 0; i < 120; i++) {\n      callCount = i + 1\n      router.remember({ value: i }, `key-${i}`)\n    }\n  }\n</script>\n\n<div>\n  <h1>History Throttle Test</h1>\n  <p id=\"call-count\">State updates: {callCount}</p>\n  <button id=\"trigger\" on:click={triggerRapidStateUpdates}>Trigger Rapid State Updates</button>\n  <a id=\"home-link\" href=\"/\" use:inertia>Go Home</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Home.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia, page, router } from '@inertiajs/svelte'\n  import { onMount } from 'svelte'\n\n  const visitsMethod = () => {\n    router.visit('/visits/method')\n  }\n\n  const visitsReplace = () => {\n    router.get('/visits/replace')\n  }\n\n  const redirect = () => {\n    router.post('/redirect')\n  }\n\n  const redirectExternal = () => {\n    router.post('/redirect-external')\n  }\n\n  onMount(() => {\n    window._inertia_page_key = crypto.randomUUID()\n    window._inertia_props = $page.props\n    window._plugin_global_props = {}\n  })\n</script>\n\n<div>\n  <span class=\"text\">This is the Test App Entrypoint page</span>\n\n  <a href=\"/links/method\" use:inertia class=\"links-method\">Basic Links</a>\n  <a href=\"/links/replace\" use:inertia class=\"links-replace\">'Replace' Links</a>\n\n  <a href={'#'} on:click|preventDefault={visitsMethod} class=\"visits-method\">Manual basic visits</a>\n  <a href={'#'} on:click|preventDefault={visitsReplace} class=\"visits-replace\">Manual 'Replace' visits</a>\n\n  <button use:inertia={{ href: '/redirect', method: 'post' }} class=\"links-redirect\">Internal Redirect Link</button>\n  <a href={'#'} on:click|preventDefault={redirect} class=\"visits-redirect\">Manual Redirect visit</a>\n\n  <button use:inertia={{ href: '/redirect-external', method: 'post' }} class=\"links-redirect-external\"\n    >External Redirect Link</button\n  >\n  <a href={'#'} on:click|preventDefault={redirectExternal} class=\"visits-redirect-external\"\n    >Manual External Redirect visit</a\n  >\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/CustomElement.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n</script>\n\n<InfiniteScroll data=\"users\" as=\"section\" data-testid=\"infinite-scroll-container\">\n  <div slot=\"loading\" style=\"text-align: center; padding: 20px\">Loading...</div>\n\n  {#each users.data as user (user.id)}\n    <UserCard {user} />\n  {/each}\n</InfiniteScroll>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/CustomTriggersRef.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n\n  let tableHeader: HTMLTableSectionElement\n  let tableFooter: HTMLTableSectionElement\n  let tableBody: HTMLTableSectionElement\n</script>\n\n<div style=\"padding: 20px\">\n  <h1>Custom Triggers with Refs Test</h1>\n\n  <InfiniteScroll\n    data=\"users\"\n    startElement={() => tableHeader}\n    endElement={() => tableFooter}\n    itemsElement={() => tableBody}\n    let:loading\n  >\n    <div style=\"height: 300px; width: 100%; text-align: center; line-height: 300px; border: 1px solid #ccc\">Spacer</div>\n\n    <table style=\"width: 100%; border-collapse: collapse\">\n      <thead bind:this={tableHeader} style=\"padding: 10px\">\n        <tr>\n          <th style=\"padding: 12px; border: 1px solid #ccc\">ID</th>\n          <th style=\"padding: 12px; border: 1px solid #ccc\">Name</th>\n        </tr>\n      </thead>\n\n      <tbody bind:this={tableBody}>\n        {#each users.data as user (user.id)}\n          <tr data-user-id={user.id}>\n            <td style=\"padding: 80px 12px; border: 1px solid #ccc\">{user.id}</td>\n            <td style=\"padding: 80px 12px; border: 1px solid #ccc\">{user.name}</td>\n          </tr>\n        {/each}\n\n        {#if loading}\n          <tr>\n            <td colspan=\"2\" style=\"padding: 12px; border: 1px solid #ccc; text-align: center\"> Loading... </td>\n          </tr>\n        {/if}\n      </tbody>\n\n      <tfoot bind:this={tableFooter} style=\"background: #fdf2e8; padding: 10px\">\n        <tr>\n          <td colspan=\"2\" style=\"padding: 12px; border: 1px solid #ccc; text-align: center\">\n            Table Footer - Triggers when this comes into view\n          </td>\n        </tr>\n      </tfoot>\n    </table>\n\n    <div style=\"height: 300px; width: 100%; text-align: center; line-height: 300px; border: 1px solid #ccc\">Spacer</div>\n  </InfiniteScroll>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/CustomTriggersRefObject.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n\n  let tableHeader: HTMLTableSectionElement\n  let tableFooter: HTMLTableSectionElement\n  let tableBody: HTMLTableSectionElement\n</script>\n\n<div style=\"padding: 20px\">\n  <h1>Custom Triggers with Svelte Ref Objects Test</h1>\n\n  <InfiniteScroll\n    data=\"users\"\n    startElement={() => tableHeader}\n    endElement={() => tableFooter}\n    itemsElement={() => tableBody}\n    let:loading\n  >\n    <div style=\"height: 300px; width: 100%; text-align: center; line-height: 300px; border: 1px solid #ccc\">Spacer</div>\n\n    <table style=\"width: 100%; border-collapse: collapse\">\n      <thead bind:this={tableHeader} style=\"padding: 10px\">\n        <tr>\n          <th style=\"padding: 12px; border: 1px solid #ccc\">ID</th>\n          <th style=\"padding: 12px; border: 1px solid #ccc\">Name</th>\n        </tr>\n      </thead>\n\n      <tbody bind:this={tableBody}>\n        {#each users.data as user (user.id)}\n          <tr data-user-id={user.id}>\n            <td style=\"padding: 80px 12px; border: 1px solid #ccc\">{user.id}</td>\n            <td style=\"padding: 80px 12px; border: 1px solid #ccc\">{user.name}</td>\n          </tr>\n        {/each}\n\n        {#if loading}\n          <tr>\n            <td colspan=\"2\" style=\"padding: 12px; border: 1px solid #ccc; text-align: center\"> Loading... </td>\n          </tr>\n        {/if}\n      </tbody>\n\n      <tfoot bind:this={tableFooter} style=\"background: #fdf2e8; padding: 10px\">\n        <tr>\n          <td colspan=\"2\" style=\"padding: 12px; border: 1px solid #ccc; text-align: center\">\n            Table Footer - Triggers when this comes into view\n          </td>\n        </tr>\n      </tfoot>\n    </table>\n\n    <div style=\"height: 300px; width: 100%; text-align: center; line-height: 300px; border: 1px solid #ccc\">Spacer</div>\n  </InfiniteScroll>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/CustomTriggersSelector.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n</script>\n\n<div style=\"padding: 20px\">\n  <h1>Custom Triggers with Selectors Test</h1>\n\n  <InfiniteScroll\n    data=\"users\"\n    itemsElement=\"#table-body\"\n    startElement=\"#table-header\"\n    endElement=\"#table-footer\"\n    let:loading\n  >\n    <div style=\"height: 300px; width: 100%; text-align: center; line-height: 300px; border: 1px solid #ccc\">Spacer</div>\n\n    <table style=\"width: 100%; border-collapse: collapse\">\n      <thead id=\"table-header\" style=\"padding: 12px\">\n        <tr>\n          <th style=\"padding: 12px; border: 1px solid #ccc\">ID</th>\n          <th style=\"padding: 12px; border: 1px solid #ccc\">Name</th>\n        </tr>\n      </thead>\n\n      <tbody id=\"table-body\">\n        {#each users.data as user (user.id)}\n          <tr data-user-id={user.id}>\n            <td style=\"padding: 80px 12px; border: 1px solid #ccc\">{user.id}</td>\n            <td style=\"padding: 80px 12px; border: 1px solid #ccc\">{user.name}</td>\n          </tr>\n        {/each}\n\n        {#if loading}\n          <tr>\n            <td colspan=\"2\" style=\"padding: 12px; border: 1px solid #ccc; text-align: center\"> Loading... </td>\n          </tr>\n        {/if}\n      </tbody>\n\n      <tfoot id=\"table-footer\" style=\"padding: 12px\">\n        <tr>\n          <td colspan=\"2\" style=\"padding: 12px; border: 1px solid #ccc; text-align: center\">\n            Table Footer - Triggers when this comes into view\n          </td>\n        </tr>\n      </tfoot>\n    </table>\n\n    <div style=\"height: 300px; width: 100%; text-align: center; line-height: 300px; border: 1px solid #ccc\">Spacer</div>\n  </InfiniteScroll>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/DataTable.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n</script>\n\n<InfiniteScroll data=\"users\" itemsElement=\"tbody\" let:loading>\n  <table style=\"width: 100%; border-collapse: collapse\">\n    <thead>\n      <tr>\n        <th style=\"padding: 8px; border: 1px solid #ccc\">ID</th>\n        <th style=\"padding: 8px; border: 1px solid #ccc\">Name</th>\n      </tr>\n    </thead>\n\n    <tbody>\n      {#each users.data as user (user.id)}\n        <tr data-user-id={user.id}>\n          <td style=\"padding: 8px; border: 1px solid #ccc\">{user.id}</td>\n          <td style=\"padding: 8px; border: 1px solid #ccc\">{user.name}</td>\n        </tr>\n      {/each}\n    </tbody>\n\n    <tfoot>\n      {#if loading}\n        <tr>\n          <td colspan=\"2\" style=\"padding: 8px; border: 1px solid #ccc; text-align: center\"> Loading... </td>\n        </tr>\n      {/if}\n    </tfoot>\n  </table>\n</InfiniteScroll>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/Deferred.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred, InfiniteScroll } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] } | undefined\n</script>\n\n<Deferred data=\"users\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading deferred scroll prop...</div>\n  </svelte:fragment>\n\n  <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\" manual>\n    <div slot=\"previous\" let:hasMore let:loading let:fetch>\n      <p>Has more previous items: {hasMore}</p>\n      <button on:click={fetch}>\n        {loading ? 'Loading previous items...' : 'Load previous items'}\n      </button>\n    </div>\n\n    {#each users?.data ?? [] as user (user.id)}\n      <UserCard {user} />\n    {/each}\n\n    <div slot=\"next\" let:hasMore let:loading let:fetch>\n      <p>Has more next items: {hasMore}</p>\n      <button on:click={fetch}>\n        {loading ? 'Loading next items...' : 'Load next items'}\n      </button>\n    </div>\n  </InfiniteScroll>\n</Deferred>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/DualContainers.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users1: { data: User[] }\n  export let users2: { data: User[] }\n</script>\n\n<div style=\"padding: 20px\">\n  <div style=\"display: flex; gap: 20px\">\n    <!-- First scroll container -->\n    <div style=\"flex: 1\">\n      <h2>Users1 Container</h2>\n      <div\n        data-testid=\"scroll-container-1\"\n        style=\"height: 400px; width: 100%; border: 2px solid #3b82f6; overflow-y: auto; background: #f0f9ff; padding: 10px\"\n      >\n        <InfiniteScroll data=\"users1\" style=\"display: grid; gap: 10px\">\n          <div slot=\"loading\" style=\"text-align: center; padding: 20px; color: #3b82f6\">Loading more users1...</div>\n\n          {#each users1.data as user (user.id)}\n            <UserCard {user} />\n          {/each}\n        </InfiniteScroll>\n      </div>\n    </div>\n\n    <!-- Second scroll container -->\n    <div style=\"flex: 1\">\n      <h2>Users2 Container</h2>\n      <div\n        data-testid=\"scroll-container-2\"\n        style=\"height: 400px; width: 100%; border: 2px solid #ef4444; overflow-y: auto; background: #fef2f2; padding: 10px\"\n      >\n        <InfiniteScroll data=\"users2\" style=\"display: grid; gap: 10px\">\n          <div slot=\"loading\" style=\"text-align: center; padding: 20px; color: #ef4444\">Loading more users2...</div>\n\n          {#each users2.data as user (user.id)}\n            <UserCard {user} />\n          {/each}\n        </InfiniteScroll>\n      </div>\n    </div>\n  </div>\n\n  <p style=\"margin-top: 20px\">Content below the scroll containers to verify page doesn't scroll.</p>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/DualSibling.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users1: { data: User[] }\n  export let users2: { data: User[] }\n</script>\n\n<div style=\"padding: 20px\">\n  <h1>Dual Sibling InfiniteScroll</h1>\n  <p style=\"margin-bottom: 20px\">Two InfiniteScroll components side by side, sharing the window scroll</p>\n\n  <div style=\"display: grid; grid-template-columns: 1fr 1fr; gap: 40px\">\n    <div>\n      <h2>Users 1</h2>\n      <InfiniteScroll data=\"users1\" style=\"display: grid; gap: 20px\" manual>\n        {#each users1.data as user (user.id)}\n          <UserCard {user} />\n        {/each}\n\n        <div slot=\"next\" let:exposedNext style=\"text-align: center; padding: 20px\">\n          <button on:click={exposedNext.fetch} disabled={exposedNext.loading}>\n            {exposedNext.loading ? 'Loading...' : 'Load More Users 1'}\n          </button>\n        </div>\n      </InfiniteScroll>\n    </div>\n\n    <div>\n      <h2>Users 2</h2>\n      <InfiniteScroll data=\"users2\" style=\"display: grid; gap: 20px\" manual>\n        {#each users2.data as user (user.id)}\n          <UserCard {user} />\n        {/each}\n\n        <div slot=\"next\" let:exposedNext style=\"text-align: center; padding: 20px\">\n          <button on:click={exposedNext.fetch} disabled={exposedNext.loading}>\n            {exposedNext.loading ? 'Loading...' : 'Load More Users 2'}\n          </button>\n        </div>\n      </InfiniteScroll>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/Empty.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n</script>\n\n<div>\n  <h1>Empty Dataset Test</h1>\n  <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\">\n    <div slot=\"loading\" style=\"text-align: center; padding: 20px\">Loading...</div>\n\n    {#each users.data as user (user.id)}\n      <UserCard {user} />\n    {/each}\n\n    {#if users.data.length === 0}\n      <div style=\"text-align: center; padding: 40px; color: #666\">No users found.</div>\n    {/if}\n  </InfiniteScroll>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/Filtering.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll, Link, useForm } from '@inertiajs/svelte'\n  import { onDestroy } from 'svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n  export let preserveState: boolean\n  export let filter: string | undefined = undefined\n  export let search: string | undefined = undefined\n\n  const form = useForm({\n    filter: undefined,\n    page: undefined,\n    search: search,\n  })\n\n  let timeoutId: ReturnType<typeof setTimeout> | undefined\n  let previousSearch = search\n\n  onDestroy(() => {\n    if (timeoutId) {\n      clearTimeout(timeoutId)\n    }\n  })\n\n  // Debounced search using manual setTimeout/clearTimeout\n  $: if ($form.search !== previousSearch) {\n    // Clear previous timeout\n    if (timeoutId) {\n      clearTimeout(timeoutId)\n    }\n\n    // Set new timeout for debounced search\n    timeoutId = setTimeout(() => {\n      $form.get(\n        '',\n        preserveState\n          ? {\n              preserveState: true,\n              replace: true,\n              only: ['users', 'search', 'filter'],\n              reset: ['users'],\n            }\n          : { replace: true },\n      )\n      // eslint-disable-next-line svelte/infinite-reactive-loop\n      previousSearch = $form.search\n    }, 250)\n  }\n</script>\n\n<div>\n  <div style=\"margin-bottom: 20px; display: flex; gap: 10px\">\n    <Link href=\"\">No Filter</Link>\n    <Link href=\"?filter=a-m\">A-M</Link>\n    <Link href=\"?filter=n-z\">N-Z</Link>\n    <div>Current filter: {filter || 'none'}</div>\n    <div>Current search: {search || 'none'}</div>\n    <input bind:value={$form.search} placeholder=\"Search...\" />\n  </div>\n\n  <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\">\n    <div slot=\"loading\" style=\"text-align: center; padding: 20px\">Loading...</div>\n\n    {#each users.data as user (user.id)}\n      <UserCard {user} />\n    {/each}\n  </InfiniteScroll>\n\n  <div style=\"margin-top: 20px; display: flex; gap: 10px\">\n    <Link href=\"\">No Filter</Link>\n    <Link href=\"?filter=a-m\">A-M</Link>\n    <Link href=\"?filter=n-z\">N-Z</Link>\n    <div>Current filter: {filter || 'none'}</div>\n    <div>Current search: {search || 'none'}</div>\n    <input bind:value={$form.search} placeholder=\"Search...\" />\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/FilteringManual.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll, useForm } from '@inertiajs/svelte'\n  import { onDestroy } from 'svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n  export let search: string | undefined = undefined\n\n  const form = useForm({\n    search: search,\n  })\n\n  let timeoutId: ReturnType<typeof setTimeout> | undefined\n  let previousSearch = search\n\n  onDestroy(() => {\n    if (timeoutId) {\n      clearTimeout(timeoutId)\n    }\n  })\n\n  $: if ($form.search !== previousSearch) {\n    if (timeoutId) {\n      clearTimeout(timeoutId)\n    }\n\n    // Set new timeout for debounced search\n    timeoutId = setTimeout(() => {\n      $form.get('', {\n        preserveState: true,\n        replace: true,\n        only: ['users', 'search'],\n        reset: ['users'],\n      })\n      // eslint-disable-next-line svelte/infinite-reactive-loop\n      previousSearch = $form.search\n    }, 250)\n  }\n</script>\n\n<div>\n  <div style=\"margin-bottom: 20px; display: flex; gap: 10px\">\n    <div>Current search: {search || 'none'}</div>\n    <input bind:value={$form.search} placeholder=\"Search...\" />\n  </div>\n\n  <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\" manual>\n    <div slot=\"previous\" let:hasMore let:loading let:fetch>\n      <p>Has more previous items: {hasMore}</p>\n      <button on:click={fetch}>\n        {loading ? 'Loading previous items...' : 'Load previous items'}\n      </button>\n    </div>\n\n    {#each users.data as user (user.id)}\n      <UserCard {user} />\n    {/each}\n\n    <div slot=\"next\" let:hasMore let:loading let:fetch>\n      <p>Has more next items: {hasMore}</p>\n      <button on:click={fetch}>\n        {loading ? 'Loading next items...' : 'Load next items'}\n      </button>\n    </div>\n  </InfiniteScroll>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/FilteringReset.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll, useForm } from '@inertiajs/svelte'\n  import { onDestroy } from 'svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n  export let search: string | undefined = undefined\n\n  const form = useForm({\n    search: search,\n  })\n\n  let timeoutId: ReturnType<typeof setTimeout> | undefined\n  let previousSearch = search\n\n  onDestroy(() => {\n    if (timeoutId) {\n      clearTimeout(timeoutId)\n    }\n  })\n\n  $: if ($form.search !== previousSearch) {\n    if (timeoutId) {\n      clearTimeout(timeoutId)\n    }\n\n    timeoutId = setTimeout(() => {\n      $form.get('', {\n        preserveState: true,\n        replace: true,\n        only: ['users', 'search'],\n        reset: ['users'],\n      })\n      // eslint-disable-next-line svelte/infinite-reactive-loop\n      previousSearch = $form.search\n    }, 250)\n  }\n</script>\n\n<div>\n  <div style=\"margin-bottom: 20px; display: flex; gap: 10px\">\n    <div>Current search: {search || 'none'}</div>\n    <input bind:value={$form.search} placeholder=\"Search...\" />\n  </div>\n\n  <InfiniteScroll data=\"users\" buffer={2000} style=\"display: grid; gap: 20px\">\n    <div slot=\"loading\" style=\"text-align: center; padding: 20px\">Loading...</div>\n\n    {#each users.data as user (user.id)}\n      <UserCard {user} />\n    {/each}\n  </InfiniteScroll>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/Grid.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n</script>\n\n<InfiniteScroll data=\"users\" style=\"display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px\">\n  <div slot=\"loading\" style=\"grid-column: 1 / -1; text-align: center; padding: 20px\">Loading more users...</div>\n\n  <svelte:fragment slot=\"default\">\n    {#each users.data as user (user.id)}\n      <UserCard {user} />\n    {/each}\n  </svelte:fragment>\n</InfiniteScroll>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/HorizontalScroll.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n</script>\n\n<div style=\"height: 120px; overflow-x: scroll; display: flex; width: 100vw\">\n  <InfiniteScroll data=\"users\" style=\"display: flex; gap: 20px; height: 120px\">\n    <div\n      slot=\"loading\"\n      style=\"min-width: 150px; height: 100px; display: flex; align-items: center; justify-content: center; border: 1px dashed #ccc; margin-left: 20px; margin-right: 20px\"\n    >\n      Loading...\n    </div>\n\n    {#each users.data as user (user.id)}\n      <div\n        data-user-id={user.id}\n        style=\"min-width: 200px; height: 100px; border: 1px solid #ccc; background-color: #f5f5f5; display: flex; align-items: center; justify-content: center; flex: none\"\n      >\n        {user.name}\n      </div>\n    {/each}\n  </InfiniteScroll>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/InfiniteScrollWithLink.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia, InfiniteScroll } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n</script>\n\n<div>\n  <a href=\"/infinite-scroll\" use:inertia>Go back to Links</a>\n  <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\">\n    <div slot=\"loading\" style=\"text-align: center; padding: 20px\">Loading...</div>\n\n    {#each users.data as user (user.id)}\n      <UserCard {user} />\n    {/each}\n  </InfiniteScroll>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/InvisibleFirstChild.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n</script>\n\n<div>\n  <h1>Infinite Scroll with Invisible First Child</h1>\n\n  <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\">\n    <div slot=\"loading\" style=\"text-align: center; padding: 20px\">Loading...</div>\n\n    <div style=\"display: none\">Hidden first element</div>\n\n    {#each users.data as user (user.id)}\n      <UserCard {user} />\n    {/each}\n  </InfiniteScroll>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/Links.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <a href=\"/infinite-scroll-with-link\" use:inertia>Go to InfiniteScrollWithLink</a>\n  <a href=\"/infinite-scroll-with-link\" use:inertia={{ prefetch: true }}>Go to InfiniteScrollWithLink (Prefetch)</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/Manual.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n</script>\n\n<InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\" manual>\n  <div slot=\"previous\" let:hasMore let:loading let:fetch>\n    <p>Has more previous items: {hasMore}</p>\n    <button on:click={fetch}>\n      {loading ? 'Loading previous items...' : 'Load previous items'}\n    </button>\n  </div>\n\n  {#each users.data as user (user.id)}\n    <UserCard {user} />\n  {/each}\n\n  <div slot=\"next\" let:hasMore let:loading let:fetch>\n    <p>Has more next items: {hasMore}</p>\n    <button on:click={fetch}>\n      {loading ? 'Loading next items...' : 'Load next items'}\n    </button>\n  </div>\n</InfiniteScroll>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/ManualAfter.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n</script>\n\n<InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\" manualAfter={2}>\n  {#each users.data as user (user.id)}\n    <UserCard {user} />\n  {/each}\n\n  <div slot=\"next\" let:loading let:manualMode let:fetch>\n    {#if loading}\n      <p>Loading...</p>\n    {/if}\n\n    <p>Manual mode: {manualMode}</p>\n\n    {#if manualMode}\n      <button on:click={fetch}>Load next items...</button>\n    {/if}\n  </div>\n</InfiniteScroll>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/OverflowX.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import type { User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n</script>\n\n<div style=\"overflow-x: hidden\">\n  <InfiniteScroll data=\"users\">\n    {#each users.data as user (user.id)}\n      <div data-user-id={user.id}>\n        <div>{user.name}</div>\n      </div>\n    {/each}\n  </InfiniteScroll>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/PreserveUrl.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n</script>\n\n<InfiniteScroll data=\"users\" preserveUrl={true} style=\"display: grid; gap: 20px\">\n  <div slot=\"loading\" style=\"text-align: center; padding: 20px\">Loading...</div>\n\n  {#each users.data as user (user.id)}\n    <UserCard {user} />\n  {/each}\n</InfiniteScroll>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/ProgrammaticRef.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import { onMount } from 'svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n  import type { InfiniteScrollRef } from '@inertiajs/core'\n  export let users: { data: User[] }\n\n  // Use the actual component type like Form component does\n  let infRef: InfiniteScrollRef | null = null\n  let hasPrevious = false\n  let hasNext = false\n\n  function updateStates() {\n    hasPrevious = infRef?.hasPrevious() || false\n    hasNext = infRef?.hasNext() || false\n  }\n\n  function fetchNext() {\n    infRef?.fetchNext({ onFinish: updateStates })\n  }\n\n  function fetchPrevious() {\n    infRef?.fetchPrevious({ onFinish: updateStates })\n  }\n\n  onMount(() => setTimeout(updateStates))\n</script>\n\n<div>\n  <h1>Programmatic Ref Test</h1>\n\n  <div style=\"margin-bottom: 20px\">\n    <p>Has more previous items: {hasPrevious.toString()}</p>\n    <p>Has more next items: {hasNext.toString()}</p>\n\n    <div style=\"display: flex; gap: 10px; margin: 10px 0\">\n      <button on:click={fetchPrevious}>Load Previous (Ref)</button>\n      <button on:click={fetchNext}>Load Next (Ref)</button>\n    </div>\n  </div>\n\n  <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\" manual bind:this={infRef}>\n    <div slot=\"loading\" style=\"text-align: center; padding: 20px\">Loading...</div>\n\n    {#each users.data as user (user.id)}\n      <UserCard {user} />\n    {/each}\n  </InfiniteScroll>\n\n  <p>Total items on page: {users.data.length}</p>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/ReloadUnrelated.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll, router } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n  export let time: number\n\n  const reloadTime = () => {\n    router.reload({ only: ['time'] })\n  }\n</script>\n\n<div>\n  <div>\n    <button on:click={reloadTime} id=\"reload-button\">Reload Time</button>\n    <span id=\"time-display\">Current time: {time}</span>\n  </div>\n\n  <InfiniteScroll data=\"users\">\n    {#each users.data as user (user.id)}\n      <UserCard {user} />\n    {/each}\n  </InfiniteScroll>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/RememberState.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll, Link, router } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n\n  function prependUser(id: number) {\n    router.prependToProp('users.data', { id, name: `User ${id}` })\n  }\n</script>\n\n<div style=\"margin-bottom: 40px; padding: 20px; border-top: 2px solid #ccc\">\n  <div style=\"margin-bottom: 20px\">\n    <button on:click={() => prependUser(0)} style=\"margin-right: 10px\">Prepend User '0'</button>\n    <button on:click={() => prependUser(-1)} style=\"margin-right: 10px\">Prepend User '-1'</button>\n  </div>\n  <Link href=\"/home\">Go Home</Link>\n</div>\n\n<InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\" manualAfter={2}>\n  {#each users.data as user (user.id)}\n    <UserCard {user} />\n  {/each}\n\n  <div slot=\"next\" let:loading let:manualMode let:fetch>\n    {#if loading}\n      <p>Loading...</p>\n    {/if}\n\n    <p>Manual mode: {manualMode}</p>\n\n    {#if manualMode}\n      <button on:click|preventDefault={fetch}>Load next items...</button>\n    {/if}\n  </div>\n</InfiniteScroll>\n\n<div style=\"margin-top: 40px; padding: 20px; border-top: 2px solid #ccc\">\n  <Link href=\"/home\">Go to Home</Link>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/Reverse.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n\n  $: reversedUsers = [...users.data].reverse()\n</script>\n\n<InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\" reverse autoScroll={false}>\n  <div slot=\"loading\" style=\"text-align: center; padding: 20px\">Loading...</div>\n\n  {#each reversedUsers as user (user.id)}\n    <UserCard {user} />\n  {/each}\n</InfiniteScroll>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/ReverseShortContent.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n\n  export let users: { data: { id: number; name: string }[] }\n\n  $: reversedUsers = [...users.data].reverse()\n</script>\n\n<div style=\"display: flex; flex-direction: column; height: 100vh\">\n  <div style=\"padding: 10px; border-bottom: 1px solid #ccc; flex-shrink: 0\">Header</div>\n\n  <div data-testid=\"scroll-container\" style=\"flex: 1; overflow-y: auto\">\n    <InfiniteScroll data=\"users\" style=\"display: grid; gap: 4px; padding: 20px\" reverse>\n      <div slot=\"loading\" style=\"text-align: center; padding: 10px\">Loading...</div>\n\n      {#each reversedUsers as user (user.id)}\n        <div data-user-id={user.id} style=\"padding: 4px 8px; border: 1px solid #ddd; font-size: 13px\">\n          {user.name}\n        </div>\n      {/each}\n    </InfiniteScroll>\n  </div>\n\n  <div style=\"padding: 10px; border-top: 1px solid #ccc; flex-shrink: 0\">Footer</div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/ScrollContainer.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n</script>\n\n<div style=\"padding: 20px\">\n  <h1>Infinite Scroll in Container</h1>\n  <p>This component scrolls within a fixed-height container, not the full page.</p>\n\n  <!-- Fixed height scrollable container -->\n  <div\n    data-testid=\"scroll-container\"\n    style=\"height: 400px; width: 100%; border: 2px solid #ccc; overflow-y: auto; background: #f9f9f9; padding: 10px\"\n  >\n    <InfiniteScroll data=\"users\" style=\"display: grid; gap: 10px\">\n      <div slot=\"loading\" style=\"text-align: center; padding: 20px; color: #666\">Loading more users...</div>\n\n      {#each users.data as user (user.id)}\n        <UserCard {user} />\n      {/each}\n    </InfiniteScroll>\n  </div>\n\n  <p style=\"margin-top: 20px\">Content below the scroll container to verify page doesn't scroll.</p>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/ShortContent.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n</script>\n\n<InfiniteScroll data=\"users\" itemsElement=\"tbody\">\n  <table style=\"width: 100%; border-collapse: collapse\">\n    <tbody>\n      {#each users.data as user (user.id)}\n        <tr data-user-id={user.id}>\n          <td style=\"padding: 10px; border: 1px solid #ccc\">{user.id}</td>\n          <td style=\"padding: 10px; border: 1px solid #ccc\">{user.name}</td>\n        </tr>\n      {/each}\n    </tbody>\n  </table>\n</InfiniteScroll>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/Toggles.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n\n  let manual = false\n  let preserveUrl = false\n  let triggerMode: 'onlyPrevious' | 'onlyNext' | 'both' = 'onlyNext'\n</script>\n\n<div>\n  <div style=\"display: flex; gap: 10px\">\n    <p>\n      <label>\n        <input type=\"checkbox\" bind:checked={manual} />\n        Manual mode: {manual.toString()}\n      </label>\n    </p>\n\n    <p>\n      <label>\n        <input type=\"checkbox\" bind:checked={preserveUrl} />\n        Preserve URL: {preserveUrl.toString()}\n      </label>\n    </p>\n\n    <p>\n      <label>\n        Trigger mode: {triggerMode}\n        <select bind:value={triggerMode}>\n          <option value=\"onlyPrevious\">onlyPrevious</option>\n          <option value=\"onlyNext\">onlyNext</option>\n          <option value=\"both\">both</option>\n        </select>\n      </label>\n    </p>\n  </div>\n\n  <InfiniteScroll\n    data=\"users\"\n    style=\"display: grid; gap: 20px\"\n    {manual}\n    {preserveUrl}\n    onlyNext={triggerMode === 'onlyNext'}\n    onlyPrevious={triggerMode === 'onlyPrevious'}\n  >\n    <div slot=\"loading\" style=\"text-align: center; padding: 20px\">Loading...</div>\n\n    {#each users.data as user (user.id)}\n      <UserCard {user} />\n    {/each}\n  </InfiniteScroll>\n\n  <p>Total items on page: {users.data.length}</p>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/TriggerBoth.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n</script>\n\n<InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\">\n  <div slot=\"loading\" style=\"text-align: center; padding: 20px\">Loading...</div>\n\n  {#each users.data as user (user.id)}\n    <UserCard {user} />\n  {/each}\n</InfiniteScroll>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/TriggerEndBuffer.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n</script>\n\n<InfiniteScroll data=\"users\" buffer={200} onlyNext style=\"display: grid; gap: 20px\">\n  <div slot=\"loading\" style=\"text-align: center; padding: 20px\">Loading...</div>\n\n  {#each users.data as user (user.id)}\n    <UserCard {user} />\n  {/each}\n</InfiniteScroll>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/TriggerStartBuffer.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n</script>\n\n<InfiniteScroll data=\"users\" buffer={200} onlyPrevious style=\"display: grid; gap: 20px\">\n  <div slot=\"loading\" style=\"text-align: center; padding: 20px\">Loading...</div>\n\n  {#each users.data as user (user.id)}\n    <UserCard {user} />\n  {/each}\n</InfiniteScroll>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/UpdateQueryString.svelte",
    "content": "<script lang=\"ts\">\n  import { InfiniteScroll, page } from '@inertiajs/svelte'\n  import UserCard, { type User } from './UserCard.svelte'\n\n  export let users: { data: User[] }\n\n  window.testing = {\n    ...(window.testing || {}),\n    get pageUrl() {\n      return $page.url\n    },\n  }\n</script>\n\n<InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\">\n  <div slot=\"loading\" style=\"text-align: center; padding: 20px\">Loading...</div>\n\n  {#each users.data as user (user.id)}\n    <UserCard {user} />\n  {/each}\n</InfiniteScroll>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/InfiniteScroll/UserCard.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  export interface User {\n    id: number\n    name: string\n  }\n</script>\n\n<script lang=\"ts\">\n  export let user: User\n</script>\n\n<div\n  data-user-id={user.id}\n  style:height=\"15vh\"\n  style:border=\"1px solid #ccc\"\n  style:background-color={`rgba(150,150,150,${user.id / 40})`}\n  style:color=\"green\"\n  style:display=\"flex\"\n  style:align-items=\"center\"\n  style:justify-content=\"center\"\n>\n  {user.name}\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/AsWarning.svelte",
    "content": "<script lang=\"ts\">\n  import { Link } from '@inertiajs/svelte'\n\n  export let method\n</script>\n\n<div>\n  <span class=\"text\">This is the links page that demonstrates inertia-links with an 'as' warning</span>\n\n  <Link href=\"/example\" {method} class=\"get\">{method} Link</Link>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/AsWarningFalse.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n\n  export let method\n</script>\n\n<div>\n  <span class=\"text\">This is the links page that demonstrates inertia-links without the 'as' warning</span>\n\n  <button use:inertia={{ method, href: '/example' }} class=\"get\">{method} button Link</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/AutomaticCancellation.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <span class=\"text\">This is the links page that demonstrates that only one visit can be active at a time</span>\n  <a\n    href=\"/sleep\"\n    use:inertia\n    on:cancel={() => console.log('cancelled')}\n    on:start={() => console.log('started')}\n    class=\"visit\"\n  >\n    Link\n  </a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/CancelSyncRequest.svelte",
    "content": "<script lang=\"ts\">\n  import { Link } from '@inertiajs/svelte'\n\n  export let page: number\n</script>\n\n<h1 style=\"font-size: 40px;\">\n  Page {page}\n</h1>\n\n<Link href=\"/links/cancel-sync-request/1\">Go to Page 1</Link>\n<Link href=\"/links/cancel-sync-request/2\">Go to Page 2</Link>\n<Link href=\"/links/cancel-sync-request/3\">Go to Page 3</Link>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/Data/AutoConverted.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n\n  const linkData = {\n    file: new File([], 'example.jpg'),\n    foo: 'bar',\n  }\n</script>\n\n<div>\n  <span class=\"text\"\n    >This is the links page that demonstrates the automatic conversion of plain objects to form-data</span\n  >\n\n  <a href=\"/dump/get\" use:inertia={{ method: 'get', data: linkData }} class=\"get\">GET Link</a>\n  <button use:inertia={{ method: 'post', href: '/dump/post', data: linkData }} class=\"post\">POST Link</button>\n  <button use:inertia={{ method: 'put', href: '/dump/put', data: linkData }} class=\"put\">PUT Link</button>\n  <button use:inertia={{ method: 'patch', href: '/dump/patch', data: linkData }} class=\"patch\">PATCH Link</button>\n  <button use:inertia={{ method: 'delete', href: '/dump/delete', data: linkData }} class=\"delete\">DELETE Link</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/Data/FormData.svelte",
    "content": "<script lang=\"ts\">\n  import { onMount } from 'svelte'\n  import { inertia } from '@inertiajs/svelte'\n\n  let linkData = new FormData()\n\n  onMount(() => {\n    linkData.append('bar', 'baz')\n  })\n</script>\n\n<div>\n  <span class=\"text\">This is the links page that demonstrates passing data through FormData objects</span>\n\n  <a href=\"/dump/get\" use:inertia={{ method: 'get', data: linkData }} class=\"get\">GET Link</a>\n  <button use:inertia={{ method: 'post', href: '/dump/post', data: linkData }} class=\"post\">POST Link</button>\n  <button use:inertia={{ method: 'put', href: '/dump/put', data: linkData }} class=\"put\">PUT Link</button>\n  <button use:inertia={{ method: 'patch', href: '/dump/patch', data: linkData }} class=\"patch\">PATCH Link</button>\n  <button use:inertia={{ method: 'delete', href: '/dump/delete', data: linkData }} class=\"delete\">DELETE Link</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/Data/Object.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <span class=\"text\">This is the links page that demonstrates passing data through plain objects</span>\n\n  <a href=\"/dump/get\" use:inertia={{ method: 'get', data: { foo: 'get' } }} class=\"get\">GET Link</a>\n  <button use:inertia={{ method: 'post', href: '/dump/post', data: { bar: 'post' } }} class=\"post\">POST Link</button>\n  <button use:inertia={{ method: 'put', href: '/dump/put', data: { baz: 'put' } }} class=\"put\">PUT Link</button>\n  <button use:inertia={{ method: 'patch', href: '/dump/patch', data: { foo: 'patch' } }} class=\"patch\"\n    >PATCH Link</button\n  >\n  <button use:inertia={{ method: 'delete', href: '/dump/delete', data: { bar: 'delete' } }} class=\"delete\"\n    >DELETE Link</button\n  >\n\n  <a href=\"/dump/get\" use:inertia={{ data: { a: ['b', 'c'] } }} class=\"qsaf-default\">QSAF Defaults</a>\n  <a href=\"/dump/get\" use:inertia={{ data: { a: ['b', 'c'] }, queryStringArrayFormat: 'indices' }} class=\"qsaf-indices\"\n    >QSAF Indices</a\n  >\n  <a\n    href=\"/dump/get\"\n    use:inertia={{ data: { a: ['b', 'c'] }, queryStringArrayFormat: 'brackets' }}\n    class=\"qsaf-brackets\">QSAF Brackets</a\n  >\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/DataLoading.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <a href=\"/sleep\" use:inertia class=\"get\">First</a>\n  <a href=\"/sleep\" use:inertia class=\"get\">Second</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/Headers.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <span class=\"text\">This is the links page that demonstrates passing custom headers</span>\n  <a href=\"/dump/get\" use:inertia class=\"default\">Standard visit Link</a>\n\n  <a href=\"/dump/get\" use:inertia={{ method: 'get', headers: { foo: 'bar' } }} class=\"custom\">GET Link</a>\n  <button\n    use:inertia={{ method: 'post', href: '/dump/post', headers: { bar: 'baz', 'X-Requested-With': 'custom' } }}\n    class=\"overridden\">POST Link</button\n  >\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/Location.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <span class=\"text\">This is the links page that demonstrates location visits inertia-links</span>\n\n  <a href=\"/location\" use:inertia={{ replace: true }} class=\"example\">Location visit</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/Method.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <span class=\"text\">This is the links page that demonstrates inertia-link methods</span>\n\n  <a href=\"/dump/get\" use:inertia={{ method: 'get' }} class=\"get\">GET Link</a>\n  <button use:inertia={{ method: 'post', href: '/dump/post' }} class=\"post\">POST Link</button>\n  <button use:inertia={{ method: 'put', href: '/dump/put' }} class=\"put\">PUT Link</button>\n  <button use:inertia={{ method: 'patch', href: '/dump/patch' }} class=\"patch\">PATCH Link</button>\n  <button use:inertia={{ method: 'delete', href: '/dump/delete' }} class=\"delete\">DELETE Link</button>\n  <button use:inertia={{ href: { url: '/dump/post', method: 'post' } }}>OBJECT Link</button>\n  <button use:inertia={{ href: { url: '/dump/post', method: 'post' }, method: 'put' }}\n    >OBJECT METHOD OVERRIDE Link</button\n  >\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/PartialReloads.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n\n  export let foo = 0\n  export let bar\n  export let baz\n  export let headers\n</script>\n\n<div>\n  <span class=\"text\">This is the links page that demonstrates partial reloads</span>\n  <span class=\"foo-text\">Foo is now {foo}</span>\n  <span class=\"bar-text\">Bar is now {bar}</span>\n  <span class=\"baz-text\">Baz is now {baz}</span>\n  <pre class=\"headers\" style=\"white-space: pre-wrap; word-break: keep-all;\">{JSON.stringify(headers, null, 2)}</pre>\n\n  <a href=\"/links/partial-reloads\" use:inertia={{ data: { foo } }} class=\"all\">Update All</a>\n  <a href=\"/links/partial-reloads\" use:inertia={{ only: ['headers', 'foo', 'bar'], data: { foo } }} class=\"foo-bar\"\n    >Only foo + bar</a\n  >\n  <a href=\"/links/partial-reloads\" use:inertia={{ only: ['headers', 'baz'], data: { foo } }} class=\"baz\">Only baz</a>\n  <a href=\"/links/partial-reloads\" use:inertia={{ except: ['foo', 'bar'], data: { foo } }} class=\"except-foo-bar\"\n    >Except foo + bar</a\n  >\n  <a href=\"/links/partial-reloads\" use:inertia={{ except: ['baz'], data: { foo } }} class=\"except-baz\">Except baz</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/PathTraversal.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n</script>\n\n<div class=\"space-y-2\">\n  <a use:inertia href=\"../\"> Up one level </a>\n\n  <a use:inertia href=\"../../method\"> Up two levels and open method </a>\n\n  <a use:inertia href=\"../../../\"> Up three levels </a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/PreserveScroll.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  export { default as layout } from '@/Layouts/WithScrollRegion.svelte'\n</script>\n\n<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n  import type { Page } from '@inertiajs/core'\n\n  export let foo: string = 'default'\n\n  const preserveCallback = (page: Page) => {\n    console.log(JSON.stringify(page))\n\n    return true\n  }\n\n  const preserveCallbackFalse = (page: Page) => {\n    console.log(JSON.stringify(page))\n\n    return false\n  }\n</script>\n\n<div style=\"height: 800px; width: 600px\">\n  <span class=\"text\">This is the links page that demonstrates scroll preservation with scroll regions</span>\n  <span class=\"foo\">Foo is now {foo}</span>\n\n  <a\n    href=\"/links/preserve-scroll-page-two\"\n    use:inertia={{ preserveScroll: true, data: { foo: 'baz' } }}\n    class=\"preserve\"\n    data-testid=\"preserve\"\n  >\n    Preserve Scroll\n  </a>\n  <a href=\"/links/preserve-scroll-page-two\" use:inertia={{ data: { foo: 'bar' } }} class=\"reset\" data-testid=\"reset\">\n    Reset Scroll\n  </a>\n\n  <a\n    href=\"/links/preserve-scroll-page-two\"\n    use:inertia={{ preserveScroll: preserveCallback, data: { foo: 'baz' } }}\n    class=\"preserve-callback\"\n    data-testid=\"preserve-callback\"\n  >\n    Preserve Scroll (Callback)\n  </a>\n  <a\n    href=\"/links/preserve-scroll-page-two\"\n    use:inertia={{ preserveScroll: preserveCallbackFalse, data: { foo: 'foo' } }}\n    class=\"reset-callback\"\n    data-testid=\"reset-callback\"\n  >\n    Reset Scroll (Callback)\n  </a>\n\n  <a href=\"/non-inertia\" class=\"off-site\" style=\"display: block\">Off-site link</a>\n\n  <a href=\"/article\" use:inertia={{}} class=\"article\" data-testid=\"article\"> Article </a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/PreserveScrollFalse.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  export { default as layout } from '@/Layouts/WithoutScrollRegion.svelte'\n</script>\n\n<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n  import type { Page } from '@inertiajs/core'\n\n  export let foo: string = 'default'\n\n  const preserveCallback = (page: Page) => {\n    console.log(JSON.stringify(page))\n\n    return true\n  }\n\n  const preserveCallbackFalse = (page: Page) => {\n    console.log(JSON.stringify(page))\n\n    return false\n  }\n</script>\n\n<div style=\"height: 800px; width: 600px\">\n  <span class=\"text\">This is the links page that demonstrates scroll preservation without scroll regions</span>\n  <span class=\"foo\">Foo is now {foo}</span>\n\n  <a\n    href=\"/links/preserve-scroll-false-page-two\"\n    use:inertia={{ preserveScroll: true, data: { foo: 'baz' } }}\n    class=\"preserve\"\n    data-testid=\"preserve\">Preserve Scroll</a\n  >\n  <a\n    href=\"/links/preserve-scroll-false-page-two\"\n    use:inertia={{ data: { foo: 'bar' } }}\n    class=\"reset\"\n    data-testid=\"reset\">Reset Scroll</a\n  >\n\n  <a\n    href=\"/links/preserve-scroll-false-page-two\"\n    use:inertia={{ preserveScroll: preserveCallback, data: { foo: 'baz' } }}\n    class=\"preserve-callback\"\n    data-testid=\"preserve-callback\">Preserve Scroll (Callback)</a\n  >\n  <a\n    href=\"/links/preserve-scroll-false-page-two\"\n    use:inertia={{ preserveScroll: preserveCallbackFalse, data: { foo: 'foo' } }}\n    class=\"reset-callback\"\n    data-testid=\"reset-callback\">Reset Scroll (Callback)</a\n  >\n\n  <a href=\"/non-inertia\" class=\"off-site\">Off-site link</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/PreserveState.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  export { default as layout } from '@/Layouts/WithoutScrollRegion.svelte'\n</script>\n\n<script lang=\"ts\">\n  import { onMount } from 'svelte'\n  import { inertia } from '@inertiajs/svelte'\n  import type { Page } from '@inertiajs/core'\n\n  export let foo: string = 'default'\n\n  const preserveCallback = (page: Page) => {\n    alert(page)\n\n    return true\n  }\n\n  const preserveCallbackFalse = (page: Page) => {\n    alert(page)\n\n    return false\n  }\n\n  onMount(() => {\n    window._inertia_page_key = crypto.randomUUID()\n  })\n</script>\n\n<div>\n  <span class=\"text\">This is the links page that demonstrates preserve state on Links</span>\n  <span class=\"foo\">Foo is now {foo}</span>\n  <label>\n    Example Field\n    <input type=\"text\" name=\"example-field\" class=\"field\" />\n  </label>\n\n  <a href=\"/links/preserve-state-page-two\" use:inertia={{ preserveState: true, data: { foo: 'bar' } }} class=\"preserve\">\n    [State] Preserve: true\n  </a>\n  <a\n    href=\"/links/preserve-state-page-two\"\n    use:inertia={{ preserveState: false, data: { foo: 'baz' } }}\n    class=\"preserve-false\"\n  >\n    [State] Preserve: false\n  </a>\n  <a\n    href=\"/links/preserve-state-page-two\"\n    use:inertia={{ preserveState: preserveCallback, data: { foo: 'callback-bar' } }}\n    class=\"preserve-callback\"\n  >\n    [State] Preserve Callback: true\n  </a>\n  <a\n    href=\"/links/preserve-state-page-two\"\n    use:inertia={{ preserveState: preserveCallbackFalse, data: { foo: 'callback-baz' } }}\n    class=\"preserve-callback-false\"\n  >\n    [State] Preserve Callback: false\n  </a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/PreserveUrl.svelte",
    "content": "<script lang=\"ts\">\n  import { router, Link } from '@inertiajs/svelte'\n\n  export let foo: string = 'default'\n  export let items:\n    | {\n        data: string[]\n        next_page_url?: string\n      }\n    | undefined = undefined\n\n  const loadMore = () => {\n    if (items?.next_page_url) {\n      router.visit(items.next_page_url, {\n        only: ['items'],\n        preserveState: true,\n        preserveScroll: true,\n        preserveUrl: true,\n      })\n    }\n  }\n</script>\n\n<div>\n  <span class=\"text\">This is the links page that demonstrates preserve url on Links</span>\n  <span class=\"foo\">Foo is now {foo}</span>\n\n  <Link href=\"/links/preserve-url-page-two\" preserveUrl data={{ foo: 'bar' }} class=\"preserve\">\n    [URL] Preserve: true\n  </Link>\n  <Link href=\"/links/preserve-url-page-two\" preserveUrl={false} data={{ foo: 'baz' }} class=\"preserve-false\">\n    [URL] Preserve: false\n  </Link>\n\n  {#if items}\n    <div class=\"items-section\">\n      <div class=\"items\">\n        {#each items.data as item, index (index)}\n          <div class=\"item\">{item}</div>\n        {/each}\n      </div>\n\n      <span class=\"items-loaded\">Items loaded: {items.data.length}</span>\n      <span class=\"has-next-page\">{items.next_page_url ? 'true' : 'false'}</span>\n\n      {#if items.next_page_url}\n        <Link href={items.next_page_url} only={['items']} preserveState preserveScroll preserveUrl class=\"load-more\">\n          Load More\n        </Link>\n      {/if}\n\n      {#if items.next_page_url}\n        <button on:click={loadMore} class=\"load-more-router\">Load More Router</button>\n      {/if}\n    </div>\n  {/if}\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/PropUpdate.svelte",
    "content": "<script lang=\"ts\">\n  import { Link } from '@inertiajs/svelte'\n\n  let href = '/sleep'\n\n  const changeUrl = () => {\n    href = '/something-else'\n  }\n</script>\n\n<div>\n  <button on:click={changeUrl}>Change URL</button>\n  <Link {href} class=\"get\">The Link</Link>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/Reactivity.svelte",
    "content": "<script lang=\"ts\">\n  import { Link } from '@inertiajs/svelte'\n  import type { CacheForOption, LinkPrefetchOption, Method } from '@inertiajs/core'\n\n  let method: Method = 'get'\n  let href = '/dump/get'\n  let data = { foo: 'bar' }\n  let headers = { 'X-Custom-Header': 'value' }\n  let prefetch: boolean | LinkPrefetchOption = false\n  let cacheFor: CacheForOption = 0\n\n  function change() {\n    method = 'post'\n    href = '/dump/post'\n    data = { foo: 'baz' }\n    headers = { 'X-Custom-Header': 'new-value' }\n  }\n\n  function enablePrefetch() {\n    prefetch = 'hover'\n    cacheFor = '1s'\n  }\n</script>\n\n<div>\n  <span class=\"text\">\n    This page demonstrates reactivity in Inertia links. Click the button to change the link properties.\n  </span>\n\n  <Link {method} {href} {data} {headers}>Submit</Link>\n\n  <button on:click={change}>Change Link Props</button>\n\n  <Link href=\"/dump/get\" {prefetch} {cacheFor}>Prefetch Link</Link>\n\n  <button on:click={enablePrefetch}>Enable Prefetch (1s cache)</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/Replace.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <span class=\"text\">This is the links page that demonstrates replace on Links</span>\n\n  <a href=\"/dump/get\" use:inertia={{ replace: true }} class=\"replace\">[State] Replace: true</a>\n  <a href=\"/dump/get\" use:inertia={{ replace: false }} class=\"replace-false\">[State] Replace: false</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/ScrollRegionList.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  export { default as layout } from '@/Layouts/WithScrollRegion.svelte'\n</script>\n\n<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n  import type { VisitHelperOptions } from '@inertiajs/core'\n\n  export let user_id: number | undefined = undefined\n\n  const users = Array.from({ length: 10 }, (_, i) => ({ id: i + 1, name: `User ${i + 1}` }))\n\n  const navigate = (id: number, options: VisitHelperOptions = {}) => {\n    router.get(`/links/scroll-region-list/user/${id}`, {}, options)\n  }\n</script>\n\n<div>\n  <span class=\"text\">Scrollable list with scroll region</span>\n  <div class=\"user-text\">Clicked user: {user_id || 'none'}</div>\n\n  {#each users as user (user.id)}\n    <div style=\"padding: 20px; border-bottom: 1px solid #ccc\">\n      <div style=\"margin-bottom: 10px; width: 500px\">{user.name}</div>\n      <button on:click={() => navigate(user.id)}>Default</button>\n      <button on:click={() => navigate(user.id, { preserveScroll: true })}> Preserve True </button>\n      <button on:click={() => navigate(user.id, { preserveScroll: false })}> Preserve False </button>\n    </div>\n  {/each}\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Links/UrlFragments.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n\n  let documentScrollTop = 0\n  let documentScrollLeft = 0\n\n  const handleScrollEvent = () => {\n    documentScrollTop = document.documentElement.scrollTop\n    documentScrollLeft = document.documentElement.scrollLeft\n  }\n</script>\n\n<svelte:document on:scroll={handleScrollEvent} />\n\n<div>\n  <span class=\"text\">This is the links page that demonstrates url fragment behaviour</span>\n  <div style=\"width: 200vw; height: 200vh; margin-top: 50vh\">\n    <!-- prettier-ignore -->\n    <button on:click={handleScrollEvent}>Update scroll positions</button>\n    <div class=\"document-position\">Document scroll position is {documentScrollLeft} & {documentScrollTop}</div>\n    <a href=\"/links/url-fragments#target\" use:inertia class=\"basic\">Basic link</a>\n    <a href=\"#target\" use:inertia class=\"fragment\">Fragment link</a>\n    <a href=\"/links/url-fragments#non-existent-fragment\" use:inertia class=\"non-existent-fragment\"\n      >Non-existent fragment link</a\n    >\n\n    <div id=\"target\">This is the element with id 'target'</div>\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/MatchPropsOnKey.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  interface ComponentProps {\n    foo: {\n      data: { id: number; name: string }[]\n      companies: { id: number; name: string }[]\n      teams: { id: number; name: string }[]\n      page: number\n      per_page: number\n      meta: { label: string }\n    }\n    bar: number[]\n    baz: number[]\n  }\n\n  export let foo: ComponentProps['foo']\n  export let bar: ComponentProps['bar']\n  export let baz: ComponentProps['baz']\n\n  let page = foo.page\n\n  const reloadIt = () => {\n    router.visit('/match-props-on-key', {\n      data: {\n        page,\n      },\n      only: ['foo', 'baz'],\n      onSuccess(visit) {\n        // TODO: Refactor 'unknown' and make Page<ComponentProps> work\n        page = (visit.props as unknown as { foo: { page: number } }).foo.page\n      },\n    })\n  }\n\n  const getFresh = () => {\n    page = 0\n    router.visit('/match-props-on-key', {\n      reset: ['foo', 'baz'],\n    })\n  }\n</script>\n\n<div>bar count is {bar.length}</div>\n<div>baz count is {baz.length}</div>\n<div>foo.data count is {foo.data.length}</div>\n<div>first foo.data name is {foo.data[0].name}</div>\n<div>last foo.data name is {foo.data[foo.data.length - 1].name}</div>\n<div>foo.companies count is {foo.companies.length}</div>\n<div>first foo.companies name is {foo.companies[0].name}</div>\n<div>last foo.companies name is {foo.companies[foo.companies.length - 1].name}</div>\n<div>foo.teams count is {foo.teams.length}</div>\n<div>first foo.teams name is {foo.teams[0].name}</div>\n<div>last foo.teams name is {foo.teams[foo.teams.length - 1].name}</div>\n<div>foo.page is {foo.page}</div>\n<div>foo.per_page is {foo.per_page}</div>\n<div>foo.meta.label is {foo.meta.label}</div>\n<button on:click={reloadIt}>Reload</button>\n<button on:click={getFresh}>Get Fresh</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/MergeNestedProps.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  export let users: { data: { id: number; name: string }[]; meta: { page: number; perPage: number } } = {\n    data: [],\n    meta: { page: 1, perPage: 10 },\n  }\n\n  const loadMore = () => {\n    router.reload({\n      only: ['users'],\n      data: { page: users.meta.page + 1 },\n    })\n  }\n</script>\n\n<div>\n  <p id=\"users\">{users.data.map((user) => user.name).join(', ')}</p>\n  <p id=\"meta\">Page: {users.meta.page}, Per Page: {users.meta.perPage}</p>\n  <button on:click={loadMore}>Load More</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/MergeProps.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  export let foo: number[] = []\n  export let bar: number[] = []\n\n  const reloadIt = () => {\n    router.reload({\n      only: ['foo'],\n    })\n  }\n\n  const getFresh = () => {\n    router.reload({\n      reset: ['foo'],\n    })\n  }\n</script>\n\n<div>bar count is {bar.length}</div>\n<div>foo count is {foo.length}</div>\n<button on:click={reloadIt}>Reload</button>\n<button on:click={getFresh}>Get Fresh</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/NavigateNonInertia.svelte",
    "content": "<script lang=\"ts\">\n  function navigate(e: MouseEvent) {\n    e.preventDefault()\n    window.history.replaceState({ foo: {} }, '')\n    window.location.href = '/non-inertia'\n  }\n</script>\n\n<div>\n  <h1>Navigate Non-Inertia</h1>\n  <p>\n    <a href=\"/non-inertia\" on:click={navigate}>Go to non-Inertia page</a>\n  </p>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/NetworkError.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n  import { onMount } from 'svelte'\n\n  let error = false\n\n  onMount(() => {\n    return router.on('exception', () => {\n      error = true\n      return false\n    })\n  })\n\n  function makeRequest() {\n    error = false\n    router.get('/network-error')\n  }\n</script>\n\n<div>\n  <h1>Network Error</h1>\n  {#if error}\n    <div id=\"network-error\">Network error occurred</div>\n  {/if}\n  <button id=\"make-request\" on:click={makeRequest}>Make Request</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/ClientSideVisit.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  export let foo: string\n  export let bar: string\n\n  const pushWithoutPreserving = () => {\n    router.push({\n      url: '/once-props/client-side-visit',\n      component: 'OnceProps/ClientSideVisit',\n      props: { bar: 'bar-updated' },\n    })\n  }\n\n  const pushWithOnceProps = () => {\n    router.push({\n      url: '/once-props/client-side-visit',\n      component: 'OnceProps/ClientSideVisit',\n      props: (currentProps, onceProps) => ({ ...onceProps, bar: 'bar-updated' }),\n    })\n  }\n</script>\n\n<p id=\"foo\">Foo: {foo}</p>\n<p id=\"bar\">Bar: {bar}</p>\n<button on:click={pushWithoutPreserving}>Push without preserving</button>\n<button on:click={pushWithOnceProps}>Push with once props</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/CustomKeyPageA.svelte",
    "content": "<script lang=\"ts\">\n  import { Link } from '@inertiajs/svelte'\n\n  export let userPermissions: string\n  export let bar: string\n</script>\n\n<p id=\"permissions\">Permissions: {userPermissions}</p>\n<p id=\"bar\">Bar: {bar}</p>\n<Link href=\"/once-props/custom-key/b\">Go to Custom Key Page B</Link>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/CustomKeyPageB.svelte",
    "content": "<script lang=\"ts\">\n  import { Link } from '@inertiajs/svelte'\n\n  export let permissions: string\n  export let bar: string\n</script>\n\n<p id=\"permissions\">Permissions: {permissions}</p>\n<p id=\"bar\">Bar: {bar}</p>\n<Link href=\"/once-props/custom-key/a\">Go to Custom Key Page A</Link>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/DeferredPageA.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred, Link } from '@inertiajs/svelte'\n\n  export let foo: { text: string } | undefined\n  export let bar: string\n</script>\n\n<Deferred data=\"foo\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading foo...</div>\n  </svelte:fragment>\n\n  <p id=\"foo\">Foo: {foo?.text}</p>\n</Deferred>\n\n<p id=\"bar\">Bar: {bar}</p>\n\n<Link href=\"/once-props/deferred/b\">Go to Deferred Page B</Link>\n<Link href=\"/once-props/deferred/c\" prefetch=\"mount\">Go to Deferred Page C</Link>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/DeferredPageB.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred, Link } from '@inertiajs/svelte'\n\n  export let foo: { text: string } | undefined\n  export let bar: string\n</script>\n\n<Deferred data=\"foo\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading foo...</div>\n  </svelte:fragment>\n\n  <p id=\"foo\">Foo: {foo?.text}</p>\n</Deferred>\n\n<p id=\"bar\">Bar: {bar}</p>\n\n<Link href=\"/once-props/deferred/a\">Go to Deferred Page A</Link>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/DeferredPageC.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred, Link } from '@inertiajs/svelte'\n\n  export let foo: { text: string } | undefined\n  export let bar: string\n</script>\n\n<Deferred data=\"foo\">\n  <svelte:fragment slot=\"fallback\">\n    <div>Loading foo...</div>\n  </svelte:fragment>\n\n  <p id=\"foo\">Foo: {foo?.text}</p>\n</Deferred>\n\n<p id=\"bar\">Bar: {bar}</p>\n\n<Link href=\"/once-props/deferred/a\">Go to Deferred Page A</Link>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/MergePageA.svelte",
    "content": "<script lang=\"ts\">\n  import { Link, router } from '@inertiajs/svelte'\n\n  export let items: string[]\n  export let bar: string\n</script>\n\n<p id=\"items\">Items count: {items.length}</p>\n<p id=\"bar\">Bar: {bar}</p>\n<Link href=\"/once-props/merge/b\">Go to Merge Page B</Link>\n<button on:click={() => router.reload({ only: ['items'] })}>Load more items</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/MergePageB.svelte",
    "content": "<script lang=\"ts\">\n  import { Link, router } from '@inertiajs/svelte'\n\n  export let items: string[]\n  export let bar: string\n</script>\n\n<p id=\"items\">Items count: {items.length}</p>\n<p id=\"bar\">Bar: {bar}</p>\n<Link href=\"/once-props/merge/a\">Go to Merge Page A</Link>\n<button on:click={() => router.reload({ only: ['items'] })}>Load more items</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/OptionalPageA.svelte",
    "content": "<script lang=\"ts\">\n  import { Link, router } from '@inertiajs/svelte'\n\n  export let foo: string | undefined\n  export let bar: string\n</script>\n\n<p id=\"foo\">Foo: {foo ?? 'not loaded'}</p>\n<p id=\"bar\">Bar: {bar}</p>\n<Link href=\"/once-props/optional/b\">Go to Optional Page B</Link>\n<button on:click={() => router.reload({ only: ['foo'] })}>Load foo</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/OptionalPageB.svelte",
    "content": "<script lang=\"ts\">\n  import { Link, router } from '@inertiajs/svelte'\n\n  export let foo: string | undefined\n  export let bar: string\n</script>\n\n<p id=\"foo\">Foo: {foo ?? 'not loaded'}</p>\n<p id=\"bar\">Bar: {bar}</p>\n<Link href=\"/once-props/optional/a\">Go to Optional Page A</Link>\n<button on:click={() => router.reload({ only: ['foo'] })}>Load foo</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/PageA.svelte",
    "content": "<script lang=\"ts\">\n  import { Link, router } from '@inertiajs/svelte'\n\n  export let foo: string\n  export let bar: string\n</script>\n\n<p id=\"foo\">Foo: {foo}</p>\n<p id=\"bar\">Bar: {bar}</p>\n<Link href=\"/once-props/page-b\">Go to Page B</Link>\n<Link href=\"/once-props/page-c\">Go to Page C</Link>\n<Link href=\"/once-props/page-d\" prefetch=\"mount\">Go to Page D</Link>\n<Link href=\"/once-props/page-e\" prefetch=\"mount\" cacheFor={1000}>Go to Page E (short cache)</Link>\n<button on:click={() => router.reload({ only: ['foo'] })}>Reload (only foo)</button>\n<button on:click={() => router.replaceProp('foo', 'replaced-foo')}>Replace foo</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/PageB.svelte",
    "content": "<script lang=\"ts\">\n  import { Link, router } from '@inertiajs/svelte'\n\n  export let foo: string\n  export let bar: string\n</script>\n\n<p id=\"foo\">Foo: {foo}</p>\n<p id=\"bar\">Bar: {bar}</p>\n<Link href=\"/once-props/page-a\">Go to Page A</Link>\n<button on:click={() => router.reload({ only: ['foo'] })}>Reload (only foo)</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/PageC.svelte",
    "content": "<script lang=\"ts\">\n  import { Link } from '@inertiajs/svelte'\n</script>\n\n<Link href=\"/once-props/page-a\">Go to Page A</Link>\n<Link href=\"/once-props/page-b\">Go to Page B</Link>\n<Link href=\"/once-props/page-d\" prefetch=\"mount\">Go to Page D</Link>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/PageD.svelte",
    "content": "<script lang=\"ts\">\n  export let foo: string\n  export let bar: string\n</script>\n\n<p id=\"foo\">Foo: {foo}</p>\n<p id=\"bar\">Bar: {bar}</p>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/PageE.svelte",
    "content": "<script lang=\"ts\">\n  export let foo: string\n  export let bar: string\n</script>\n\n<p id=\"foo\">Foo: {foo}</p>\n<p id=\"bar\">Bar: {bar}</p>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/PartialReloadA.svelte",
    "content": "<script lang=\"ts\">\n  import { Link, router } from '@inertiajs/svelte'\n\n  export let foo: string\n  export let bar: string\n</script>\n\n<p id=\"foo\">Foo: {foo}</p>\n<p id=\"bar\">Bar: {bar}</p>\n<Link href=\"/once-props/partial-reload/b\">Go to Partial Reload B</Link>\n<button on:click={() => router.reload({ only: ['foo'] })}>Reload (only foo)</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/PartialReloadB.svelte",
    "content": "<script lang=\"ts\">\n  import { Link } from '@inertiajs/svelte'\n\n  export let foo: string\n  export let bar: string\n</script>\n\n<p id=\"foo\">Foo: {foo}</p>\n<p id=\"bar\">Bar: {bar}</p>\n<Link href=\"/once-props/partial-reload/a\">Go to Partial Reload A</Link>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/SlowDeferredPageA.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred, Link } from '@inertiajs/svelte'\n\n  export let foo: string | undefined\n  export let bar: string\n</script>\n\n<Deferred data=\"foo\">\n  <svelte:fragment slot=\"fallback\">\n    <div id=\"foo-loading\">Loading foo...</div>\n  </svelte:fragment>\n\n  <p id=\"foo\">Foo: {foo}</p>\n</Deferred>\n\n<p id=\"bar\">Bar: {bar}</p>\n\n<Link href=\"/once-props/slow-deferred/b\">Go to Page B</Link>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/SlowDeferredPageB.svelte",
    "content": "<script lang=\"ts\">\n  import { Deferred, Link } from '@inertiajs/svelte'\n\n  export let foo: string | undefined\n  export let bar: string\n</script>\n\n<Deferred data=\"foo\">\n  <svelte:fragment slot=\"fallback\">\n    <div id=\"foo-loading\">Loading foo...</div>\n  </svelte:fragment>\n\n  <p id=\"foo\">Foo: {foo}</p>\n</Deferred>\n\n<p id=\"bar\">Bar: {bar}</p>\n\n<Link href=\"/once-props/slow-deferred/a\">Go to Page A</Link>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/TtlPageA.svelte",
    "content": "<script lang=\"ts\">\n  import { Link, router } from '@inertiajs/svelte'\n\n  export let foo: string\n  export let bar: string\n</script>\n\n<p id=\"foo\">Foo: {foo}</p>\n<p id=\"bar\">Bar: {bar}</p>\n<Link href=\"/once-props/ttl/b\">Go to TTL Page B</Link>\n<Link href=\"/once-props/ttl/c\" prefetch=\"mount\">Go to TTL Page C</Link>\n<button on:click={() => router.reload({ only: ['foo'] })}>Reload foo</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/TtlPageB.svelte",
    "content": "<script lang=\"ts\">\n  import { Link } from '@inertiajs/svelte'\n\n  export let foo: string\n  export let bar: string\n</script>\n\n<p id=\"foo\">Foo: {foo}</p>\n<p id=\"bar\">Bar: {bar}</p>\n<Link href=\"/once-props/ttl/a\">Go to TTL Page A</Link>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/OnceProps/TtlPageC.svelte",
    "content": "<script lang=\"ts\">\n  import { Link } from '@inertiajs/svelte'\n\n  export let foo: string\n  export let bar: string\n</script>\n\n<p id=\"foo\">Foo: {foo}</p>\n<p id=\"bar\">Bar: {bar}</p>\n<Link href=\"/once-props/ttl/a\">Go to TTL Page A</Link>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageA.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  import NestedLayout from '@/Layouts/NestedLayout.svelte'\n  import SiteLayout from '@/Layouts/SiteLayout.svelte'\n  import type { ComponentType } from 'svelte'\n\n  export const layout = (\n    h: (component: ComponentType, children: ComponentType[]) => ComponentType,\n    page: ComponentType,\n  ) => {\n    return h(SiteLayout, [h(NestedLayout, [page])])\n  }\n</script>\n\n<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <span class=\"text\">Nested Persistent Layout - Page A</span>\n  <a href=\"/persistent-layouts/render-function/nested/page-b\" use:inertia>Page B</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageB.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  import NestedLayout from '@/Layouts/NestedLayout.svelte'\n  import SiteLayout from '@/Layouts/SiteLayout.svelte'\n  import type { ComponentType } from 'svelte'\n\n  export const layout = (\n    h: (component: ComponentType, children: ComponentType[]) => ComponentType,\n    page: ComponentType,\n  ) => {\n    return h(SiteLayout, [h(NestedLayout, [page])])\n  }\n</script>\n\n<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <span class=\"text\">Nested Persistent Layout - Page B</span>\n  <a href=\"/persistent-layouts/render-function/nested/page-a\" use:inertia>Page A</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageA.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  import SiteLayout from '@/Layouts/SiteLayout.svelte'\n  import type { ComponentType } from 'svelte'\n\n  export const layout = (\n    h: (component: ComponentType, children: ComponentType[]) => ComponentType,\n    page: ComponentType,\n  ) => h(SiteLayout, [page])\n</script>\n\n<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <span class=\"text\">Simple Persistent Layout - Page A</span>\n  <a href=\"/persistent-layouts/render-function/simple/page-b\" use:inertia>Page B</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageB.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  import SiteLayout from '@/Layouts/SiteLayout.svelte'\n  import type { ComponentType } from 'svelte'\n\n  export const layout = (\n    h: (component: ComponentType, children: ComponentType[]) => ComponentType,\n    page: ComponentType,\n  ) => h(SiteLayout, [page])\n</script>\n\n<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <span class=\"text\">Simple Persistent Layout - Page B</span>\n  <a href=\"/persistent-layouts/render-function/simple/page-a\" use:inertia>Page A</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  import NestedLayout from '@/Layouts/NestedLayout.svelte'\n  import SiteLayout from '@/Layouts/SiteLayout.svelte'\n\n  export const layout = [SiteLayout, NestedLayout]\n</script>\n\n<script lang=\"ts\">\n  import { inertia, page } from '@inertiajs/svelte'\n\n  window._inertia_page_props = $page.props\n</script>\n\n<div>\n  <span class=\"text\">Nested Persistent Layout - Page A</span>\n  <a href=\"/persistent-layouts/shorthand/nested/page-b\" use:inertia>Page B</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  import NestedLayout from '@/Layouts/NestedLayout.svelte'\n  import SiteLayout from '@/Layouts/SiteLayout.svelte'\n\n  export const layout = [SiteLayout, NestedLayout]\n</script>\n\n<script lang=\"ts\">\n  import { inertia, page } from '@inertiajs/svelte'\n\n  window._inertia_page_props = $page.props\n</script>\n\n<div>\n  <span class=\"text\">Nested Persistent Layout - Page B</span>\n  <a href=\"/persistent-layouts/shorthand/nested/page-a\" use:inertia>Page A</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  import SiteLayout from '@/Layouts/SiteLayout.svelte'\n\n  export const layout = SiteLayout\n</script>\n\n<script lang=\"ts\">\n  import { inertia, page } from '@inertiajs/svelte'\n\n  window._inertia_page_props = $page.props\n</script>\n\n<div>\n  <span class=\"text\">Simple Persistent Layout - Page A</span>\n  <a href=\"/persistent-layouts/shorthand/simple/page-b\" use:inertia>Page B</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  import SiteLayout from '@/Layouts/SiteLayout.svelte'\n\n  export const layout = SiteLayout\n</script>\n\n<script lang=\"ts\">\n  import { inertia, page } from '@inertiajs/svelte'\n\n  window._inertia_page_props = $page.props\n</script>\n\n<div>\n  <span class=\"text\">Simple Persistent Layout - Page B</span>\n  <a href=\"/persistent-layouts/shorthand/simple/page-a\" use:inertia>Page A</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Poll/Hook.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia, usePoll } from '@inertiajs/svelte'\n\n  usePoll(500, {\n    only: ['custom_prop'],\n    onFinish() {\n      console.log('hook poll finished')\n    },\n  })\n</script>\n\n<a href=\"/\" use:inertia>Home</a>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Poll/HookManual.svelte",
    "content": "<script lang=\"ts\">\n  import { usePoll } from '@inertiajs/svelte'\n\n  const { start, stop } = usePoll(\n    500,\n    {\n      only: ['custom_prop'],\n      onFinish() {\n        console.log('hook poll finished')\n      },\n    },\n    {\n      autoStart: false,\n    },\n  )\n</script>\n\n<button on:click={() => start()}>Start</button>\n<button on:click={() => stop()}>Stop</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Poll/RouterManual.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  const { start, stop } = router.poll(\n    500,\n    {\n      only: ['custom_prop'],\n      onFinish() {\n        console.log('hook poll finished')\n      },\n    },\n    {\n      autoStart: false,\n    },\n  )\n</script>\n\n<button on:click={() => start()}>Start</button>\n<button on:click={() => stop()}>Stop</button>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Poll/UnchangedData.svelte",
    "content": "<script lang=\"ts\">\n  import { usePoll } from '@inertiajs/svelte'\n  import { onMount } from 'svelte'\n\n  let replaceStateCalls = 0\n  let pollsFinished = 0\n\n  onMount(() => {\n    const original = window.history.replaceState.bind(window.history)\n    window.history.replaceState = function (...args) {\n      replaceStateCalls++\n      return original(...args)\n    }\n  })\n\n  usePoll(500, {\n    only: ['custom_prop'],\n    onFinish: () => pollsFinished++,\n  })\n</script>\n\n<div>\n  <p>replaceState calls: <span class=\"replaceStateCalls\">{replaceStateCalls}</span></p>\n  <p>polls finished: <span class=\"pollsFinished\">{pollsFinished}</span></p>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Prefetch/AfterError.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  const prefetchPage = () => {\n    router.prefetch('/prefetch/swr/1', { method: 'get' }, { cacheFor: 5000 })\n  }\n\n  const visitPage = () => {\n    router.visit('/prefetch/swr/1')\n  }\n\n  const prefetchNonInertia = () => {\n    router.prefetch('/non-inertia', { method: 'get' }, { cacheFor: 5000 })\n  }\n\n  const visitNonInertia = () => {\n    router.visit('/non-inertia')\n  }\n</script>\n\n<div>\n  <button on:click={prefetchPage}>Prefetch Page</button>\n  <button on:click={visitPage}>Visit Page</button>\n  <button on:click={prefetchNonInertia}>Prefetch Non-Inertia</button>\n  <button on:click={visitNonInertia}>Visit Non-Inertia</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Prefetch/Form.svelte",
    "content": "<script lang=\"ts\">\n  import { Link, page, useForm } from '@inertiajs/svelte'\n\n  const form = useForm({})\n\n  const submitToSame = () => {\n    $form.post('/prefetch/form')\n  }\n\n  const submitToOther = () => {\n    $form.post('/prefetch/redirect-back')\n  }\n</script>\n\n<div>\n  <p>\n    Random Value: <span class=\"random-value\">{$page.props.randomValue}</span>\n  </p>\n  <button on:click={submitToSame}>Submit to Same URL</button>\n  <button on:click={submitToOther}>Submit to Other URL</button>\n  <Link href=\"/prefetch/test-page\">Back to Test Page</Link>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Prefetch/Page.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  export { default as layout } from '@/Layouts/Prefetch.svelte'\n</script>\n\n<script lang=\"ts\">\n  export let pageNumber: number\n  export let lastLoaded: number\n</script>\n\n<div>This is page {pageNumber}</div>\n<div>\n  Last loaded at <span id=\"last-loaded\">{lastLoaded}</span>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Prefetch/PreserveState.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  export let page: number\n  export let timestamp: number\n\n  const prefetchPage2 = () => {\n    router.prefetch('/prefetch/preserve-state', { method: 'get', data: { page: 2 } }, { cacheFor: '30s' })\n  }\n\n  const loadPage2WithoutPreserveState = () => {\n    router.get('/prefetch/preserve-state', { page: 2 }, { preserveState: false })\n  }\n\n  const loadPage2WithPreserveState = () => {\n    router.get('/prefetch/preserve-state', { page: 2 }, { preserveState: true })\n  }\n</script>\n\n<div>\n  <div>Current Page: {page}</div>\n  <div>Timestamp: {timestamp}</div>\n\n  <h3>Prefetch:</h3>\n  <button on:click={prefetchPage2}>Prefetch Page 2</button>\n\n  <h3>Load (should use cache if prefetched):</h3>\n  <button on:click={loadPage2WithoutPreserveState}>Load Page 2 (preserveState: false)</button>\n  <button on:click={loadPage2WithPreserveState}>Load Page 2 (preserveState: true)</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Prefetch/SWR.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  export { default as layout } from '@/Layouts/SWR.svelte'\n</script>\n\n<script lang=\"ts\">\n  export let pageNumber: number\n  export let lastLoaded: number\n</script>\n\n<div>This is page {pageNumber}</div>\n<div>\n  Last loaded at <span id=\"last-loaded\">{lastLoaded}</span>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Prefetch/Tags.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia, router, useForm } from '@inertiajs/svelte'\n  export let pageNumber\n  export let lastLoaded\n  export let propType: string\n\n  const form = useForm({\n    name: '',\n  })\n\n  function flushUserTags() {\n    router.flushByCacheTags(propType === 'string' ? 'user' : ['user'])\n  }\n\n  function flushUserProductTags() {\n    router.flushByCacheTags(['user', 'product'])\n  }\n\n  function programmaticPrefetch() {\n    router.prefetch('/prefetch/tags/2', { method: 'get' }, { cacheTags: propType === 'string' ? 'user' : ['user'] })\n    router.prefetch(\n      '/prefetch/tags/3',\n      { method: 'get' },\n      { cacheFor: '1m', cacheTags: propType === 'string' ? 'product' : ['product'] },\n    )\n    router.prefetch(\n      '/prefetch/tags/6',\n      { method: 'get' },\n      { cacheFor: '1m' }, // No tags (untagged)\n    )\n  }\n\n  function submitWithUserInvalidation() {\n    $form.post('/dump/post', {\n      invalidateCacheTags: propType === 'string' ? 'user' : ['user'],\n    })\n  }\n</script>\n\n<div>\n  <div id=\"links\">\n    <a href=\"/prefetch/tags/1\" use:inertia={{ prefetch: 'hover', cacheTags: ['user', 'profile'] }}> User Page 1 </a>\n    <a href=\"/prefetch/tags/2\" use:inertia={{ prefetch: 'hover', cacheTags: ['user', 'settings'] }}> User Page 2 </a>\n    <a href=\"/prefetch/tags/3\" use:inertia={{ prefetch: 'hover', cacheTags: ['product', 'catalog'] }}>\n      Product Page 3\n    </a>\n    <a href=\"/prefetch/tags/4\" use:inertia={{ prefetch: 'hover', cacheTags: ['product', 'details'] }}>\n      Product Page 4\n    </a>\n    <a\n      href=\"/prefetch/tags/5\"\n      use:inertia={{ prefetch: 'hover', cacheTags: propType === 'string' ? 'admin' : ['admin'] }}\n    >\n      Admin Page 5\n    </a>\n    <a href=\"/prefetch/tags/6\" use:inertia={{ prefetch: 'hover' }}> Untagged Page 6 </a>\n  </div>\n  <div id=\"controls\">\n    <button id=\"flush-user\" on:click={flushUserTags}> Flush User Tags </button>\n    <button id=\"flush-user-product\" on:click={flushUserProductTags}> Flush User + Product Tags </button>\n    <button id=\"programmatic-prefetch\" on:click={programmaticPrefetch}> Programmatic Prefetch </button>\n  </div>\n\n  <div id=\"form-section\">\n    <h3>Form Test</h3>\n    <form on:submit|preventDefault>\n      <input id=\"form-name\" bind:value={$form.name} type=\"text\" placeholder=\"Enter name\" />\n      <button id=\"submit-invalidate-user\" on:click={submitWithUserInvalidation}> Submit (Invalidate User) </button>\n    </form>\n  </div>\n\n  <div>\n    <div>This is tags page {pageNumber}</div>\n    <div>\n      Last loaded at <span id=\"last-loaded\">{lastLoaded}</span>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Prefetch/TestPage.svelte",
    "content": "<script lang=\"ts\">\n  import { Link } from '@inertiajs/svelte'\n</script>\n\n<div>\n  <Link href=\"/prefetch/form\" prefetch>Go to Prefetch Form</Link>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Prefetch/Wayfinder.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n  import { onMount } from 'svelte'\n\n  let isPrefetched = false\n  let isPrefetching = false\n\n  const wayfinderUrl = (): {\n    url: string\n    method: 'get'\n  } => ({\n    url: '/prefetch/swr/4',\n    method: 'get',\n  })\n\n  const checkStatus = () => {\n    isPrefetched = !!router.getCached(wayfinderUrl())\n    isPrefetching = !!router.getPrefetching(wayfinderUrl())\n  }\n\n  const testPrefetch = () => {\n    router.prefetch(wayfinderUrl(), {\n      onPrefetching: () => {\n        isPrefetching = true\n      },\n      onPrefetched: () => {\n        isPrefetching = false\n        setTimeout(checkStatus)\n      },\n    })\n  }\n\n  const testFlush = () => {\n    router.flush(wayfinderUrl())\n    checkStatus()\n  }\n\n  const flushAll = () => {\n    router.flushAll()\n    checkStatus()\n  }\n\n  onMount(checkStatus)\n</script>\n\n<div>\n  <p>\n    Is Prefetched: <span id=\"is-prefetched\">{isPrefetched}</span>\n  </p>\n  <p>\n    Is Prefetching: <span id=\"is-prefetching\">{isPrefetching}</span>\n  </p>\n\n  <button on:click={testPrefetch} id=\"test-prefetch\">Test prefetch</button>\n  <button on:click={testFlush} id=\"test-flush\">Test flush</button>\n  <button on:click={flushAll} id=\"flush-all\">Flush all</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/PreserveEqualProps.svelte",
    "content": "<script lang=\"ts\">\n  import { config, Link } from '@inertiajs/svelte'\n\n  export let nestedA: { count: number }\n  export let nestedB: { date: number }\n\n  let effectACount = 1\n  let effectBCount = 1\n\n  let previousNestedA: { count: number } = nestedA\n  let previousNestedB: { date: number } = nestedB\n\n  $: if (nestedA !== previousNestedA) {\n    effectACount = effectACount + 1\n    previousNestedA = nestedA\n  }\n\n  $: if (nestedB !== previousNestedB) {\n    effectBCount = effectBCount + 1\n    previousNestedB = nestedB\n  }\n\n  function enable() {\n    config.set('future.preserveEqualProps', true)\n  }\n</script>\n\n<div>\n  <h1>Preserve Equal Props</h1>\n  <p id=\"count-a\">Count A: {nestedA.count}</p>\n  <p id=\"date-b\">Date B: {nestedB.date}</p>\n  <p id=\"effect-a\">Effect A Count: {effectACount}</p>\n  <p id=\"effect-b\">Effect B Count: {effectBCount}</p>\n  <Link method=\"post\" href=\"/preserve-equal-props/back\">Submit and redirect back</Link>\n  <button on:click={enable}>Enable</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/ProgressComponent.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  declare global {\n    interface Window {\n      progressTests: unknown[]\n    }\n  }\n</script>\n\n<script lang=\"ts\">\n  import { progress } from '@inertiajs/svelte'\n\n  window.progressTests = []\n\n  let logs: string[] = []\n\n  const log = (...args: unknown[]) => {\n    const message = args.join(' ')\n    window.progressTests.push(...args)\n    logs = [...logs, message]\n  }\n\n  const testStart = () => {\n    progress.start()\n    log('started')\n  }\n\n  const testSet25 = () => {\n    progress.set(0.25)\n    log('set 25%')\n  }\n\n  const testSet50 = () => {\n    progress.set(0.5)\n    log('set 50%')\n  }\n\n  const testSet75 = () => {\n    progress.set(0.75)\n    log('set 75%')\n  }\n\n  const testFinish = () => {\n    progress.finish()\n    log('finished')\n  }\n\n  const testReset = () => {\n    progress.reset()\n    log('reset')\n  }\n\n  const testRemove = () => {\n    progress.remove()\n    log('removed')\n  }\n\n  const testHide = () => {\n    progress.hide()\n    log('hidden')\n  }\n\n  const testReveal = () => {\n    progress.reveal()\n    log('revealed')\n  }\n\n  const testIsStarted = () => {\n    log('isStarted:', progress.isStarted())\n  }\n\n  const testGetStatus = () => {\n    log('getStatus:', progress.getStatus())\n  }\n\n  const clearLogs = () => {\n    window.progressTests = []\n    logs = []\n  }\n</script>\n\n<div>\n  <h1>Progress API Test</h1>\n\n  <div>\n    <button on:click={testStart}>Start</button>\n    <button on:click={testSet25}>Set 25%</button>\n    <button on:click={testSet50}>Set 50%</button>\n    <button on:click={testSet75}>Set 75%</button>\n    <button on:click={testFinish}>Finish</button>\n  </div>\n\n  <div>\n    <button on:click={testReset}>Reset</button>\n    <button on:click={testRemove}>Remove</button>\n    <button on:click={testHide}>Hide</button>\n    <button on:click={testReveal}>Reveal</button>\n  </div>\n\n  <div>\n    <button on:click={testIsStarted}>Is Started</button>\n    <button on:click={testGetStatus}>Get Status</button>\n    <button on:click={clearLogs}>Clear</button>\n  </div>\n\n  <div>\n    Logs: <span id=\"logs\">{logs.join(', ')}</span>\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Reload/Concurrent.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  export let foo: string | undefined\n  export let bar: string | undefined\n\n  function reloadBothProps() {\n    router.reload({ only: ['foo'] })\n    setTimeout(() => router.reload({ only: ['bar'] }), 50)\n  }\n</script>\n\n<div>\n  <div id=\"foo\">Foo: {foo}</div>\n  <div id=\"bar\">Bar: {bar}</div>\n\n  <button on:click={reloadBothProps}>Reload both props</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Reload/ConcurrentWithData.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  export let foo: string | undefined\n  export let bar: string | undefined\n  export let timeframe: string | undefined\n\n  function reloadBothPropsWithData() {\n    router.reload({ only: ['foo'], data: { timeframe: 'week' } })\n    setTimeout(() => router.reload({ only: ['bar'], data: { timeframe: 'week' } }), 50)\n  }\n</script>\n\n<div>\n  <div id=\"foo\">Foo: {foo}</div>\n  <div id=\"bar\">Bar: {bar}</div>\n  <div id=\"timeframe\">Timeframe: {timeframe}</div>\n\n  <button on:click={reloadBothPropsWithData}>Reload both props with data</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Remember/Components/ComponentA.svelte",
    "content": "<script lang=\"ts\">\n  import { useRemember } from '@inertiajs/svelte'\n\n  let untracked = ''\n\n  const data = useRemember(\n    {\n      name: '',\n      remember: false,\n    },\n    'Example/ComponentA',\n  )\n</script>\n\n<div {...$$restProps}>\n  <span>This component uses a string 'key' for the remember functionality.</span>\n  <label>\n    Full Name\n    <input type=\"text\" class=\"a-name\" name=\"full_name\" bind:value={$data.name} />\n  </label>\n  <label>\n    Remember Me\n    <input type=\"checkbox\" class=\"a-remember\" name=\"remember\" bind:checked={$data.remember} />\n  </label>\n  <label>\n    Remember Me\n    <input type=\"text\" class=\"a-untracked\" name=\"untracked\" bind:value={untracked} />\n  </label>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Remember/Components/ComponentB.svelte",
    "content": "<script lang=\"ts\">\n  import { useRemember } from '@inertiajs/svelte'\n\n  let untracked = ''\n\n  const data = useRemember(\n    {\n      name: '',\n      remember: false,\n    },\n    'Example/ComponentB',\n  )\n</script>\n\n<div {...$$restProps}>\n  <span>This component uses a string 'key' for the remember functionality.</span>\n  <label>\n    Full Name\n    <input type=\"text\" class=\"b-name\" name=\"full_name\" bind:value={$data.name} />\n  </label>\n  <label>\n    Remember Me\n    <input type=\"checkbox\" class=\"b-remember\" name=\"remember\" bind:checked={$data.remember} />\n  </label>\n  <label>\n    Remember Me\n    <input type=\"text\" class=\"b-untracked\" name=\"untracked\" bind:value={untracked} />\n  </label>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Remember/Default.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n\n  let name = ''\n  let remember = false\n  let untracked = ''\n</script>\n\n<div>\n  <label>\n    Full Name\n    <input type=\"text\" id=\"name\" name=\"full_name\" bind:value={name} />\n  </label>\n  <label>\n    Remember Me\n    <input type=\"checkbox\" id=\"remember\" name=\"remember\" bind:checked={remember} />\n  </label>\n  <label>\n    Untracked\n    <input type=\"text\" id=\"untracked\" name=\"untracked\" bind:value={untracked} />\n  </label>\n\n  <a href=\"/dump/get\" use:inertia class=\"link\">Navigate away</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Remember/FormHelper/Default.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia, useForm } from '@inertiajs/svelte'\n\n  let untracked = ''\n\n  const form = useForm({\n    name: 'foo',\n    handle: 'example',\n    remember: false,\n  })\n\n  const submit = () => {\n    $form.post('/remember/form-helper/default')\n  }\n</script>\n\n<div>\n  <label>\n    Full Name\n    <input type=\"text\" id=\"name\" name=\"name\" bind:value={$form.name} />\n  </label>\n  {#if $form.errors.name}\n    <span class=\"name_error\">{$form.errors.name}</span>\n  {/if}\n  <label>\n    Handle\n    <input type=\"text\" id=\"handle\" name=\"handle\" bind:value={$form.handle} />\n  </label>\n  {#if $form.errors.handle}\n    <span class=\"handle_error\">{$form.errors.handle}</span>\n  {/if}\n  <label>\n    Remember Me\n    <input type=\"checkbox\" id=\"remember\" name=\"remember\" bind:checked={$form.remember} />\n  </label>\n  {#if $form.errors.remember}\n    <span class=\"remember_error\">{$form.errors.remember}</span>\n  {/if}\n  <label>\n    Untracked\n    <input type=\"text\" id=\"untracked\" name=\"untracked\" bind:value={untracked} />\n  </label>\n\n  <button on:click={submit} class=\"submit\">Submit form</button>\n\n  <a href=\"/dump/get\" use:inertia class=\"link\">Navigate away</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Remember/FormHelper/Password.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia, useForm } from '@inertiajs/svelte'\n\n  const form = useForm('password-form', {\n    username: '',\n    password: '',\n  }).dontRemember('password')\n</script>\n\n<div>\n  <label>\n    Username\n    <input type=\"text\" id=\"username\" bind:value={$form.username} />\n  </label>\n  <label>\n    Password\n    <input type=\"password\" id=\"password\" bind:value={$form.password} />\n  </label>\n\n  <a href=\"/dump/get\" use:inertia class=\"link\">Navigate away</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Remember/FormHelper/Remember.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia, useForm } from '@inertiajs/svelte'\n\n  const form = useForm('form', {\n    name: 'foo',\n    handle: 'example',\n    remember: false,\n  })\n\n  let untracked = ''\n\n  const submit = () => {\n    $form.post('/remember/form-helper/remember')\n  }\n\n  const reset = () => {\n    $form.reset('handle').clearErrors('name')\n  }\n</script>\n\n<div>\n  <label>\n    Full Name\n    <input type=\"text\" id=\"name\" name=\"name\" bind:value={$form.name} />\n  </label>\n  {#if $form.errors.name}\n    <span class=\"name_error\">{$form.errors.name}</span>\n  {/if}\n  <label>\n    Handle\n    <input type=\"text\" id=\"handle\" name=\"handle\" bind:value={$form.handle} />\n  </label>\n  {#if $form.errors.handle}\n    <span class=\"handle_error\">{$form.errors.handle}</span>\n  {/if}\n  <label>\n    Remember Me\n    <input type=\"checkbox\" id=\"remember\" name=\"remember\" bind:checked={$form.remember} />\n  </label>\n  {#if $form.errors.remember}\n    <span class=\"remember_error\">{$form.errors.remember}</span>\n  {/if}\n  <label>\n    Untracked\n    <input type=\"text\" id=\"untracked\" name=\"untracked\" bind:value={untracked} />\n  </label>\n\n  <button on:click={submit} class=\"submit\">Submit form</button>\n  <button on:click={reset} class=\"reset-one\">Reset one field & error</button>\n\n  <a href=\"/dump/get\" use:inertia class=\"link\">Navigate away</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Remember/MultipleComponents.svelte",
    "content": "<script lang=\"ts\">\n  import ComponentA from '@/Pages/Remember/Components/ComponentA.svelte'\n  import ComponentB from '@/Pages/Remember/Components/ComponentB.svelte'\n  import { inertia, useRemember } from '@inertiajs/svelte'\n\n  let untracked = ''\n\n  const form = useRemember({\n    name: '',\n    remember: false,\n  })\n</script>\n\n<div>\n  <label>\n    Full Name\n    <input type=\"text\" id=\"name\" name=\"full_name\" bind:value={$form.name} />\n  </label>\n  <label>\n    Remember Me\n    <input type=\"checkbox\" id=\"remember\" name=\"remember\" bind:checked={$form.remember} />\n  </label>\n  <label>\n    Untracked\n    <input type=\"text\" id=\"untracked\" name=\"untracked\" bind:value={untracked} />\n  </label>\n\n  <ComponentA class=\"component-a\" />\n  <ComponentB class=\"component-b\" />\n\n  <a href=\"/dump/get\" use:inertia class=\"link\">Navigate away</a>\n  <a href=\"/non-inertia\" class=\"off-site\">Navigate off-site</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Remember/Object.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia, useRemember } from '@inertiajs/svelte'\n\n  let untracked = ''\n\n  const form = useRemember({\n    name: '',\n    remember: false,\n  })\n</script>\n\n<div>\n  <label>\n    Full Name\n    <input type=\"text\" id=\"name\" name=\"full_name\" bind:value={$form.name} />\n  </label>\n  <label>\n    Remember Me\n    <input type=\"checkbox\" id=\"remember\" name=\"remember\" bind:checked={$form.remember} />\n  </label>\n  <label>\n    Untracked\n    <input type=\"text\" id=\"untracked\" name=\"untracked\" bind:value={untracked} />\n  </label>\n\n  <a href=\"/dump/get\" use:inertia class=\"link\">Navigate away</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Remember/Router.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  let foo = '-'\n  let bar = 0\n\n  function remember() {\n    router.remember('foo')\n    router.remember(42, 'bar')\n  }\n\n  function restore() {\n    foo = router.restore() ?? '-'\n    bar = router.restore('bar') ?? 0\n  }\n\n  function restoreTyped() {\n    const fooValue = router.restore<string>()\n    const barValue = router.restore<number>('bar')\n\n    fooValue?.startsWith('f')\n    barValue?.toFixed(2)\n\n    foo = fooValue ?? '-'\n    bar = barValue ?? 0\n\n    // @ts-expect-error - Testing type safety\n    fooValue?.toFixed(2)\n    // @ts-expect-error - Testing type safety\n    barValue?.startsWith('b')\n  }\n</script>\n\n<div>\n  <p>Foo: {foo}</p>\n  <p>Bar: {bar}</p>\n  <button on:click={remember}>Remember</button>\n  <button on:click={restore}>Restore</button>\n  <button on:click={restoreTyped}>Restore Typed</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/SSR/Page1.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n\n  export let user: { name: string; email: string }\n  export let items: string[]\n  export let count: number\n</script>\n\n<div>\n  <h1 data-testid=\"ssr-title\">SSR Page 1</h1>\n\n  <div data-testid=\"user-info\">\n    <p data-testid=\"user-name\">Name: {user.name}</p>\n    <p data-testid=\"user-email\">Email: {user.email}</p>\n  </div>\n\n  <ul data-testid=\"items-list\">\n    {#each items as item (item)}\n      <li data-testid=\"item\">{item}</li>\n    {/each}\n  </ul>\n\n  <p data-testid=\"count\">Count: {count}</p>\n\n  <a href=\"/ssr/page2\" use:inertia data-testid=\"navigate-link\">Navigate to another page</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/SSR/Page2.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n\n  export let navigatedTo: boolean\n</script>\n\n<div>\n  <h1 data-testid=\"ssr-title\">SSR Page 2</h1>\n  <p data-testid=\"navigated-status\">Navigated: {navigatedTo}</p>\n\n  <a href=\"/ssr/page1\" use:inertia data-testid=\"back-link\">Go back</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/SSR/PageWithScriptElement.svelte",
    "content": "<script lang=\"ts\">\n  export let message: string\n</script>\n\n<div>\n  <h1 data-testid=\"ssr-title\">SSR Page With Script Element</h1>\n  <p data-testid=\"message\">{message}</p>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/ScrollAfterRender.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  let originalScrollTo: typeof window.scrollTo | null = null\n</script>\n\n<script lang=\"ts\">\n  import { Link } from '@inertiajs/svelte'\n\n  export let page: number\n\n  // Patch scrollTo to log synchronously when it's called (not when the scroll event fires)\n  if (!originalScrollTo) {\n    originalScrollTo = window.scrollTo.bind(window)\n\n    window.scrollTo = ((xOrOptions: number | ScrollToOptions, y?: number) => {\n      const firstArgIsNumber = typeof xOrOptions === 'number'\n      const scrollY = firstArgIsNumber ? y : (xOrOptions?.top ?? 0)\n\n      console.log('ScrollY', scrollY)\n\n      return firstArgIsNumber ? originalScrollTo!(xOrOptions, y!) : originalScrollTo!(xOrOptions)\n    }) as typeof window.scrollTo\n  } else {\n    console.log('Render')\n  }\n\n  function beforeNavigate() {\n    window.scrollTo(0, 100)\n  }\n</script>\n\n<h1 style=\"font-size: 40px;\">Article Header</h1>\n<h2 style=\"font-size: 40px;\">Page {page}</h2>\n<article style=\"font-size: 20px; max-width: 500px;\">\n  <p>\n    Sunt culpa sit sunt enim aliquip. Esse ea ea quis voluptate. Enim consectetur aliqua ex ex magna cupidatat id minim\n    sit elit.\n  </p>\n  <Link href={`/scroll-after-render/${page + 1}`} style=\"display: block; margin-top: 20px;\" on:before={beforeNavigate}>\n    Go to page {page + 1}\n  </Link>\n  {#each Array(500).keys() as i (i)}\n    <div>\n      <p>\n        Sunt culpa sit sunt enim aliquip. Esse ea ea quis voluptate. Enim consectetur aliqua ex ex magna cupidatat id\n        minim sit elit. Amet pariatur occaecat pariatur duis eiusmod dolore magna. Et commodo cupidatat in commodo elit\n        cupidatat minim qui id non enim ad. Culpa aliquip ad Lorem sit consectetur ullamco culpa duis nisi et fugiat\n        mollit eiusmod. Laboris voluptate veniam consequat proident in nulla irure velit.\n      </p>\n\n      <p>\n        Sit sint laboris sunt eiusmod ipsum laborum eiusmod amet commodo exercitation in duis magna. Proident sunt minim\n        in elit qui. Id pariatur commodo fugiat excepteur in deserunt Lorem ipsum occaecat est. Excepteur sit tempor\n        ipsum ex officia veniam enim amet velit fugiat mollit cillum. Incididunt aliqua nulla id occaecat nulla. Non ea\n        ad est occaecat deserunt officia qui commodo exercitation.\n      </p>\n\n      <p>\n        Voluptate laborum quis aliqua ullamco magna amet ullamco laborum qui cillum eu. Dolore dolore aliqua proident\n        proident sunt ipsum in. Enim velit dolore labore dolor quis incididunt duis culpa Lorem. Eu adipisicing non elit\n        fugiat voluptate labore ipsum dolore consectetur commodo. Et in et cillum duis consequat quis ex eu commodo.\n        Eiusmod aliqua excepteur consectetur eiusmod aute et consectetur sit pariatur dolore qui officia pariatur.\n      </p>\n\n      <p>\n        Non sunt eu mollit qui reprehenderit. Aute culpa anim voluptate do in esse duis laborum ad dolore. Ullamco nisi\n        in nostrud officia do. Duis pariatur officia id duis. Deserunt ad incididunt est sint consectetur reprehenderit\n        mollit est Lorem ea pariatur anim dolor adipisicing. Nostrud irure magna nostrud laboris aute sunt veniam\n        laboris veniam incididunt sit. Nulla proident ad aliqua fugiat culpa sunt est in dolor velit ad irure nulla.\n      </p>\n\n      <p>\n        Do aute laborum deserunt non laborum voluptate voluptate. Anim ut laborum magna sunt cupidatat irure. Cupidatat\n        fugiat minim sint cillum laborum excepteur irure id est irure ad occaecat adipisicing enim. Deserunt nulla anim\n        proident velit irure nostrud est est reprehenderit consequat pariatur qui. Fugiat Lorem sint eu laborum minim\n        pariatur cillum mollit nulla consequat ullamco ex. Ex consectetur ad ut irure fugiat occaecat aliqua\n        exercitation cillum ipsum anim dolore tempor.\n      </p>\n\n      <p>\n        Adipisicing consequat irure fugiat Lorem deserunt aliquip do cupidatat. Lorem labore elit ex qui nostrud qui\n        cillum sunt adipisicing occaecat. Sunt nostrud amet amet cupidatat fugiat Lorem quis nulla id cillum esse eu.\n        Ullamco aliqua dolore irure amet mollit anim velit dolore.\n      </p>\n\n      <p>\n        Veniam cupidatat ipsum ea officia ipsum nisi laborum culpa qui dolore. Aliqua Lorem nisi labore ea velit aliquip\n        irure excepteur eu. Laboris proident duis non labore sunt quis aute tempor laboris enim anim eiusmod.\n      </p>\n\n      <p>\n        Minim proident ut aliqua ea ut culpa fugiat ullamco nisi esse nostrud reprehenderit id. Id id ullamco velit anim\n        nisi magna Lorem tempor. Et veniam occaecat ut labore consequat fugiat duis.\n      </p>\n\n      <p>\n        Adipisicing ea consectetur adipisicing aute eu pariatur enim labore consequat occaecat consectetur minim nisi.\n        Cillum commodo sunt labore reprehenderit. Duis esse excepteur magna tempor eiusmod exercitation Lorem\n        reprehenderit excepteur pariatur. Esse cupidatat occaecat magna do aliquip Lorem. Consectetur adipisicing\n        consequat dolore nostrud esse eu cillum id commodo duis. Aliquip dolor cillum cupidatat fugiat.\n      </p>\n\n      <p>\n        Ex eiusmod id est laborum sunt ex ea aute adipisicing ad magna deserunt duis. Nostrud velit dolore id commodo\n        quis enim fugiat. Sint non quis consectetur voluptate aliqua dolore nulla. Irure sit reprehenderit sint laboris\n        non elit. Duis minim nisi esse dolor. Sit ex in consequat non occaecat commodo irure et. Commodo qui ipsum Lorem\n        magna consequat consequat et minim eiusmod Lorem eiusmod cupidatat voluptate.\n      </p>\n    </div>\n  {/each}\n</article>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/ScrollRegionPreserveUrl.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  export let page: number\n\n  let scrollInterval: ReturnType<typeof setInterval> | null = null\n  let items = Array.from({ length: 50 }, (_, i) => i + 1)\n\n  const startScrollingAndNavigate = () => {\n    const container = document.getElementById('scroll-container')!\n    const nextPage = page === 1 ? 2 : 1\n\n    // Start continuous scrolling\n    scrollInterval = setInterval(() => {\n      container.scrollTop += 10\n    }, 10)\n\n    // After 150ms of scrolling, navigate to the other page\n    setTimeout(() => {\n      router.visit(`/scroll-region-preserve-url/${nextPage}`, {\n        preserveScroll: true,\n        preserveState: true,\n        preserveUrl: true,\n        onSuccess: () => {\n          // Stop scrolling after navigation\n          if (scrollInterval) {\n            clearInterval(scrollInterval)\n            scrollInterval = null\n          }\n        },\n      })\n    }, 150)\n  }\n</script>\n\n<div scroll-region id=\"scroll-container\" style=\"height: 300px; overflow-y: auto; border: 1px solid #ccc\">\n  <div style=\"padding: 10px\">\n    <div class=\"page-number\">Page: {page}</div>\n    <button id=\"scroll-and-navigate\" on:click={startScrollingAndNavigate}>Start scrolling and navigate</button>\n    {#each items as num (num)}\n      <div style=\"padding: 20px; border-bottom: 1px solid #eee\">Item {num}</div>\n    {/each}\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/ScrollSmooth.svelte",
    "content": "<script>\n  import { Link } from '@inertiajs/svelte'\n  import { onMount, onDestroy } from 'svelte'\n\n  export let page\n\n  onMount(() => {\n    document.documentElement.style.scrollBehavior = 'smooth'\n  })\n\n  onDestroy(() => {\n    document.documentElement.style.scrollBehavior = ''\n  })\n</script>\n\n<div>\n  <h1>{page === 'long' ? 'Long Page' : 'Short Page'}</h1>\n\n  <div style=\"height: {page === 'long' ? '2000px' : '100px'}\"></div>\n\n  {#if page === 'long'}\n    <Link href=\"/scroll-smooth/short\">Go to Short Page</Link>\n  {:else}\n    <Link href=\"/scroll-smooth/long\">Go to Long Page</Link>\n  {/if}\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/ScrollableParent.svelte",
    "content": "<script lang=\"ts\">\n  import { onMount } from 'svelte'\n  import { getScrollableParent } from '@inertiajs/core'\n\n  let overflowXHidden: HTMLDivElement\n  let overflowXScroll: HTMLDivElement\n  let overflowYAuto: HTMLDivElement\n  let overflowYAutoNoHeight: HTMLDivElement\n  let overflowXScrollOverflowYHidden: HTMLDivElement\n  let horizontalScrollCalc: HTMLDivElement\n  let verticalScrollMaxHeight: HTMLDivElement\n  let nestedScroll: HTMLDivElement\n  let overflowAutoNoConstraints: HTMLDivElement\n  let flexHorizontalCarousel: HTMLDivElement\n  let coercedAutoNoConstraint: HTMLDivElement\n  let displayContents: HTMLDivElement\n  let overflowClip: HTMLDivElement\n  let overflowOverlay: HTMLDivElement\n  let inlineWidthStyle: HTMLDivElement\n  let bothScrollDirections: HTMLDivElement\n  let overflowYAutoOverflowXVisible: HTMLDivElement\n  let overflowYAutoOverflowXClip: HTMLDivElement\n  let overflowXAutoOverflowYVisible: HTMLDivElement\n  let overflowXAutoOverflowYClip: HTMLDivElement\n  let overflowYAutoOverflowXHidden: HTMLDivElement\n  let overflowXAutoOverflowYHidden: HTMLDivElement\n\n  let results: Record<string, HTMLElement | null> = {}\n\n  onMount(() => {\n    Object.entries({\n      overflowXHidden,\n      overflowXScroll,\n      overflowYAuto,\n      overflowYAutoNoHeight,\n      overflowXScrollOverflowYHidden,\n      horizontalScrollCalc,\n      verticalScrollMaxHeight,\n      nestedScroll,\n      overflowAutoNoConstraints,\n      flexHorizontalCarousel,\n      coercedAutoNoConstraint,\n      displayContents,\n      overflowClip,\n      overflowOverlay,\n      inlineWidthStyle,\n      bothScrollDirections,\n      overflowYAutoOverflowXVisible,\n      overflowYAutoOverflowXClip,\n      overflowXAutoOverflowYVisible,\n      overflowXAutoOverflowYClip,\n      overflowYAutoOverflowXHidden,\n      overflowXAutoOverflowYHidden,\n    }).forEach(([key, element]) => {\n      results[key] = getScrollableParent(element)\n    })\n  })\n</script>\n\n<div style=\"padding: 20px\">\n  <h1>ScrollableParent Tests</h1>\n\n  <div style=\"display: grid; gap: 20px; margin-top: 20px\">\n    <!-- overflow-x: hidden -->\n    <div>\n      <h3>overflow-x: hidden</h3>\n      <div style=\"overflow-x: hidden; border: 2px solid red; padding: 10px\">\n        <div bind:this={overflowXHidden} data-testid=\"overflow-x-hidden\">Test</div>\n      </div>\n      <p data-testid=\"result-overflow-x-hidden\">{results.overflowXHidden?.tagName || 'null'}</p>\n    </div>\n\n    <!-- overflow-x: scroll -->\n    <div>\n      <h3>overflow-x: scroll</h3>\n      <div\n        style=\"overflow-x: scroll; width: 300px; border: 2px solid red; padding: 10px\"\n        data-testid=\"scroll-container-x\"\n      >\n        <div bind:this={overflowXScroll} data-testid=\"overflow-x-scroll\" style=\"width: 600px\">Wide content</div>\n      </div>\n      <p data-testid=\"result-overflow-x-scroll\">{results.overflowXScroll?.dataset?.testid || 'null'}</p>\n    </div>\n\n    <!-- overflow-y: auto with height -->\n    <div>\n      <h3>overflow-y: auto + height</h3>\n      <div\n        style=\"overflow-y: auto; height: 100px; border: 2px solid red; padding: 10px\"\n        data-testid=\"scroll-container-y\"\n      >\n        <div bind:this={overflowYAuto} data-testid=\"overflow-y-auto\">\n          <p>Content</p>\n          <p>Content</p>\n          <p>Content</p>\n        </div>\n      </div>\n      <p data-testid=\"result-overflow-y-auto\">{results.overflowYAuto?.dataset?.testid || 'null'}</p>\n    </div>\n\n    <!-- overflow-y: auto no height -->\n    <div>\n      <h3>overflow-y: auto (no height)</h3>\n      <div style=\"overflow-y: auto; border: 2px solid red; padding: 10px\">\n        <div bind:this={overflowYAutoNoHeight} data-testid=\"overflow-y-auto-no-height\">Content</div>\n      </div>\n      <p data-testid=\"result-overflow-y-auto-no-height\">{results.overflowYAutoNoHeight?.tagName || 'null'}</p>\n    </div>\n\n    <!-- overflow-x: scroll, overflow-y: hidden -->\n    <div>\n      <h3>overflow-x: scroll, overflow-y: hidden</h3>\n      <div\n        style=\"overflow-x: scroll; overflow-y: hidden; width: 300px; border: 2px solid red; padding: 10px\"\n        data-testid=\"scroll-container-x-y-hidden\"\n      >\n        <div bind:this={overflowXScrollOverflowYHidden} data-testid=\"overflow-x-scroll-y-hidden\" style=\"width: 600px\">\n          Wide content\n        </div>\n      </div>\n      <p data-testid=\"result-overflow-x-scroll-y-hidden\">\n        {results.overflowXScrollOverflowYHidden?.dataset?.testid || 'null'}\n      </p>\n    </div>\n\n    <!-- overflow-x: scroll + max-width -->\n    <div>\n      <h3>overflow-x: scroll + max-width</h3>\n      <div\n        style=\"overflow-x: scroll; max-width: 300px; border: 2px solid red; padding: 10px\"\n        data-testid=\"scroll-container-max-width\"\n      >\n        <div bind:this={horizontalScrollCalc} data-testid=\"horizontal-scroll-calc\" style=\"width: 600px\">\n          Wide content\n        </div>\n      </div>\n      <p data-testid=\"result-horizontal-scroll-calc\">{results.horizontalScrollCalc?.dataset?.testid || 'null'}</p>\n    </div>\n\n    <!-- overflow-y: auto + max-height -->\n    <div>\n      <h3>overflow-y: auto + max-height</h3>\n      <div\n        style=\"overflow-y: auto; max-height: 100px; border: 2px solid red; padding: 10px\"\n        data-testid=\"scroll-container-max-height\"\n      >\n        <div bind:this={verticalScrollMaxHeight} data-testid=\"vertical-scroll-max-height\">\n          <p>Content</p>\n          <p>Content</p>\n          <p>Content</p>\n        </div>\n      </div>\n      <p data-testid=\"result-vertical-scroll-max-height\">\n        {results.verticalScrollMaxHeight?.dataset?.testid || 'null'}\n      </p>\n    </div>\n\n    <!-- Nested containers -->\n    <div>\n      <h3>Nested containers</h3>\n      <div style=\"overflow-y: auto; height: 200px; border: 2px solid red; padding: 10px\" data-testid=\"outer-scroll\">\n        <p>Outer</p>\n        <div style=\"overflow-y: auto; height: 100px; border: 2px solid blue; padding: 10px\" data-testid=\"inner-scroll\">\n          <div bind:this={nestedScroll} data-testid=\"nested-scroll\">\n            <p>Content</p>\n            <p>Content</p>\n            <p>Content</p>\n            <p>Content</p>\n            <p>Content</p>\n          </div>\n        </div>\n      </div>\n      <p data-testid=\"result-nested-scroll\">{results.nestedScroll?.dataset?.testid || 'null'}</p>\n    </div>\n\n    <!-- overflow: auto (no constraints) -->\n    <div>\n      <h3>overflow: auto (no constraints)</h3>\n      <div style=\"overflow: auto; border: 2px solid red; padding: 10px\">\n        <div bind:this={overflowAutoNoConstraints} data-testid=\"overflow-auto-no-constraints\">Content</div>\n      </div>\n      <p data-testid=\"result-overflow-auto-no-constraints\">{results.overflowAutoNoConstraints?.tagName || 'null'}</p>\n    </div>\n\n    <!-- Flex carousel -->\n    <div>\n      <h3>Flex horizontal carousel</h3>\n      <div\n        style=\"overflow-x: scroll; display: flex; gap: 10px; width: 300px; border: 2px solid red; padding: 10px\"\n        data-testid=\"flex-carousel\"\n      >\n        <div\n          bind:this={flexHorizontalCarousel}\n          data-testid=\"flex-horizontal-carousel\"\n          style=\"min-width: 150px; height: 50px; background: lightblue\"\n        >\n          Item\n        </div>\n        <div style=\"min-width: 150px; height: 50px; background: lightgreen\">Item</div>\n        <div style=\"min-width: 150px; height: 50px; background: lightcoral\">Item</div>\n      </div>\n      <p data-testid=\"result-flex-horizontal-carousel\">{results.flexHorizontalCarousel?.dataset?.testid || 'null'}</p>\n    </div>\n\n    <!-- Coerced auto -->\n    <div>\n      <h3>overflow-x: scroll (overflow-y coerced)</h3>\n      <div\n        style=\"overflow-x: scroll; display: flex; width: 300px; border: 2px solid red; padding: 10px\"\n        data-testid=\"coerced-auto\"\n      >\n        <div bind:this={coercedAutoNoConstraint} data-testid=\"coerced-auto-no-constraint\" style=\"min-width: 600px\">\n          Wide\n        </div>\n      </div>\n      <p data-testid=\"result-coerced-auto-no-constraint\">\n        {results.coercedAutoNoConstraint?.dataset?.testid || 'null'}\n      </p>\n    </div>\n\n    <!-- display: contents -->\n    <div>\n      <h3>display: contents (skip parent)</h3>\n      <div\n        style=\"overflow-y: auto; height: 100px; border: 2px solid red; padding: 10px\"\n        data-testid=\"scroll-container-skip-contents\"\n      >\n        <div style=\"display: contents\">\n          <div bind:this={displayContents} data-testid=\"display-contents\">\n            <p>Content</p>\n            <p>Content</p>\n            <p>Content</p>\n            <p>Content</p>\n          </div>\n        </div>\n      </div>\n      <p data-testid=\"result-display-contents\">{results.displayContents?.dataset?.testid || 'null'}</p>\n    </div>\n\n    <!-- overflow: clip -->\n    <div>\n      <h3>overflow: clip</h3>\n      <div style=\"overflow: clip; height: 100px; border: 2px solid red; padding: 10px\">\n        <div bind:this={overflowClip} data-testid=\"overflow-clip\">\n          <p>Content</p>\n          <p>Content</p>\n        </div>\n      </div>\n      <p data-testid=\"result-overflow-clip\">{results.overflowClip?.tagName || 'null'}</p>\n    </div>\n\n    <!-- overflow: overlay -->\n    <div>\n      <h3>overflow: overlay</h3>\n      <div\n        style=\"overflow: overlay; height: 100px; border: 2px solid red; padding: 10px\"\n        data-testid=\"scroll-container-overlay\"\n      >\n        <div bind:this={overflowOverlay} data-testid=\"overflow-overlay\">\n          <p>Content</p>\n          <p>Content</p>\n          <p>Content</p>\n          <p>Content</p>\n        </div>\n      </div>\n      <p data-testid=\"result-overflow-overlay\">{results.overflowOverlay?.dataset?.testid || 'null'}</p>\n    </div>\n\n    <!-- Inline width -->\n    <div>\n      <h3>overflow-x: auto + inline width</h3>\n      <div\n        style=\"overflow-x: auto; width: 300px; border: 2px solid red; padding: 10px\"\n        data-testid=\"inline-width-container\"\n      >\n        <div bind:this={inlineWidthStyle} data-testid=\"inline-width-style\" style=\"width: 600px\">Wide</div>\n      </div>\n      <p data-testid=\"result-inline-width-style\">{results.inlineWidthStyle?.dataset?.testid || 'null'}</p>\n    </div>\n\n    <!-- Both scroll -->\n    <div>\n      <h3>overflow: scroll (both)</h3>\n      <div\n        style=\"overflow-x: scroll; overflow-y: scroll; width: 300px; height: 100px; border: 2px solid red; padding: 10px\"\n        data-testid=\"both-scroll\"\n      >\n        <div bind:this={bothScrollDirections} data-testid=\"both-scroll-directions\" style=\"width: 600px\">\n          <p>Wide and tall</p>\n          <p>Content</p>\n          <p>Content</p>\n        </div>\n      </div>\n      <p data-testid=\"result-both-scroll-directions\">{results.bothScrollDirections?.dataset?.testid || 'null'}</p>\n    </div>\n\n    <!-- overflow-y: auto + overflow-x: visible -->\n    <div>\n      <h3>overflow-y: auto + overflow-x: visible</h3>\n      <div\n        style=\"overflow-y: auto; overflow-x: visible; height: 100px; border: 2px solid red; padding: 10px\"\n        data-testid=\"overflow-y-auto-x-visible\"\n      >\n        <div bind:this={overflowYAutoOverflowXVisible} data-testid=\"overflow-y-auto-overflow-x-visible\">\n          <p>Content</p>\n          <p>Content</p>\n          <p>Content</p>\n        </div>\n      </div>\n      <p data-testid=\"result-overflow-y-auto-overflow-x-visible\">\n        {results.overflowYAutoOverflowXVisible?.dataset?.testid || 'null'}\n      </p>\n    </div>\n\n    <!-- overflow-y: auto + overflow-x: clip -->\n    <div>\n      <h3>overflow-y: auto + overflow-x: clip</h3>\n      <div\n        style=\"overflow-y: auto; overflow-x: clip; height: 100px; border: 2px solid red; padding: 10px\"\n        data-testid=\"overflow-y-auto-x-clip\"\n      >\n        <div bind:this={overflowYAutoOverflowXClip} data-testid=\"overflow-y-auto-overflow-x-clip\">\n          <p>Content</p>\n          <p>Content</p>\n          <p>Content</p>\n        </div>\n      </div>\n      <p data-testid=\"result-overflow-y-auto-overflow-x-clip\">\n        {results.overflowYAutoOverflowXClip?.dataset?.testid || 'null'}\n      </p>\n    </div>\n\n    <!-- overflow-x: auto + overflow-y: visible -->\n    <div>\n      <h3>overflow-x: auto + overflow-y: visible</h3>\n      <div\n        style=\"overflow-x: auto; overflow-y: visible; width: 300px; border: 2px solid red; padding: 10px\"\n        data-testid=\"overflow-x-auto-y-visible\"\n      >\n        <div\n          bind:this={overflowXAutoOverflowYVisible}\n          data-testid=\"overflow-x-auto-overflow-y-visible\"\n          style=\"width: 600px\"\n        >\n          Wide content\n        </div>\n      </div>\n      <p data-testid=\"result-overflow-x-auto-overflow-y-visible\">\n        {results.overflowXAutoOverflowYVisible?.dataset?.testid || 'null'}\n      </p>\n    </div>\n\n    <!-- overflow-x: auto + overflow-y: clip -->\n    <div>\n      <h3>overflow-x: auto + overflow-y: clip</h3>\n      <div\n        style=\"overflow-x: auto; overflow-y: clip; width: 300px; border: 2px solid red; padding: 10px\"\n        data-testid=\"overflow-x-auto-y-clip\"\n      >\n        <div bind:this={overflowXAutoOverflowYClip} data-testid=\"overflow-x-auto-overflow-y-clip\" style=\"width: 600px\">\n          Wide content\n        </div>\n      </div>\n      <p data-testid=\"result-overflow-x-auto-overflow-y-clip\">\n        {results.overflowXAutoOverflowYClip?.dataset?.testid || 'null'}\n      </p>\n    </div>\n\n    <!-- overflow-y: auto + overflow-x: hidden (no height) -->\n    <div>\n      <h3>overflow-y: auto + overflow-x: hidden (no height)</h3>\n      <div style=\"overflow-y: auto; overflow-x: hidden; border: 2px solid red; padding: 10px\">\n        <div bind:this={overflowYAutoOverflowXHidden} data-testid=\"overflow-y-auto-overflow-x-hidden\">Content</div>\n      </div>\n      <p data-testid=\"result-overflow-y-auto-overflow-x-hidden\">\n        {results.overflowYAutoOverflowXHidden?.tagName || 'null'}\n      </p>\n    </div>\n\n    <!-- overflow-x: auto + overflow-y: hidden (no width) -->\n    <div>\n      <h3>overflow-x: auto + overflow-y: hidden (no width)</h3>\n      <div style=\"overflow-x: auto; overflow-y: hidden; border: 2px solid red; padding: 10px\">\n        <div bind:this={overflowXAutoOverflowYHidden} data-testid=\"overflow-x-auto-overflow-y-hidden\">Content</div>\n      </div>\n      <p data-testid=\"result-overflow-x-auto-overflow-y-hidden\">\n        {results.overflowXAutoOverflowYHidden?.tagName || 'null'}\n      </p>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Svelte/PropsAndPageStore.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia, page, usePage, useForm } from '@inertiajs/svelte'\n  import { onMount } from 'svelte'\n\n  type PageProps = {\n    foo: string\n  }\n\n  export let foo\n\n  const form = useForm({ foo })\n\n  const pageProps: PageProps = {\n    foo: $page.props.foo,\n  }\n\n  const sveltePage = usePage<PageProps>()\n\n  console.log('[script] foo prop is', foo)\n  console.log('[script] $page.props.foo is', $page.props.foo)\n  console.log('[script] $sveltePage.props.foo is', $sveltePage.props.foo)\n\n  $: console.log('[reactive expression] foo prop is', foo)\n  $: console.log('[reactive expression] $page.props.foo is', $page.props.foo)\n  $: console.log('[reactive expression] $sveltePage.props.foo is', $sveltePage.props.foo)\n\n  onMount(() => {\n    console.log('[onMount] foo prop is', foo)\n    console.log('[onMount] $page.props.foo is', $page.props.foo)\n    console.log('[onMount] $sveltePage.props.foo is', $sveltePage.props.foo)\n  })\n</script>\n\n<div>\n  <input id=\"input\" type=\"text\" bind:value={$form.foo} />\n  <p>foo prop is {foo}</p>\n  <p>$page.props.foo is {$page.props.foo}</p>\n  <p>pageProps.foo is {pageProps.foo}</p>\n  <p>$sveltePage.props.foo is {$sveltePage.props.foo}</p>\n\n  <a href=\"/svelte/props-and-page-store\" use:inertia={{ data: { foo: 'bar' } }}> Bar </a>\n  <a href=\"/svelte/props-and-page-store\" use:inertia={{ data: { foo: 'baz' } }}> Baz </a>\n  <a href=\"/\" use:inertia> Home </a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/TypeScriptCreateInertiaApp.ts",
    "content": "// This file is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { createInertiaApp, type ResolvedComponent } from '@inertiajs/svelte'\n\ndeclare module '@inertiajs/core' {\n  export interface InertiaConfig {\n    sharedPageProps: {\n      auth: { user: { name: string } | null }\n    }\n  }\n}\n\n// createInertiaApp setup should include shared props without explicit generic\ncreateInertiaApp({\n  resolve: (name) => {\n    const pages = import.meta.glob<ResolvedComponent>('./Pages/**/*.svelte', { eager: true })\n    return pages[`./Pages/${name}.svelte`]\n  },\n  setup({ el, App, props }) {\n    console.log(props.initialPage.props.auth.user?.name)\n    // @ts-expect-error - 'email' does not exist on user\n    console.log(props.initialPage.props.auth.user?.email)\n\n    new App({ target: el!, props })\n  },\n})\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/TypeScriptFlash.svelte",
    "content": "<script lang=\"ts\" context=\"module\">\n  declare module '@inertiajs/core' {\n    export interface InertiaConfig {\n      flashDataType: {\n        toast?: { type: 'success' | 'error'; message: string }\n      }\n    }\n  }\n</script>\n\n<script lang=\"ts\">\n  // This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\n  import { router, page } from '@inertiajs/svelte'\n\n  // page.flash is always an object\n  $: flash = $page.flash\n  $: toast = $page.flash.toast\n  $: toastMessage = $page.flash.toast?.message\n  $: toastType = $page.flash.toast?.type\n\n  // @ts-expect-error - 'message' does not exist on flash (it's on toast)\n  $: flashMessage = $page.flash.message\n\n  // router.flash with object\n  router.flash({ toast: { type: 'success', message: 'Hello' } })\n\n  // router.flash with key-value\n  router.flash('toast', { type: 'error', message: 'Oops' })\n\n  // router.flash with callback\n  router.flash((current) => ({\n    ...current,\n    toast: { type: 'success', message: 'Updated' },\n  }))\n\n  // Client-side visit with flash\n  router.replace({\n    flash: { toast: { type: 'success', message: 'Replaced' } },\n    onFlash: (flash) => {\n      console.log(flash.toast?.message)\n    },\n  })\n\n  // Client-side visit with flash callback\n  router.push({\n    flash: (current) => ({\n      ...current,\n      toast: { type: 'error', message: 'Error' },\n    }),\n  })\n\n  // Scoped flash typing with generic (for page/section-specific flash)\n  router.flash<{ paymentError: string }>({ paymentError: 'Card declined' })\n\n  // @ts-expect-error - 'paymentError' should be string, not number\n  router.flash<{ paymentError: string }>({ paymentError: 123 })\n\n  console.log({\n    flash,\n    toast,\n    toastMessage,\n    toastType,\n    flashMessage,\n  })\n</script>\n\n{#if $page.flash.toast}\n  {$page.flash.toast.message}\n{/if}\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/TypeScriptProps.svelte",
    "content": "<script lang=\"ts\" context=\"module\">\n  declare module '@inertiajs/core' {\n    export interface InertiaConfig {\n      sharedPageProps: {\n        auth: { user: { name: string } | null }\n      }\n    }\n  }\n</script>\n\n<script lang=\"ts\">\n  // This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\n  import { router, usePage } from '@inertiajs/svelte'\n\n  type PageProps = {\n    posts: { id: number; title: string }[]\n  }\n\n  const page = usePage<PageProps>()\n\n  $: userName = $page.props.auth.user?.name\n  $: postTitles = $page.props.posts.map((post) => post.title)\n\n  // @ts-expect-error - 'email' does not exist on user\n  $: userEmail = $page.props.auth.user?.email\n  // @ts-expect-error - 'users' does not exist on page props\n  $: userNames = $page.props.users.map((user) => user.name)\n\n  // Global event callbacks should include shared props\n  router.on('success', (event) => {\n    console.log(event.detail.page.props.auth.user?.name)\n    // @ts-expect-error - 'email' does not exist on user\n    console.log(event.detail.page.props.auth.user?.email)\n  })\n\n  router.on('navigate', (event) => {\n    console.log(event.detail.page.props.auth.user?.name)\n    // @ts-expect-error - 'email' does not exist on user\n    console.log(event.detail.page.props.auth.user?.email)\n  })\n\n  router.on('beforeUpdate', (event) => {\n    console.log(event.detail.page.props.auth.user?.name)\n    // @ts-expect-error - 'email' does not exist on user\n    console.log(event.detail.page.props.auth.user?.email)\n  })\n\n  // Visit callback onSuccess should include shared props\n  router.visit('/example', {\n    onSuccess: (page) => {\n      console.log(page.props.auth.user?.name)\n      // @ts-expect-error - 'email' does not exist on user\n      console.log(page.props.auth.user?.email)\n    },\n  })\n\n  // Client-side visit onSuccess should include shared props\n  router.push({\n    onSuccess: (page) => {\n      console.log(page.props.auth.user?.name)\n      // @ts-expect-error - 'email' does not exist on user\n      console.log(page.props.auth.user?.email)\n    },\n  })\n\n  router.replace({\n    onSuccess: (page) => {\n      console.log(page.props.auth.user?.name)\n      // @ts-expect-error - 'email' does not exist on user\n      console.log(page.props.auth.user?.email)\n    },\n  })\n\n  console.log({\n    userName,\n    postTitles,\n    userEmail,\n    userNames,\n  })\n</script>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/ViewTransition/FormErrors.svelte",
    "content": "<script lang=\"ts\">\n  import { useForm } from '@inertiajs/svelte'\n\n  const form = useForm({ name: '' })\n\n  const submit = () => {\n    $form.post('/view-transition/form-errors', {\n      viewTransition: (viewTransition) => {\n        viewTransition.ready.then(() => console.log('ready'))\n        viewTransition.updateCallbackDone.then(() => console.log('updateCallbackDone'))\n        viewTransition.finished.then(() => console.log('finished'))\n      },\n    })\n  }\n</script>\n\n<div>\n  <h1>View Transition Form Errors Test</h1>\n\n  <label>\n    Name\n    <input id=\"name\" bind:value={$form.name} type=\"text\" name=\"name\" />\n  </label>\n\n  {#if $form.errors.name}\n    <p class=\"name_error\">{$form.errors.name}</p>\n  {/if}\n\n  <button class=\"submit\" on:click={submit}>Submit with View Transition</button>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/ViewTransition/PageA.svelte",
    "content": "<script lang=\"ts\">\n  import { Link, router } from '@inertiajs/svelte'\n\n  const transitionWithBoolean = () => {\n    router.visit('/view-transition/page-b', {\n      viewTransition: true,\n    })\n  }\n\n  const transitionWithCallback = () => {\n    router.visit('/view-transition/page-b', {\n      viewTransition: (viewTransition) => {\n        viewTransition.ready.then(() => console.log('ready'))\n        viewTransition.updateCallbackDone.then(() => console.log('updateCallbackDone'))\n        viewTransition.finished.then(() => console.log('finished'))\n      },\n    })\n  }\n\n  const clientSideReplace = () => {\n    router.replace({\n      url: '/view-transition/page-b',\n      component: 'ViewTransition/PageB',\n      props: {},\n      viewTransition: (viewTransition) => {\n        viewTransition.ready.then(() => console.log('ready'))\n        viewTransition.updateCallbackDone.then(() => console.log('updateCallbackDone'))\n        viewTransition.finished.then(() => console.log('finished'))\n      },\n    })\n  }\n</script>\n\n<h1>Page A - View Transition Test</h1>\n\n<button on:click={transitionWithBoolean}>Transition with boolean</button>\n<button on:click={transitionWithCallback}>Transition with callback</button>\n<button on:click={clientSideReplace}>Client-side replace</button>\n<Link\n  href=\"/view-transition/page-b\"\n  viewTransition={(viewTransition) => {\n    viewTransition.ready.then(() => console.log('ready'))\n    viewTransition.updateCallbackDone.then(() => console.log('updateCallbackDone'))\n    viewTransition.finished.then(() => console.log('finished'))\n  }}>Link to Page B</Link\n>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/ViewTransition/PageB.svelte",
    "content": "<h1>Page B - View Transition Test</h1>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Visits/AfterError.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  const visitDump = (e: Event) => {\n    e.preventDefault()\n    router.visit('/dump/get')\n  }\n\n  const throwErrorOnSuccess = (e: Event) => {\n    e.preventDefault()\n\n    router.visit('/visits/after-error/2', {\n      onSuccess: () => {\n        throw new Error('Error after visit')\n      },\n    })\n  }\n</script>\n\n<div>\n  <a href={'#'} on:click|preventDefault={visitDump}> Visit dump page </a>\n\n  <a href={'#'} on:click|preventDefault={throwErrorOnSuccess}> Throw error on success </a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Visits/AutomaticCancellation.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  const visit = () => {\n    router.get(\n      '/sleep',\n      {},\n      {\n        onStart: () => console.log('started'),\n        onCancel: () => console.log('cancelled'),\n      },\n    )\n  }\n</script>\n\n<div>\n  <span class=\"text\">This is the page that demonstrates that only one visit can be active at a time</span>\n  <a href={'#'} on:click|preventDefault={visit} class=\"visit\">Link</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Visits/Data/AutoConverted.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  const formData = {\n    file: new File([], 'example.jpg'),\n    foo: 'bar',\n  }\n\n  const visitMethod = () => {\n    router.visit('/dump/post', {\n      method: 'post',\n      data: formData,\n    })\n  }\n\n  const postMethod = () => {\n    router.post('/dump/post', formData)\n  }\n\n  const putMethod = () => {\n    router.put('/dump/put', formData)\n  }\n\n  const patchMethod = () => {\n    router.patch('/dump/patch', formData)\n  }\n\n  const deleteMethod = () => {\n    router.delete('/dump/delete', {\n      data: formData,\n    })\n  }\n</script>\n\n<div>\n  <span class=\"text\">\n    This is the page that demonstrates automatic conversion of plain objects to form-data using manual visits\n  </span>\n\n  <a href={'#'} on:click|preventDefault={visitMethod} class=\"visit\">Visit Link</a>\n  <a href={'#'} on:click|preventDefault={postMethod} class=\"post\">POST Link</a>\n  <a href={'#'} on:click|preventDefault={putMethod} class=\"put\">PUT Link</a>\n  <a href={'#'} on:click|preventDefault={patchMethod} class=\"patch\">PATCH Link</a>\n  <a href={'#'} on:click|preventDefault={deleteMethod} class=\"delete\">DELETE Link</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Visits/Data/FormData.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  const visitMethod = () => {\n    const formData = new FormData()\n    formData.append('foo', 'visit')\n\n    router.visit('/dump/post', {\n      method: 'post',\n      data: formData,\n    })\n  }\n\n  const postMethod = () => {\n    const formData = new FormData()\n    formData.append('baz', 'post')\n\n    router.post('/dump/post', formData)\n  }\n\n  const putMethod = () => {\n    const formData = new FormData()\n    formData.append('foo', 'put')\n\n    router.put('/dump/put', formData)\n  }\n\n  const patchMethod = () => {\n    const formData = new FormData()\n    formData.append('bar', 'patch')\n\n    router.patch('/dump/patch', formData)\n  }\n\n  const deleteMethod = () => {\n    const formData = new FormData()\n    formData.append('baz', 'delete')\n\n    router.delete('/dump/delete', {\n      data: formData,\n    })\n  }\n</script>\n\n<div>\n  <span class=\"text\">This is the page that demonstrates manual visit data passing through FormData objects</span>\n\n  <a href={'#'} on:click|preventDefault={visitMethod} class=\"visit\">Visit Link</a>\n  <a href={'#'} on:click|preventDefault={postMethod} class=\"post\">POST Link</a>\n  <a href={'#'} on:click|preventDefault={putMethod} class=\"put\">PUT Link</a>\n  <a href={'#'} on:click|preventDefault={patchMethod} class=\"patch\">PATCH Link</a>\n  <a href={'#'} on:click|preventDefault={deleteMethod} class=\"delete\">DELETE Link</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Visits/Data/Object.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  const visitMethod = () => {\n    router.visit('/dump/get', {\n      data: { foo: 'visit' },\n    })\n  }\n\n  const getMethod = () => {\n    router.get('/dump/get', {\n      bar: 'get',\n    })\n  }\n\n  const postMethod = () => {\n    router.post('/dump/post', {\n      baz: 'post',\n    })\n  }\n\n  const putMethod = () => {\n    router.put('/dump/put', {\n      foo: 'put',\n    })\n  }\n\n  const patchMethod = () => {\n    router.patch('/dump/patch', {\n      bar: 'patch',\n    })\n  }\n\n  const deleteMethod = () => {\n    router.delete('/dump/delete', {\n      data: { baz: 'delete' },\n    })\n  }\n\n  const qsafDefault = () => {\n    router.visit('/dump/get', {\n      data: { a: ['b', 'c'] },\n    })\n  }\n\n  const qsafIndices = () => {\n    router.visit('/dump/get', {\n      data: { a: ['b', 'c'] },\n      queryStringArrayFormat: 'indices',\n    })\n  }\n\n  const qsafBrackets = () => {\n    router.visit('/dump/get', {\n      data: { a: ['b', 'c'] },\n      queryStringArrayFormat: 'brackets',\n    })\n  }\n\n  const deleteQueryParam = (e: Event) => {\n    e.preventDefault()\n    router.visit('/dump/get', {\n      data: { a: undefined },\n    })\n  }\n</script>\n\n<div>\n  <span class=\"text\">This is the page that demonstrates manual visit data passing through plain objects</span>\n\n  <a href={'#'} on:click|preventDefault={visitMethod} class=\"visit\">Visit Link</a>\n  <a href={'#'} on:click|preventDefault={getMethod} class=\"get\">GET Link</a>\n  <a href={'#'} on:click|preventDefault={postMethod} class=\"post\">POST Link</a>\n  <a href={'#'} on:click|preventDefault={putMethod} class=\"put\">PUT Link</a>\n  <a href={'#'} on:click|preventDefault={patchMethod} class=\"patch\">PATCH Link</a>\n  <a href={'#'} on:click|preventDefault={deleteMethod} class=\"delete\">DELETE Link</a>\n\n  <a href={'#'} on:click|preventDefault={qsafDefault} class=\"qsaf-default\">QSAF Defaults</a>\n  <a href={'#'} on:click|preventDefault={qsafIndices} class=\"qsaf-indices\">QSAF Indices</a>\n  <a href={'#'} on:click|preventDefault={qsafBrackets} class=\"qsaf-brackets\">QSAF Brackets</a>\n  <a href={'#'} on:click|preventDefault={deleteQueryParam} class=\"delete-query-param\">Delete Query Param</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Visits/ErrorBags.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  const defaultVisit = () => {\n    router.post('/dump/post')\n  }\n\n  const basicVisit = () => {\n    router.visit('/dump/post', {\n      method: 'post',\n      data: { foo: 'bar' },\n      errorBag: 'visitErrorBag',\n    })\n  }\n\n  const postVisit = () => {\n    router.post(\n      '/dump/post',\n      {\n        foo: 'baz',\n      },\n      {\n        errorBag: 'postErrorBag',\n      },\n    )\n  }\n</script>\n\n<div>\n  <span class=\"text\">This is the page that demonstrates error bags using manual visits</span>\n  <a href={'#'} on:click|preventDefault={defaultVisit} class=\"default\">Default visit</a>\n  <a href={'#'} on:click|preventDefault={basicVisit} class=\"visit\">Basic visit</a>\n  <a href={'#'} on:click|preventDefault={postVisit} class=\"get\">POST visit</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Visits/Headers.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  const defaultHeadersMethod = () => {\n    router.visit('/dump/get')\n  }\n\n  const visitWithCustomHeaders = () => {\n    router.visit('/dump/get', {\n      headers: {\n        foo: 'bar',\n      },\n    })\n  }\n\n  const getMethod = () => {\n    router.get(\n      '/dump/get',\n      {},\n      {\n        headers: {\n          bar: 'baz',\n        },\n      },\n    )\n  }\n\n  const postMethod = () => {\n    router.post(\n      '/dump/post',\n      {},\n      {\n        headers: {\n          baz: 'foo',\n        },\n      },\n    )\n  }\n\n  const putMethod = () => {\n    router.put(\n      '/dump/put',\n      {},\n      {\n        headers: {\n          foo: 'bar',\n        },\n      },\n    )\n  }\n\n  const patchMethod = () => {\n    router.patch(\n      '/dump/patch',\n      {},\n      {\n        headers: {\n          bar: 'baz',\n        },\n      },\n    )\n  }\n\n  const deleteMethod = () => {\n    router.delete('/dump/delete', {\n      headers: {\n        baz: 'foo',\n      },\n    })\n  }\n\n  const overridden = () => {\n    router.post(\n      '/dump/post',\n      {},\n      {\n        headers: {\n          bar: 'baz',\n          'X-Requested-With': 'custom',\n        },\n      },\n    )\n  }\n</script>\n\n<div>\n  <span class=\"text\">This is the page that demonstrates passing custom headers through manual visits</span>\n\n  <a href={'#'} on:click|preventDefault={defaultHeadersMethod} class=\"default\">Standard visit Link</a>\n\n  <a href={'#'} on:click|preventDefault={visitWithCustomHeaders} class=\"visit\">Specific visit Link</a>\n  <a href={'#'} on:click|preventDefault={getMethod} class=\"get\">GET Link</a>\n  <a href={'#'} on:click|preventDefault={postMethod} class=\"post\">POST Link</a>\n  <a href={'#'} on:click|preventDefault={putMethod} class=\"put\">PUT Link</a>\n  <a href={'#'} on:click|preventDefault={patchMethod} class=\"patch\">PATCH Link</a>\n  <a href={'#'} on:click|preventDefault={deleteMethod} class=\"delete\">DELETE Link</a>\n\n  <a href={'#'} on:click|preventDefault={overridden} class=\"overridden\">Overriden Link</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Visits/Location.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  const locationVisit = () => {\n    router.visit('/location')\n  }\n</script>\n\n<div>\n  <span class=\"text\">This is the page that demonstrates location visits</span>\n\n  <a href={'#'} on:click|preventDefault={locationVisit} class=\"example\">Location visit</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Visits/Method.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  const standardVisitMethod = () => {\n    router.visit('/dump/get')\n  }\n\n  const specificVisitMethod = () => {\n    router.visit('/dump/patch', {\n      method: 'patch',\n    })\n  }\n\n  const getMethod = () => {\n    router.get('/dump/get')\n  }\n\n  const postMethod = () => {\n    router.post('/dump/post')\n  }\n\n  const putMethod = () => {\n    router.put('/dump/put')\n  }\n\n  const patchMethod = () => {\n    router.patch('/dump/patch')\n  }\n\n  const deleteMethod = () => {\n    router.delete('/dump/delete')\n  }\n</script>\n\n<div>\n  <span class=\"text\">This is the page that demonstrates manual visit methods</span>\n\n  <a href={'#'} on:click|preventDefault={standardVisitMethod} class=\"visit-get\">Standard visit Link</a>\n  <a href={'#'} on:click|preventDefault={specificVisitMethod} class=\"visit-specific\">Specific visit Link</a>\n  <a href={'#'} on:click|preventDefault={getMethod} class=\"get\">GET Link</a>\n  <a href={'#'} on:click|preventDefault={postMethod} class=\"post\">POST Link</a>\n  <a href={'#'} on:click|preventDefault={putMethod} class=\"put\">PUT Link</a>\n  <a href={'#'} on:click|preventDefault={patchMethod} class=\"patch\">PATCH Link</a>\n  <a href={'#'} on:click|preventDefault={deleteMethod} class=\"delete\">DELETE Link</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Visits/PartialReloads.svelte",
    "content": "<script lang=\"ts\">\n  import { page, router } from '@inertiajs/svelte'\n  import { onMount } from 'svelte'\n\n  export let foo\n  export let bar\n  export let baz\n  export let headers\n\n  onMount(() => {\n    window._inertia_props = $page.props\n  })\n\n  const partialReloadVisit = () => {\n    router.visit('/visits/partial-reloads', {\n      data: { foo },\n    })\n  }\n\n  const partialReloadVisitFooBar = () => {\n    router.visit('/visits/partial-reloads', {\n      data: { foo },\n      only: ['headers', 'foo', 'bar'],\n    })\n  }\n\n  const partialReloadVisitBaz = () => {\n    router.visit('/visits/partial-reloads', {\n      data: { foo },\n      only: ['headers', 'baz'],\n    })\n  }\n\n  const partialReloadVisitExceptFooBar = () => {\n    router.visit('/visits/partial-reloads', {\n      data: { foo },\n      except: ['foo', 'bar'],\n    })\n  }\n\n  const partialReloadVisitExceptBaz = () => {\n    router.visit('/visits/partial-reloads', {\n      data: { foo },\n      except: ['baz'],\n    })\n  }\n\n  const partialReloadGet = () => {\n    router.get('/visits/partial-reloads', {\n      foo,\n    })\n  }\n\n  const partialReloadGetFooBar = () => {\n    router.get(\n      '/visits/partial-reloads',\n      {\n        foo,\n      },\n      {\n        only: ['headers', 'foo', 'bar'],\n      },\n    )\n  }\n\n  const partialReloadGetBaz = () => {\n    router.get(\n      '/visits/partial-reloads',\n      {\n        foo,\n      },\n      {\n        only: ['headers', 'baz'],\n      },\n    )\n  }\n\n  const partialReloadGetExceptFooBar = () => {\n    router.get(\n      '/visits/partial-reloads',\n      {\n        foo,\n      },\n      {\n        except: ['foo', 'bar'],\n      },\n    )\n  }\n\n  const partialReloadGetExceptBaz = () => {\n    router.get(\n      '/visits/partial-reloads',\n      {\n        foo,\n      },\n      {\n        except: ['baz'],\n      },\n    )\n  }\n</script>\n\n<div>\n  <span class=\"text\">This is the page that demonstrates partial reloads using manual visits</span>\n  <span class=\"foo-text\">Foo is now {foo}</span>\n  <span class=\"bar-text\">Bar is now {bar}</span>\n  <span class=\"baz-text\">Baz is now {baz}</span>\n  <pre class=\"headers\">{headers}</pre>\n\n  <a href={'#'} on:click|preventDefault={partialReloadVisit} class=\"visit\">Update All (visit)</a>\n  <a href={'#'} on:click|preventDefault={partialReloadVisitFooBar} class=\"visit-foo-bar\">'Only' foo + bar (visit)</a>\n  <a href={'#'} on:click|preventDefault={partialReloadVisitBaz} class=\"visit-baz\">'Only' baz (visit)</a>\n  <a href={'#'} on:click|preventDefault={partialReloadVisitExceptFooBar} class=\"visit-except-foo-bar\"\n    >'Except' foo + bar (visit)</a\n  >\n  <a href={'#'} on:click|preventDefault={partialReloadVisitExceptBaz} class=\"visit-except-baz\">'Except' baz (visit)</a>\n\n  <a href={'#'} on:click|preventDefault={partialReloadGet} class=\"get\">Update All (GET)</a>\n  <a href={'#'} on:click|preventDefault={partialReloadGetFooBar} class=\"get-foo-bar\">'Only' foo + bar (GET)</a>\n  <a href={'#'} on:click|preventDefault={partialReloadGetBaz} class=\"get-baz\">'Only' baz (GET)</a>\n  <a href={'#'} on:click|preventDefault={partialReloadGetExceptFooBar} class=\"get-except-foo-bar\"\n    >'Except' foo + bar (GET)</a\n  >\n  <a href={'#'} on:click|preventDefault={partialReloadGetExceptBaz} class=\"get-except-baz\">'Except' baz (GET)</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Visits/PreserveScroll.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  export { default as layout } from '@/Layouts/WithScrollRegion.svelte'\n</script>\n\n<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  export let foo: string = 'default'\n\n  const preserve = () => {\n    router.visit('/visits/preserve-scroll-page-two', {\n      data: { foo: 'foo' },\n      preserveScroll: true,\n    })\n  }\n\n  const preserveFalse = () => {\n    router.visit('/visits/preserve-scroll-page-two', {\n      data: { foo: 'bar' },\n    })\n  }\n\n  const preserveCallback = () => {\n    router.visit('/visits/preserve-scroll-page-two', {\n      data: { foo: 'baz' },\n      preserveScroll: (page) => {\n        console.log(JSON.stringify(page))\n\n        return true\n      },\n    })\n  }\n\n  const preserveCallbackFalse = () => {\n    router.visit('/visits/preserve-scroll-page-two', {\n      data: { foo: 'foo' },\n      preserveScroll: (page) => {\n        console.log(JSON.stringify(page))\n\n        return false\n      },\n    })\n  }\n\n  const preserveGet = () => {\n    router.get(\n      '/visits/preserve-scroll-page-two',\n      {\n        foo: 'bar',\n      },\n      {\n        preserveScroll: true,\n      },\n    )\n  }\n\n  const preserveGetFalse = () => {\n    router.get('/visits/preserve-scroll-page-two', {\n      foo: 'baz',\n    })\n  }\n</script>\n\n<div style=\"height: 800px; width: 600px\">\n  <span class=\"text\">\n    This is the page that demonstrates scroll preservation with scroll regions when using manual visits\n  </span>\n  <span class=\"foo\">Foo is now {foo}</span>\n\n  <a href={'#'} on:click|preventDefault={preserve} class=\"preserve\">Preserve Scroll</a>\n  <a href={'#'} on:click|preventDefault={preserveFalse} class=\"reset\">Reset Scroll</a>\n  <a href={'#'} on:click|preventDefault={preserveCallback} class=\"preserve-callback\">Preserve Scroll (Callback)</a>\n  <br />\n  <a href={'#'} on:click|preventDefault={preserveCallbackFalse} class=\"reset-callback\">Reset Scroll (Callback)</a>\n  <a href={'#'} on:click|preventDefault={preserveGet} class=\"preserve-get\">Preserve Scroll (GET)</a>\n  <a href={'#'} on:click|preventDefault={preserveGetFalse} class=\"reset-get\">Reset Scroll (GET)</a>\n\n  <a href=\"/non-inertia\" class=\"off-site\">Off-site link</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Visits/PreserveScrollFalse.svelte",
    "content": "<script context=\"module\" lang=\"ts\">\n  export { default as layout } from '@/Layouts/WithoutScrollRegion.svelte'\n</script>\n\n<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  export let foo: string = 'default'\n\n  const preserve = () => {\n    router.visit('/visits/preserve-scroll-false-page-two', {\n      data: { foo: 'foo' },\n      preserveScroll: true,\n    })\n  }\n\n  const preserveFalse = () => {\n    router.visit('/visits/preserve-scroll-false-page-two', {\n      data: { foo: 'bar' },\n    })\n  }\n\n  const preserveCallback = () => {\n    router.visit('/visits/preserve-scroll-false-page-two', {\n      data: { foo: 'baz' },\n      preserveScroll: (page) => {\n        console.log(JSON.stringify(page))\n\n        return true\n      },\n    })\n  }\n\n  const preserveCallbackFalse = () => {\n    router.visit('/visits/preserve-scroll-false-page-two', {\n      data: { foo: 'foo' },\n      preserveScroll: (page) => {\n        console.log(JSON.stringify(page))\n\n        return false\n      },\n    })\n  }\n\n  const preserveGet = () => {\n    router.get(\n      '/visits/preserve-scroll-false-page-two',\n      {\n        foo: 'bar',\n      },\n      {\n        preserveScroll: true,\n      },\n    )\n  }\n\n  const preserveGetFalse = () => {\n    router.get('/visits/preserve-scroll-false-page-two', {\n      foo: 'baz',\n    })\n  }\n</script>\n\n<div style=\"height: 800px; width: 600px\">\n  <span class=\"text\">\n    This is the page that demonstrates scroll preservation without scroll regions when using manual visits\n  </span>\n  <span class=\"foo\">Foo is now {foo}</span>\n\n  <a href={'#'} on:click|preventDefault={preserve} class=\"preserve\">Preserve Scroll</a>\n  <a href={'#'} on:click|preventDefault={preserveFalse} class=\"reset\">Reset Scroll</a>\n  <a href={'#'} on:click|preventDefault={preserveCallback} class=\"preserve-callback\">Preserve Scroll (Callback)</a>\n  <br />\n  <a href={'#'} on:click|preventDefault={preserveCallbackFalse} class=\"reset-callback\">Reset Scroll (Callback)</a>\n  <a href={'#'} on:click|preventDefault={preserveGet} class=\"preserve-get\">Preserve Scroll (GET)</a>\n  <a href={'#'} on:click|preventDefault={preserveGetFalse} class=\"reset-get\">Reset Scroll (GET)</a>\n\n  <a href=\"/non-inertia\" class=\"off-site\">Off-site link</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Visits/PreserveState.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n  import { onMount } from 'svelte'\n\n  export let foo = 'default'\n\n  onMount(() => {\n    window._inertia_page_key = crypto.randomUUID()\n  })\n\n  const preserve = () => {\n    router.visit('/visits/preserve-state-page-two', {\n      data: { foo: 'bar' },\n      preserveState: true,\n    })\n  }\n\n  const preserveFalse = () => {\n    router.visit('/visits/preserve-state-page-two', {\n      data: { foo: 'baz' },\n      preserveState: false,\n    })\n  }\n\n  const preserveCallback = () => {\n    router.get(\n      '/visits/preserve-state-page-two',\n      {\n        foo: 'callback-bar',\n      },\n      {\n        preserveState: (page) => {\n          alert(page)\n\n          return true\n        },\n      },\n    )\n  }\n\n  const preserveCallbackFalse = () => {\n    router.get(\n      '/visits/preserve-state-page-two',\n      {\n        foo: 'callback-baz',\n      },\n      {\n        preserveState: (page) => {\n          alert(page)\n\n          return false\n        },\n      },\n    )\n  }\n\n  const preserveGet = () => {\n    router.get(\n      '/visits/preserve-state-page-two',\n      {\n        foo: 'get-bar',\n      },\n      {\n        preserveState: true,\n      },\n    )\n  }\n\n  const preserveGetFalse = () => {\n    router.get(\n      '/visits/preserve-state-page-two',\n      {\n        foo: 'get-baz',\n      },\n      {\n        preserveState: false,\n      },\n    )\n  }\n</script>\n\n<div>\n  <span class=\"text\">This is the page that demonstrates preserve state on manual visits</span>\n  <span class=\"foo\">Foo is now {foo}</span>\n  <label>\n    Example Field\n    <input type=\"text\" name=\"example-field\" class=\"field\" />\n  </label>\n\n  <a href={'#'} on:click|preventDefault={preserve} class=\"preserve\">[State] Preserve visit: true</a>\n  <a href={'#'} on:click|preventDefault={preserveFalse} class=\"preserve-false\">[State] Preserve visit: false</a>\n  <a href={'#'} on:click|preventDefault={preserveCallback} class=\"preserve-callback\">[State] Preserve Callback: true</a>\n  <a href={'#'} on:click|preventDefault={preserveCallbackFalse} class=\"preserve-callback-false\"\n    >[State] Preserve Callback: false</a\n  >\n  <a href={'#'} on:click|preventDefault={preserveGet} class=\"preserve-get\">[State] Preserve GET: true</a>\n  <a href={'#'} on:click|preventDefault={preserveGetFalse} class=\"preserve-get-false\">[State] Preserve GET: false</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Visits/ReloadOnMount.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n  import { onMount } from 'svelte'\n\n  export let name\n\n  onMount(() => {\n    router.reload({ only: ['name'] })\n  })\n</script>\n\n<div>Name is {name}</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Visits/Replace.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  const replace = () => {\n    router.visit('/dump/get', {\n      replace: true,\n    })\n  }\n\n  const replaceFalse = () => {\n    router.visit('/dump/get', {\n      replace: false,\n    })\n  }\n\n  const replaceGet = () => {\n    router.get(\n      '/dump/get',\n      {},\n      {\n        replace: true,\n      },\n    )\n  }\n\n  const replaceGetFalse = () => {\n    router.get(\n      '/dump/get',\n      {},\n      {\n        replace: false,\n      },\n    )\n  }\n</script>\n\n<div>\n  <span class=\"text\">This is the links page that demonstrates manual replace</span>\n\n  <a href={'#'} on:click|preventDefault={replace} class=\"replace\">[State] Replace visit: true</a>\n  <a href={'#'} on:click|preventDefault={replaceFalse} class=\"replace-false\">[State] Replace visit: false</a>\n  <a href={'#'} on:click|preventDefault={replaceGet} class=\"replace-get\">[State] Replace GET: true</a>\n  <a href={'#'} on:click|preventDefault={replaceGetFalse} class=\"replace-get-false\">[State] Replace GET: false</a>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Visits/UrlFragments.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  let documentScrollTop = 0\n  let documentScrollLeft = 0\n\n  const handleScrollEvent = () => {\n    documentScrollTop = document.documentElement.scrollTop\n    documentScrollLeft = document.documentElement.scrollLeft\n    console.log(documentScrollTop, documentScrollLeft)\n  }\n\n  const basicVisit = () => {\n    router.visit('/visits/url-fragments#target')\n  }\n\n  const fragmentVisit = () => {\n    router.visit('#target')\n  }\n\n  const nonExistentFragmentVisit = () => {\n    router.visit('/visits/url-fragments#non-existent-fragment')\n  }\n\n  const basicGetVisit = () => {\n    router.get('/visits/url-fragments#target')\n  }\n\n  const fragmentGetVisit = () => {\n    router.get('#target')\n  }\n\n  const nonExistentFragmentGetVisit = () => {\n    router.get('/visits/url-fragments#non-existent-fragment')\n  }\n</script>\n\n<svelte:document on:scroll={handleScrollEvent} />\n\n<div>\n  <span class=\"text\">This is the page that demonstrates url fragment behaviour using manual visits</span>\n  <div style=\"width: 200vw; height: 200vh; margin-top: 50vh\">\n    <!-- prettier-ignore -->\n    <button on:click={handleScrollEvent}>Update scroll positions</button>\n    <div class=\"document-position\">Document scroll position is {documentScrollLeft} & {documentScrollTop}</div>\n    <a href={'#'} on:click|preventDefault={basicVisit} class=\"basic\">Basic visit</a>\n    <a href={'#'} on:click|preventDefault={fragmentVisit} class=\"fragment\">Fragment visit</a>\n    <a href={'#'} on:click|preventDefault={nonExistentFragmentVisit} class=\"non-existent-fragment\"\n      >Non-existent fragment visit</a\n    >\n\n    <a href={'#'} on:click|preventDefault={basicGetVisit} class=\"basic-get\">Basic GET visit</a>\n    <a href={'#'} on:click|preventDefault={fragmentGetVisit} class=\"fragment-get\">Fragment GET visit</a>\n    <a href={'#'} on:click|preventDefault={nonExistentFragmentGetVisit} class=\"non-existent-fragment-get\"\n      >Non-existent fragment GET visit</a\n    >\n\n    <div id=\"target\">This is the element with id 'target'</div>\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/Visits/Wayfinder.svelte",
    "content": "<script lang=\"ts\">\n  import { router } from '@inertiajs/svelte'\n\n  const wayfinderObjectVisit = () => {\n    router.visit({ url: '/dump/post', method: 'post' })\n  }\n\n  const wayfinderObjectMethodOverride = () => {\n    router.visit({ url: '/dump/patch', method: 'get' }, { method: 'patch' })\n  }\n</script>\n\n<div>\n  <a href={'#'} on:click|preventDefault={wayfinderObjectVisit} class=\"wayfinder-visit\">Wayfinder object visit</a>\n  <a href={'#'} on:click|preventDefault={wayfinderObjectMethodOverride} class=\"wayfinder-method-override\"\n    >Wayfinder object method override</a\n  >\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/WhenVisible.svelte",
    "content": "<script lang=\"ts\">\n  import { WhenVisible } from '@inertiajs/svelte'\n\n  export let count = 0\n</script>\n\n<div style=\"margin-top: 5000px\">\n  <WhenVisible data=\"foo\">\n    <svelte:fragment slot=\"fallback\">\n      <div>Loading first one...</div>\n    </svelte:fragment>\n\n    <div>First one is visible!</div>\n  </WhenVisible>\n</div>\n\n<div style=\"margin-top: 5000px\">\n  <WhenVisible buffer={1000} data=\"foo\">\n    <svelte:fragment slot=\"fallback\">\n      <div>Loading second one...</div>\n    </svelte:fragment>\n\n    <div>Second one is visible!</div>\n  </WhenVisible>\n</div>\n\n<div style=\"margin-top: 5000px\">\n  <WhenVisible data=\"foo\" always>\n    <svelte:fragment slot=\"fallback\">\n      <div>Loading third one...</div>\n    </svelte:fragment>\n\n    <div>Third one is visible!</div>\n  </WhenVisible>\n</div>\n\n<div style=\"margin-top: 5000px\">\n  <WhenVisible data=\"foo\">\n    <svelte:fragment slot=\"fallback\">\n      <div>Loading fourth one...</div>\n    </svelte:fragment>\n  </WhenVisible>\n</div>\n\n<div style=\"margin-top: 6000px\">\n  <WhenVisible\n    always\n    params={{\n      data: {\n        count,\n      },\n      onSuccess() {\n        count += 1\n      },\n    }}\n  >\n    <svelte:fragment slot=\"fallback\">\n      <div>Loading fifth one...</div>\n    </svelte:fragment>\n\n    <div>Count is now {count}</div>\n  </WhenVisible>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/WhenVisibleArrayReload.svelte",
    "content": "<script lang=\"ts\">\n  import { router, WhenVisible } from '@inertiajs/svelte'\n\n  export let firstData:\n    | {\n        text: string\n      }\n    | undefined = undefined\n\n  export let secondData:\n    | {\n        text: string\n      }\n    | undefined = undefined\n\n  const handleReload = () => {\n    router.reload()\n  }\n</script>\n\n<div>\n  <h1>WhenVisible + Array Props + Reload</h1>\n\n  <button on:click={handleReload}>Reload Page</button>\n\n  <div style=\"margin-top: 2000px; padding: 20px; border: 1px solid #ccc\">\n    <WhenVisible data={['firstData', 'secondData']}>\n      <svelte:fragment slot=\"fallback\">\n        <p>Loading array data...</p>\n      </svelte:fragment>\n\n      <div>\n        <p>{firstData?.text}</p>\n        <p>{secondData?.text}</p>\n      </div>\n    </WhenVisible>\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/WhenVisibleBackButton.svelte",
    "content": "<script lang=\"ts\">\n  import { Link, WhenVisible } from '@inertiajs/svelte'\n\n  export let lazyData:\n    | {\n        text: string\n      }\n    | undefined = undefined\n</script>\n\n<div>\n  <h1>WhenVisible + Back Button</h1>\n\n  <Link href=\"/links/method\">Navigate Away</Link>\n\n  <div style=\"margin-top: 2000px; padding: 20px; border: 1px solid #ccc\">\n    <WhenVisible data=\"lazyData\">\n      <svelte:fragment slot=\"fallback\">\n        <p>Loading lazy data...</p>\n      </svelte:fragment>\n\n      <p>{lazyData?.text}</p>\n    </WhenVisible>\n  </div>\n\n  <div style=\"margin-top: 2000px; padding: 20px; border: 1px solid #ccc\">\n    <WhenVisible data=\"lazyData\" always>\n      <svelte:fragment slot=\"fallback\">\n        <p>Loading always data...</p>\n      </svelte:fragment>\n\n      <p>Always: {lazyData?.text}</p>\n    </WhenVisible>\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/WhenVisibleFetching.svelte",
    "content": "<script>\n  import { WhenVisible } from '@inertiajs/svelte'\n</script>\n\n<div style=\"margin-top: 5000px\">\n  <WhenVisible data=\"lazyData\" always let:fetching>\n    <div>Lazy data loaded!</div>\n    {#if fetching}\n      <div>Fetching in background...</div>\n    {/if}\n\n    <svelte:fragment slot=\"fallback\">\n      <div>Loading lazy data...</div>\n    </svelte:fragment>\n  </WhenVisible>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/WhenVisibleMergeParams.svelte",
    "content": "<script lang=\"ts\">\n  import { WhenVisible } from '@inertiajs/svelte'\n\n  export let dataOnlyProp: { text: string } | undefined = undefined\n  export let mergedProp: { text: string } | undefined = undefined\n  export let mergedWithCallbackProp: { text: string } | undefined = undefined\n</script>\n\n<div id=\"data-only\" style=\"margin-top: 3000px\">\n  <WhenVisible data=\"dataOnlyProp\">\n    <svelte:fragment slot=\"fallback\">\n      <div>Loading data only...</div>\n    </svelte:fragment>\n    <div>Data only loaded: {dataOnlyProp?.text}</div>\n  </WhenVisible>\n</div>\n\n<div id=\"merged\" style=\"margin-top: 5000px\">\n  <WhenVisible\n    data=\"mergedProp\"\n    params={{\n      data: { extra: 'from-params' },\n    }}\n  >\n    <svelte:fragment slot=\"fallback\">\n      <div>Loading merged...</div>\n    </svelte:fragment>\n    <div>Merged loaded: {mergedProp?.text}</div>\n  </WhenVisible>\n</div>\n\n<div id=\"merged-with-callback\" style=\"margin-top: 5000px\">\n  <WhenVisible\n    data=\"mergedWithCallbackProp\"\n    params={{\n      data: { page: '2' },\n      preserveUrl: true,\n    }}\n  >\n    <svelte:fragment slot=\"fallback\">\n      <div>Loading merged with callback...</div>\n    </svelte:fragment>\n    <div>Merged with callback loaded: {mergedWithCallbackProp?.text}</div>\n  </WhenVisible>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/WhenVisibleParamsUpdate.svelte",
    "content": "<script>\n  import { WhenVisible } from '@inertiajs/svelte'\n\n  export let lazyData\n\n  let paramValue = 'initial'\n</script>\n\n<div>\n  <button on:click={() => (paramValue = 'updated')}>Update Param</button>\n  <p>Current param: {paramValue}</p>\n\n  <div style=\"margin-top: 3000px\">\n    <WhenVisible data=\"lazyData\" params={{ data: { paramValue } }} always>\n      <div>\n        <p>Data loaded: {lazyData?.text}</p>\n      </div>\n      <p slot=\"fallback\">Loading lazy data...</p>\n    </WhenVisible>\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/Pages/WhenVisibleReload.svelte",
    "content": "<script lang=\"ts\">\n  import { router, WhenVisible } from '@inertiajs/svelte'\n\n  export let lazyData:\n    | {\n        text: string\n      }\n    | undefined = undefined\n\n  const handleReload = () => {\n    router.reload()\n  }\n</script>\n\n<div>\n  <h1>WhenVisible + Reload</h1>\n\n  <button on:click={handleReload}>Reload Page</button>\n\n  <div style=\"margin-top: 2000px; padding: 20px; border: 1px solid #ccc\">\n    <WhenVisible data=\"lazyData\">\n      <svelte:fragment slot=\"fallback\">\n        <p>Loading lazy data...</p>\n      </svelte:fragment>\n\n      {lazyData?.text}\n    </WhenVisible>\n  </div>\n</div>\n"
  },
  {
    "path": "packages/svelte/test-app/app.ts",
    "content": "import type { VisitOptions } from '@inertiajs/core'\nimport { createInertiaApp, type ResolvedComponent, router } from '@inertiajs/svelte'\n\nwindow.testing = { Inertia: router }\n\nconst withAppDefaults = new URLSearchParams(window.location.search).get('withAppDefaults')\n\ncreateInertiaApp({\n  page: window.initialPage,\n  resolve: async (name) => {\n    const pages = import.meta.glob<ResolvedComponent>('./Pages/**/*.svelte', { eager: true })\n\n    if (name === 'DeferredProps/InstantReload') {\n      // Add small delay to ensure the component is loaded after the initial page load\n      // This is for projects that don't use { eager: true } in import.meta.glob\n      await new Promise((resolve) => setTimeout(resolve, 50))\n    }\n\n    return pages[`./Pages/${name}.svelte`]\n  },\n  setup({ el, App, props }) {\n    const hydrate = el?.hasAttribute('data-server-rendered')\n    new App({ target: el!, props, hydrate })\n  },\n  ...(withAppDefaults && {\n    defaults: {\n      visitOptions: (href: string, options: VisitOptions) => {\n        return { headers: { ...options.headers, 'X-From-App-Defaults': 'test' } }\n      },\n    },\n  }),\n})\n"
  },
  {
    "path": "packages/svelte/test-app/eslint.config.js",
    "content": "import js from '@eslint/js'\nimport svelte from 'eslint-plugin-svelte'\nimport globals from 'globals'\nimport ts from 'typescript-eslint'\nimport svelteConfig from './svelte.config.js'\n\nexport default ts.config(\n  {\n    files: ['**/*.js', '**/*.ts', '**/*.svelte'],\n  },\n  {\n    ignores: ['node_modules', 'dist/**/*', '*.config.js', '**/*.d.ts', '*.timestamp-*'],\n  },\n  js.configs.recommended,\n  ...ts.configs.recommended,\n  ...svelte.configs.recommended,\n  {\n    languageOptions: {\n      ecmaVersion: 2020,\n      sourceType: 'module',\n      globals: {\n        ...globals.browser,\n        ...globals.es2020,\n      },\n    },\n  },\n  {\n    files: ['**/*.ts', '**/*.svelte'],\n    // See more details at: https://typescript-eslint.io/packages/parser/\n    languageOptions: {\n      parserOptions: {\n        projectService: true,\n        extraFileExtensions: ['.svelte'], // Add support for additional file extensions, such as .svelte\n        parser: ts.parser,\n        // Specify a parser for each language, if needed:\n        // parser: {\n        //   ts: ts.parser,\n        //   js: espree,    // Use espree for .js files (add: import espree from 'espree')\n        //   typescript: ts.parser\n        // },\n\n        // We recommend importing and specifying svelte.config.js.\n        // By doing so, some rules in eslint-plugin-svelte will automatically read the configuration and adjust their behavior accordingly.\n        // While certain Svelte settings may be statically loaded from svelte.config.js even if you don’t specify it,\n        // explicitly specifying it ensures better compatibility and functionality.\n        //\n        // If non-serializable properties are included, running ESLint with the --cache flag will fail.\n        // In that case, please remove the non-serializable properties. (e.g. `svelteConfig: { ...svelteConfig, kit: { ...svelteConfig.kit, typescript: undefined }}`)\n        svelteConfig,\n      },\n    },\n  },\n  {\n    rules: {\n      'svelte/no-navigation-without-resolve': 'off',\n      'svelte/no-useless-mustaches': 'off',\n    },\n  },\n  {\n    files: ['**/*.ts', '**/*.svelte'],\n    rules: {\n      '@typescript-eslint/unbound-method': 'error',\n    },\n  },\n)\n"
  },
  {
    "path": "packages/svelte/test-app/index.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Inertia Svelte - Testing Environment</title>\n    <script>\n      window.initialPage = '{{ placeholder }}'\n    </script>\n    <script type=\"module\" src=\"app.ts\"></script>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/svelte/test-app/package.json",
    "content": "{\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"vite build .\",\n    \"build:ssr\": \"vite build --ssr ssr.ts --outDir dist\",\n    \"dev\": \"nodemon --watch . --watch ../../core/dist --watch ../../svelte/dist --ext js,ts,svelte,html,json --ignore dist/ --exec 'vite build .'\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"svelte-check --tsconfig ./tsconfig.json\"\n  },\n  \"devDependencies\": {\n    \"@eslint/js\": \"^9.39.3\",\n    \"@sveltejs/vite-plugin-svelte\": \"^3.1.2\",\n    \"@tsconfig/svelte\": \"^5.0.8\",\n    \"eslint\": \"^9.39.3\",\n    \"eslint-plugin-svelte\": \"^3.15.0\",\n    \"globals\": \"^17.3.0\",\n    \"nodemon\": \"^3.1.14\",\n    \"svelte\": \"^4.2.20\",\n    \"svelte-check\": \"^4.4.4\",\n    \"typescript\": \"^5.9.3\",\n    \"typescript-eslint\": \"^8.56.1\",\n    \"vite\": \"^5.4.21\"\n  },\n  \"dependencies\": {\n    \"@inertiajs/core\": \"workspace:*\",\n    \"@inertiajs/svelte\": \"workspace:*\"\n  }\n}\n"
  },
  {
    "path": "packages/svelte/test-app/ssr.ts",
    "content": "import { createInertiaApp, type ResolvedComponent } from '@inertiajs/svelte'\nimport createServer from '@inertiajs/svelte/server'\n\ncreateServer((page) =>\n  createInertiaApp({\n    page,\n    resolve: (name) => {\n      const pages = import.meta.glob<ResolvedComponent>('./Pages/SSR/**/*.svelte', { eager: true })\n      return pages[`./Pages/${name}.svelte`]\n    },\n    setup({ App, props }) {\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      return (App as any).render(props)\n    },\n    defaults: {\n      future: {\n        useScriptElementForInitialPage: page.component === 'SSR/PageWithScriptElement',\n      },\n    },\n  }),\n)\n"
  },
  {
    "path": "packages/svelte/test-app/svelte-html.d.ts",
    "content": "declare module 'svelte/elements' {\n  export interface HTMLAttributes<T extends EventTarget> {\n    'scroll-region'?: boolean | '' | undefined\n  }\n}\n\nexport {}\n"
  },
  {
    "path": "packages/svelte/test-app/svelte.config.js",
    "content": "import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'\n\nconst config = {\n  // Consult https://kit.svelte.dev/docs/integrations#preprocessors\n  // for more information about preprocessors\n  preprocess: vitePreprocess(),\n}\n\nexport default config\n"
  },
  {
    "path": "packages/svelte/test-app/tsconfig.json",
    "content": "{\n  \"extends\": \"@tsconfig/svelte/tsconfig.json\",\n  \"compilerOptions\": {\n    \"allowJs\": true,\n    \"checkJs\": true,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"resolveJsonModule\": true,\n    \"skipLibCheck\": true,\n    \"sourceMap\": true,\n    \"strict\": true,\n    \"module\": \"ESNext\",\n    \"lib\": [\"ESNext\", \"DOM\", \"DOM.Iterable\"],\n    \"moduleResolution\": \"bundler\",\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@/*\": [\"./*\"]\n    }\n  },\n  \"include\": [\"**/*.ts\", \"**/*.d.ts\", \"**/*.svelte\"]\n}\n"
  },
  {
    "path": "packages/svelte/test-app/types.d.ts",
    "content": "import type { Method, Page, PageProps, Router } from '@inertiajs/core'\n\ndeclare global {\n  interface Window {\n    testing: {\n      Inertia: Router\n    }\n    initialPage: Page\n    _inertia_request_dump: {\n      headers: Record<string, string>\n      method: Method\n      form: Record<string, unknown> | undefined\n      files: MulterFile[] | object\n      query: Record<string, unknown>\n      url: string\n      $page: Page\n    }\n    _inertia_page_key: string | undefined\n    _inertia_props: PageProps\n    _inertia_layout_id: number | string | undefined\n    _inertia_site_layout_props: PageProps\n    _inertia_nested_layout_id: number | string | undefined\n    _inertia_nested_layout_props: PageProps\n    _inertia_page_props: PageProps\n    _plugin_global_props: object\n  }\n\n  interface ImportMeta {\n    readonly glob: <T>(pattern: string, options: { eager: true }) => Record<string, T>\n  }\n}\n\nexport type MulterFile = Express.Multer.File\n"
  },
  {
    "path": "packages/svelte/test-app/vite-env.d.ts",
    "content": "/// <reference types=\"svelte\" />\n/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "packages/svelte/test-app/vite.config.js",
    "content": "import { svelte } from '@sveltejs/vite-plugin-svelte'\nimport { defineConfig } from 'vite'\n\nconst isSSR = process.argv.includes('--ssr')\n\nexport default defineConfig({\n  build: {\n    sourcemap: 'inline',\n    emptyOutDir: !isSSR,\n  },\n  resolve: {\n    alias: {\n      '@': __dirname,\n    },\n  },\n  plugins: [\n    svelte({\n      compilerOptions: {\n        hydratable: true,\n      },\n    }),\n  ],\n})\n"
  },
  {
    "path": "packages/svelte/tsconfig.json",
    "content": "{\n  \"extends\": \"./.svelte-kit/tsconfig.json\",\n  \"compilerOptions\": {\n    \"allowJs\": true,\n    \"checkJs\": true,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"resolveJsonModule\": true,\n    \"skipLibCheck\": true,\n    \"sourceMap\": true,\n    \"strict\": true,\n    \"declaration\": true,\n    \"declarationDir\": \"dist\",\n\n    \"module\": \"ES2020\",\n    \"moduleResolution\": \"Node\",\n    \"allowSyntheticDefaultImports\": true,\n\n    \"noImplicitThis\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"preserveConstEnums\": true,\n    \"removeComments\": true\n  }\n}\n"
  },
  {
    "path": "packages/svelte/vite-with-deps.config.js",
    "content": "import { svelte } from '@sveltejs/vite-plugin-svelte'\nimport { defineConfig } from 'vite'\n\nexport default defineConfig({\n  plugins: [svelte()],\n  build: {\n    minify: false,\n    lib: {\n      entry: './src/index.ts',\n      formats: ['es'],\n      fileName: 'index',\n    },\n    rollupOptions: {\n      // Only externalize Svelte (peer dependency) - bundle everything else\n      external: ['svelte', 'svelte/internal', 'svelte/store'],\n    },\n  },\n})\n"
  },
  {
    "path": "packages/svelte/vite.config.js",
    "content": "import { sveltekit } from '@sveltejs/kit/vite'\nimport { defineConfig } from 'vite'\n\nexport default defineConfig({\n  build: {\n    minify: false,\n  },\n  plugins: [sveltekit()],\n})\n"
  },
  {
    "path": "packages/vue3/.gitignore",
    "content": "dist\ntypes\nnode_modules\npackage-lock.json\nyarn.lock\n/test-results/\n/blob-report/\n/playwright/.cache/\n"
  },
  {
    "path": "packages/vue3/LICENSE",
    "content": "MIT License\n\nCopyright (c) Jonathan Reinink <jonathan@reinink.ca>\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": "packages/vue3/build.js",
    "content": "#!/usr/bin/env node\nimport esbuild from 'esbuild'\nimport { nodeExternalsPlugin } from 'esbuild-node-externals'\nimport { readFileSync } from 'fs'\n\nconst watch = process.argv.slice(1).includes('--watch')\nconst withDeps = process.argv.slice(1).includes('--with-deps')\n\n// For regular builds, externalize all dependencies to keep the bundle size small (using nodeExternalsPlugin).\n// For builds with dependencies, only externalize peer dependencies and bundle everything\n// else so we can check ES2020 compatibility without checking framework code.\nlet externalDependencies = undefined\n\nif (withDeps) {\n  const pkg = JSON.parse(readFileSync('./package.json', 'utf8'))\n  externalDependencies = Object.keys(pkg.peerDependencies || {})\n}\n\nconst config = {\n  bundle: true,\n  minify: false,\n  sourcemap: withDeps ? false : true,\n  target: 'es2020',\n  external: externalDependencies,\n  plugins: [\n    ...(withDeps ? [] : [nodeExternalsPlugin()]),\n    {\n      name: 'inertia',\n      setup(build) {\n        let count = 0\n        build.onEnd((result) => {\n          if (count++ !== 0) {\n            console.log(`Rebuilding ${build.initialOptions.entryPoints} (${build.initialOptions.format})…`)\n          }\n        })\n      },\n    },\n  ],\n}\n\nconst builds = [\n  { entryPoints: ['src/index.ts'], format: 'esm', outfile: 'dist/index.esm.js', platform: 'browser' },\n  { entryPoints: ['src/index.ts'], format: 'cjs', outfile: 'dist/index.js', platform: 'browser' },\n  { entryPoints: ['src/server.ts'], format: 'esm', outfile: 'dist/server.esm.js', platform: 'node' },\n  { entryPoints: ['src/server.ts'], format: 'cjs', outfile: 'dist/server.js', platform: 'node' },\n]\n\nbuilds.forEach(async (build) => {\n  const context = await esbuild.context({ ...config, ...build })\n\n  if (watch) {\n    console.log(`Watching ${build.entryPoints} (${build.format})…`)\n    await context.watch()\n  } else {\n    await context.rebuild()\n    context.dispose()\n    console.log(`Built ${build.entryPoints} (${build.format}) ${withDeps ? '(with-deps)' : ''}…`)\n  }\n})\n"
  },
  {
    "path": "packages/vue3/package.json",
    "content": "{\n  \"name\": \"@inertiajs/vue3\",\n  \"version\": \"2.3.18\",\n  \"license\": \"MIT\",\n  \"description\": \"The Vue 3 adapter for Inertia.js\",\n  \"contributors\": [\n    \"Jonathan Reinink <jonathan@reinink.ca>\"\n  ],\n  \"homepage\": \"https://inertiajs.com/\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/inertiajs/inertia.git\",\n    \"directory\": \"packages/vue3\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/inertiajs/inertia/issues\"\n  },\n  \"files\": [\n    \"dist\",\n    \"types\",\n    \"resources\"\n  ],\n  \"type\": \"module\",\n  \"main\": \"dist/index.js\",\n  \"types\": \"types/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./types/index.d.ts\",\n      \"import\": \"./dist/index.esm.js\",\n      \"require\": \"./dist/index.js\"\n    },\n    \"./server\": {\n      \"types\": \"./types/server.d.ts\",\n      \"import\": \"./dist/server.esm.js\",\n      \"require\": \"./dist/server.js\"\n    }\n  },\n  \"typesVersions\": {\n    \"*\": {\n      \"server\": [\n        \"types/server.d.ts\"\n      ]\n    }\n  },\n  \"scripts\": {\n    \"build\": \"pnpm clean && ./build.js && tsc\",\n    \"build:with-deps\": \"./build.js --with-deps\",\n    \"clean\": \"rm -rf types && rm -rf dist\",\n    \"dev\": \"pnpx concurrently -c \\\"#ffcf00,#3178c6\\\" \\\"pnpm dev:build\\\" \\\"pnpm dev:types\\\" --names build,types\",\n    \"dev:build\": \"./build.js --watch\",\n    \"dev:types\": \"tsc --watch --preserveWatchOutput\",\n    \"es2020-check\": \"pnpm build:with-deps && es-check es2020 \\\"dist/index.esm.js\\\" --checkFeatures --module --noCache --verbose\"\n  },\n  \"devDependencies\": {\n    \"axios\": \"^1.13.5\",\n    \"es-check\": \"^9.6.1\",\n    \"esbuild\": \"^0.27.3\",\n    \"esbuild-node-externals\": \"^1.20.1\",\n    \"typescript\": \"^5.9.3\",\n    \"vue\": \"^3.5.29\"\n  },\n  \"peerDependencies\": {\n    \"vue\": \"^3.0.0\"\n  },\n  \"dependencies\": {\n    \"@inertiajs/core\": \"workspace:*\",\n    \"@types/lodash-es\": \"^4.17.12\",\n    \"laravel-precognition\": \"^1.0.2\",\n    \"lodash-es\": \"^4.17.23\"\n  }\n}\n"
  },
  {
    "path": "packages/vue3/readme.md",
    "content": "# Inertia.js Vue 3 Adapter\n\nVisit [inertiajs.com](https://inertiajs.com/) to learn more.\n"
  },
  {
    "path": "packages/vue3/resources/boost/guidelines/core.blade.php",
    "content": "# Inertia + Vue\n\nVue components must have a single root element.\n- IMPORTANT: Activate `inertia-vue-development` when working with Inertia Vue client-side patterns.\n"
  },
  {
    "path": "packages/vue3/resources/boost/skills/inertia-vue-development/SKILL.blade.php",
    "content": "---\nname: inertia-vue-development\ndescription: \"Develops Inertia.js v2 Vue client-side applications. Activates when creating Vue pages, forms, or navigation; using <Link>, <Form>, useForm, or router; working with deferred props, prefetching, or polling; or when user mentions Vue with Inertia, Vue pages, Vue forms, or Vue navigation.\"\nlicense: MIT\nmetadata:\n  author: laravel\n---\n@php\n/** @var \\Laravel\\Boost\\Install\\GuidelineAssist $assist */\n@endphp\n# Inertia Vue Development\n\n## When to Apply\n\nActivate this skill when:\n\n- Creating or modifying Vue page components for Inertia\n- Working with forms in Vue (using `<Form>` or `useForm`)\n- Implementing client-side navigation with `<Link>` or `router`\n- Using v2 features: deferred props, prefetching, WhenVisible, InfiniteScroll, once props, flash data, or polling\n- Building Vue-specific features with the Inertia protocol\n\n## Documentation\n\nUse `search-docs` for detailed Inertia v2 Vue patterns and documentation.\n\n## Basic Usage\n\n### Page Components Location\n\nVue page components should be placed in the `{{ $assist->inertia()->pagesDirectory() }}` directory.\n\n### Page Component Structure\n\n@verbatim\n@boostsnippet(\"Basic Vue Page Component\", \"vue\")\n<script setup>\ndefineProps({\n    users: Array\n})\n</script>\n\n<template>\n    <div>\n        <h1>Users</h1>\n        <ul>\n            <li v-for=\"user in users\" :key=\"user.id\">\n                {{ user.name }}\n            </li>\n        </ul>\n    </div>\n</template>\n@endboostsnippet\n@endverbatim\n\n## Client-Side Navigation\n\n### Basic Link Component\n\nUse `<Link>` for client-side navigation instead of traditional `<a>` tags:\n\n@boostsnippet(\"Inertia Vue Navigation\", \"vue\")\n<script setup>\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n    <div>\n        <Link href=\"/\">Home</Link>\n        <Link href=\"/users\">Users</Link>\n        <Link :href=\"`/users/${user.id}`\">View User</Link>\n    </div>\n</template>\n@endboostsnippet\n\n### Link with Method\n\n@boostsnippet(\"Link with POST Method\", \"vue\")\n<script setup>\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n    <Link href=\"/logout\" method=\"post\" as=\"button\">\n        Logout\n    </Link>\n</template>\n@endboostsnippet\n\n### Prefetching\n\nPrefetch pages to improve perceived performance:\n\n@boostsnippet(\"Prefetch on Hover\", \"vue\")\n<script setup>\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n    <Link href=\"/users\" prefetch>\n        Users\n    </Link>\n</template>\n@endboostsnippet\n\n### Programmatic Navigation\n\n@boostsnippet(\"Router Visit\", \"vue\")\n<script setup>\nimport { router } from '@inertiajs/vue3'\n\nfunction handleClick() {\n    router.visit('/users')\n}\n\n// Or with options\nfunction createUser() {\n    router.visit('/users', {\n        method: 'post',\n        data: { name: 'John' },\n        onSuccess: () => console.log('Done'),\n    })\n}\n</script>\n\n<template>\n    <Link href=\"/users\">Users</Link>\n    <Link href=\"/logout\" method=\"post\" as=\"button\">Logout</Link>\n</template>\n@endboostsnippet\n\n## Form Handling\n\n@if($assist->inertia()->hasFormComponent())\n### Form Component (Recommended)\n\nThe recommended way to build forms is with the `<Form>` component:\n\n@verbatim\n@boostsnippet(\"Form Component Example\", \"vue\")\n<script setup>\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n    <Form action=\"/users\" method=\"post\" #default=\"{ errors, processing, wasSuccessful }\">\n        <input type=\"text\" name=\"name\" />\n        <div v-if=\"errors.name\">{{ errors.name }}</div>\n\n        <input type=\"email\" name=\"email\" />\n        <div v-if=\"errors.email\">{{ errors.email }}</div>\n\n        <button type=\"submit\" :disabled=\"processing\">\n            {{ processing ? 'Creating...' : 'Create User' }}\n        </button>\n\n        <div v-if=\"wasSuccessful\">User created!</div>\n    </Form>\n</template>\n@endboostsnippet\n@endverbatim\n\n### Form Component With All Props\n\n@verbatim\n@boostsnippet(\"Form Component Full Example\", \"vue\")\n<script setup>\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n    <Form\n        action=\"/users\"\n        method=\"post\"\n        #default=\"{\n            errors,\n            hasErrors,\n            processing,\n            progress,\n            wasSuccessful,\n            recentlySuccessful,\n            setError,\n            clearErrors,\n            resetAndClearErrors,\n            defaults,\n            isDirty,\n            reset,\n            submit\n        }\"\n    >\n        <input type=\"text\" name=\"name\" :value=\"defaults.name\" />\n        <div v-if=\"errors.name\">{{ errors.name }}</div>\n\n        <button type=\"submit\" :disabled=\"processing\">\n            {{ processing ? 'Saving...' : 'Save' }}\n        </button>\n\n        <progress v-if=\"progress\" :value=\"progress.percentage\" max=\"100\">\n            {{ progress.percentage }}%\n        </progress>\n\n        <div v-if=\"wasSuccessful\">Saved!</div>\n    </Form>\n</template>\n@endboostsnippet\n@endverbatim\n\n@if($assist->inertia()->hasFormComponentResets())\n### Form Component Reset Props\n\nThe `<Form>` component supports automatic resetting:\n\n- `resetOnError` - Reset form data when the request fails\n- `resetOnSuccess` - Reset form data when the request succeeds\n- `setDefaultsOnSuccess` - Update default values on success\n\nUse the `search-docs` tool with a query of `form component resetting` for detailed guidance.\n\n@verbatim\n@boostsnippet(\"Form with Reset Props\", \"vue\")\n<script setup>\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n    <Form\n        action=\"/users\"\n        method=\"post\"\n        reset-on-success\n        set-defaults-on-success\n        #default=\"{ errors, processing, wasSuccessful }\"\n    >\n        <input type=\"text\" name=\"name\" />\n        <div v-if=\"errors.name\">{{ errors.name }}</div>\n\n        <button type=\"submit\" :disabled=\"processing\">\n            Submit\n        </button>\n    </Form>\n</template>\n@endboostsnippet\n@endverbatim\n@else\nNote: This version of Inertia does not support `resetOnError`, `resetOnSuccess`, or `setDefaultsOnSuccess` on the `<Form>` component. Using these props will cause errors. Upgrade to Inertia v2.2.0+ to use these features.\n@endif\n\nForms can also be built using the `useForm` composable for more programmatic control. Use the `search-docs` tool with a query of `useForm helper` for guidance.\n\n@endif\n\n### `useForm` Composable\n\n@if($assist->inertia()->hasFormComponent() === false)\nFor Inertia v2.0.x: Build forms using the `useForm` composable as the `<Form>` component is not available until v2.1.0+.\n@else\nFor more programmatic control or to follow existing conventions, use the `useForm` composable:\n@endif\n\n@verbatim\n@boostsnippet(\"useForm Composable Example\", \"vue\")\n<script setup>\nimport { useForm } from '@inertiajs/vue3'\n\nconst form = useForm({\n    name: '',\n    email: '',\n    password: '',\n})\n\nfunction submit() {\n    form.post('/users', {\n        onSuccess: () => form.reset('password'),\n    })\n}\n</script>\n\n<template>\n    <form @submit.prevent=\"submit\">\n        <input type=\"text\" v-model=\"form.name\" />\n        <div v-if=\"form.errors.name\">{{ form.errors.name }}</div>\n\n        <input type=\"email\" v-model=\"form.email\" />\n        <div v-if=\"form.errors.email\">{{ form.errors.email }}</div>\n\n        <input type=\"password\" v-model=\"form.password\" />\n        <div v-if=\"form.errors.password\">{{ form.errors.password }}</div>\n\n        <button type=\"submit\" :disabled=\"form.processing\">\n            Create User\n        </button>\n    </form>\n</template>\n@endboostsnippet\n@endverbatim\n\n## Inertia v2 Features\n\n### Deferred Props\n\nUse deferred props to load data after initial page render:\n\n@verbatim\n@boostsnippet(\"Deferred Props with Empty State\", \"vue\")\n<script setup>\ndefineProps({\n    users: Array\n})\n</script>\n\n<template>\n    <div>\n        <h1>Users</h1>\n        <div v-if=\"!users\" class=\"animate-pulse\">\n            <div class=\"h-4 bg-gray-200 rounded w-3/4 mb-2\"></div>\n            <div class=\"h-4 bg-gray-200 rounded w-1/2\"></div>\n        </div>\n        <ul v-else>\n            <li v-for=\"user in users\" :key=\"user.id\">\n                {{ user.name }}\n            </li>\n        </ul>\n    </div>\n</template>\n@endboostsnippet\n@endverbatim\n\n### Polling\n\nAutomatically refresh data at intervals:\n\n@verbatim\n@boostsnippet(\"Polling Example\", \"vue\")\n<script setup>\nimport { router } from '@inertiajs/vue3'\nimport { onMounted, onUnmounted } from 'vue'\n\ndefineProps({\n    stats: Object\n})\n\nlet interval\n\nonMounted(() => {\n    interval = setInterval(() => {\n        router.reload({ only: ['stats'] })\n    }, 5000) // Poll every 5 seconds\n})\n\nonUnmounted(() => {\n    clearInterval(interval)\n})\n</script>\n\n<template>\n    <div>\n        <h1>Dashboard</h1>\n        <div>Active Users: {{ stats.activeUsers }}</div>\n    </div>\n</template>\n@endboostsnippet\n@endverbatim\n\n### WhenVisible\n\nLazy-load a prop when an element scrolls into view. Useful for deferring expensive data that sits below the fold:\n\n@verbatim\n@boostsnippet(\"WhenVisible Example\", \"vue\")\n<script setup>\nimport { WhenVisible } from '@inertiajs/vue3'\n\ndefineProps({\n    stats: Object\n})\n</script>\n\n<template>\n    <div>\n        <h1>Dashboard</h1>\n\n        <!-- stats prop is loaded only when this section scrolls into view -->\n        <WhenVisible data=\"stats\" :buffer=\"200\">\n            <template #fallback>\n                <div class=\"animate-pulse\">Loading stats...</div>\n            </template>\n\n            <template #default=\"{ fetching }\">\n                <div>\n                    <p>Total Users: {{ stats.total_users }}</p>\n                    <p>Revenue: {{ stats.revenue }}</p>\n                    <span v-if=\"fetching\">Refreshing...</span>\n                </div>\n            </template>\n        </WhenVisible>\n    </div>\n</template>\n@endboostsnippet\n@endverbatim\n\n## Server-Side Patterns\n\nServer-side patterns (Inertia::render, props, middleware) are covered in inertia-laravel guidelines.\n\n## Common Pitfalls\n\n- Using traditional `<a>` links instead of Inertia's `<Link>` component (breaks SPA behavior)\n- Forgetting that Vue components must have a single root element\n- Forgetting to add loading states (skeleton screens) when using deferred props\n- Not handling the `undefined` state of deferred props before data loads\n- Using `<form>` without preventing default submission (use `<Form>` component or `@submit.prevent`)\n- Forgetting to check if `<Form>` component is available in your Inertia version\n"
  },
  {
    "path": "packages/vue3/src/app.ts",
    "content": "import {\n  createHeadManager,\n  HeadManager,\n  HeadManagerOnUpdateCallback,\n  HeadManagerTitleCallback,\n  Page,\n  PageProps,\n  router,\n  SharedPageProps,\n} from '@inertiajs/core'\nimport {\n  computed,\n  DefineComponent,\n  defineComponent,\n  h,\n  markRaw,\n  Plugin,\n  PropType,\n  reactive,\n  ref,\n  shallowRef,\n} from 'vue'\nimport remember from './remember'\nimport { VuePageHandlerArgs } from './types'\nimport useForm from './useForm'\n\nexport interface InertiaAppProps<SharedProps extends PageProps = PageProps> {\n  initialPage: Page<SharedProps>\n  initialComponent?: DefineComponent\n  resolveComponent?: (name: string) => DefineComponent | Promise<DefineComponent>\n  titleCallback?: HeadManagerTitleCallback\n  onHeadUpdate?: HeadManagerOnUpdateCallback\n}\n\nexport type InertiaApp = DefineComponent<InertiaAppProps>\n\nconst component = ref<DefineComponent | undefined>(undefined)\nconst page = ref<Page>()\nconst layout = shallowRef(null)\nconst key = ref<number | undefined>(undefined)\nlet headManager: HeadManager\n\nconst App: InertiaApp = defineComponent({\n  name: 'Inertia',\n  props: {\n    initialPage: {\n      type: Object as PropType<Page>,\n      required: true,\n    },\n    initialComponent: {\n      type: Object as PropType<DefineComponent>,\n      required: false,\n    },\n    resolveComponent: {\n      type: Function as PropType<(name: string) => DefineComponent | Promise<DefineComponent>>,\n      required: false,\n    },\n    titleCallback: {\n      type: Function as PropType<HeadManagerTitleCallback>,\n      required: false,\n      default: (title: string) => title,\n    },\n    onHeadUpdate: {\n      type: Function as PropType<HeadManagerOnUpdateCallback>,\n      required: false,\n      default: () => () => {},\n    },\n  },\n  setup({ initialPage, initialComponent, resolveComponent, titleCallback, onHeadUpdate }: InertiaAppProps) {\n    component.value = initialComponent ? markRaw(initialComponent) : undefined\n    page.value = { ...initialPage, flash: initialPage.flash ?? {} }\n    key.value = undefined\n\n    const isServer = typeof window === 'undefined'\n    headManager = createHeadManager(isServer, titleCallback || ((title: string) => title), onHeadUpdate || (() => {}))\n\n    if (!isServer) {\n      router.init<DefineComponent>({\n        initialPage,\n        resolveComponent: resolveComponent!,\n        swapComponent: async (options: VuePageHandlerArgs) => {\n          component.value = markRaw(options.component)\n          page.value = options.page\n          key.value = options.preserveState ? key.value : Date.now()\n        },\n        onFlash: (flash) => {\n          page.value = { ...page.value!, flash }\n        },\n      })\n\n      router.on('navigate', () => headManager.forceUpdate())\n    }\n\n    return () => {\n      if (component.value) {\n        component.value.inheritAttrs = !!component.value.inheritAttrs\n\n        const child = h(component.value, {\n          ...page.value!.props,\n          key: key.value,\n        })\n\n        if (layout.value) {\n          component.value.layout = layout.value\n          layout.value = null\n        }\n\n        if (component.value.layout) {\n          if (typeof component.value.layout === 'function') {\n            return component.value.layout(h, child)\n          }\n\n          return (Array.isArray(component.value.layout) ? component.value.layout : [component.value.layout])\n            .concat(child)\n            .reverse()\n            .reduce((child, layout) => {\n              layout.inheritAttrs = !!layout.inheritAttrs\n              return h(layout, { ...page.value!.props }, () => child)\n            })\n        }\n\n        return child\n      }\n    }\n  },\n})\nexport default App\n\nexport const plugin: Plugin = {\n  install(app) {\n    router.form = useForm\n\n    Object.defineProperty(app.config.globalProperties, '$inertia', { get: () => router })\n    Object.defineProperty(app.config.globalProperties, '$page', { get: () => page.value })\n    Object.defineProperty(app.config.globalProperties, '$headManager', { get: () => headManager })\n\n    app.mixin(remember)\n  },\n}\n\nexport function usePage<TPageProps extends PageProps = PageProps>(): Page<TPageProps & SharedPageProps> {\n  return reactive({\n    props: computed(() => page.value?.props),\n    url: computed(() => page.value?.url),\n    component: computed(() => page.value?.component),\n    version: computed(() => page.value?.version),\n    clearHistory: computed(() => page.value?.clearHistory),\n    deferredProps: computed(() => page.value?.deferredProps),\n    mergeProps: computed(() => page.value?.mergeProps),\n    prependProps: computed(() => page.value?.prependProps),\n    deepMergeProps: computed(() => page.value?.deepMergeProps),\n    matchPropsOn: computed(() => page.value?.matchPropsOn),\n    rememberedState: computed(() => page.value?.rememberedState),\n    encryptHistory: computed(() => page.value?.encryptHistory),\n    flash: computed(() => page.value?.flash),\n  }) as Page<TPageProps>\n}\n"
  },
  {
    "path": "packages/vue3/src/createInertiaApp.ts",
    "content": "import {\n  CreateInertiaAppOptionsForCSR,\n  CreateInertiaAppOptionsForSSR,\n  getInitialPageFromDOM,\n  InertiaAppResponse,\n  InertiaAppSSRResponse,\n  Page,\n  PageProps,\n  router,\n  setupProgress,\n  SharedPageProps,\n} from '@inertiajs/core'\nimport { createSSRApp, DefineComponent, h, Plugin, App as VueApp } from 'vue'\nimport App, { InertiaApp, InertiaAppProps, plugin } from './app'\nimport { config } from './index'\nimport { VueInertiaAppConfig } from './types'\n\ntype ComponentResolver = (name: string) => DefineComponent | Promise<DefineComponent> | { default: DefineComponent }\n\ntype SetupOptions<ElementType, SharedProps extends PageProps> = {\n  el: ElementType\n  App: InertiaApp\n  props: InertiaAppProps<SharedProps>\n  plugin: Plugin\n}\n\ntype InertiaAppOptionsForCSR<SharedProps extends PageProps> = CreateInertiaAppOptionsForCSR<\n  SharedProps,\n  ComponentResolver,\n  SetupOptions<HTMLElement, SharedProps>,\n  void,\n  VueInertiaAppConfig\n>\n\ntype InertiaAppOptionsForSSR<SharedProps extends PageProps> = CreateInertiaAppOptionsForSSR<\n  SharedProps,\n  ComponentResolver,\n  SetupOptions<null, SharedProps>,\n  VueApp,\n  VueInertiaAppConfig\n> & {\n  render: (app: VueApp) => Promise<string>\n}\n\nexport default async function createInertiaApp<SharedProps extends PageProps = PageProps & SharedPageProps>(\n  options: InertiaAppOptionsForCSR<SharedProps>,\n): Promise<void>\nexport default async function createInertiaApp<SharedProps extends PageProps = PageProps & SharedPageProps>(\n  options: InertiaAppOptionsForSSR<SharedProps>,\n): Promise<InertiaAppSSRResponse>\nexport default async function createInertiaApp<SharedProps extends PageProps = PageProps & SharedPageProps>({\n  id = 'app',\n  resolve,\n  setup,\n  title,\n  progress = {},\n  page,\n  render,\n  defaults = {},\n}: InertiaAppOptionsForCSR<SharedProps> | InertiaAppOptionsForSSR<SharedProps>): InertiaAppResponse {\n  config.replace(defaults)\n\n  const isServer = typeof window === 'undefined'\n  const useScriptElementForInitialPage = config.get('future.useScriptElementForInitialPage')\n  const initialPage = page || getInitialPageFromDOM<Page<SharedProps>>(id, useScriptElementForInitialPage)!\n\n  const resolveComponent = (name: string) => Promise.resolve(resolve(name)).then((module) => module.default || module)\n\n  let head: string[] = []\n\n  const vueApp = await Promise.all([\n    resolveComponent(initialPage.component),\n    router.decryptHistory().catch(() => {}),\n  ]).then(([initialComponent]) => {\n    const props = {\n      initialPage,\n      initialComponent,\n      resolveComponent,\n      titleCallback: title,\n    }\n\n    if (isServer) {\n      const ssrSetup = setup as (options: SetupOptions<null, SharedProps>) => VueApp\n\n      return ssrSetup({\n        el: null,\n        App,\n        props: { ...props, onHeadUpdate: (elements: string[]) => (head = elements) },\n        plugin,\n      })\n    }\n\n    const csrSetup = setup as (options: SetupOptions<HTMLElement, SharedProps>) => void\n\n    return csrSetup({\n      el: document.getElementById(id)!,\n      App,\n      props,\n      plugin,\n    })\n  })\n\n  if (!isServer && progress) {\n    setupProgress(progress)\n  }\n\n  if (isServer && render) {\n    const element = () => {\n      if (!useScriptElementForInitialPage) {\n        return h('div', {\n          id,\n          'data-page': JSON.stringify(initialPage),\n          innerHTML: vueApp ? render(vueApp) : '',\n        })\n      }\n\n      return [\n        h('script', {\n          'data-page': id,\n          type: 'application/json',\n          innerHTML: JSON.stringify(initialPage).replace(/\\//g, '\\\\/'),\n        }),\n        h('div', {\n          id,\n          innerHTML: vueApp ? render(vueApp) : '',\n        }),\n      ]\n    }\n\n    const body = await render(\n      createSSRApp({\n        render: () => element(),\n      }),\n    )\n\n    return { head, body }\n  }\n}\n"
  },
  {
    "path": "packages/vue3/src/deferred.ts",
    "content": "import { defineComponent } from 'vue'\n\nexport default defineComponent({\n  name: 'Deferred',\n  props: {\n    data: {\n      type: [String, Array<String>],\n      required: true,\n    },\n  },\n  render() {\n    const keys = (Array.isArray(this.$props.data) ? this.$props.data : [this.$props.data]) as string[]\n\n    if (!this.$slots.fallback) {\n      throw new Error('`<Deferred>` requires a `<template #fallback>` slot')\n    }\n\n    return keys.every((key) => this.$page.props[key] !== undefined) ? this.$slots.default?.() : this.$slots.fallback()\n  },\n})\n"
  },
  {
    "path": "packages/vue3/src/form.ts",
    "content": "import {\n  config,\n  Errors,\n  FormComponentProps,\n  FormComponentRef,\n  FormComponentResetSymbol,\n  FormComponentSlotProps,\n  FormDataConvertible,\n  formDataToObject,\n  isUrlMethodPair,\n  mergeDataIntoQueryString,\n  Method,\n  resetFormFields,\n  UseFormUtils,\n  VisitOptions,\n} from '@inertiajs/core'\nimport { NamedInputEvent, ValidationConfig } from 'laravel-precognition'\nimport { isEqual } from 'lodash-es'\nimport {\n  computed,\n  defineComponent,\n  h,\n  inject,\n  InjectionKey,\n  onBeforeUnmount,\n  onMounted,\n  PropType,\n  provide,\n  ref,\n  SlotsType,\n  watch,\n} from 'vue'\nimport useForm from './useForm'\n\ntype FormSubmitOptions = Omit<VisitOptions, 'data' | 'onPrefetched' | 'onPrefetching'>\ntype FormSubmitter = HTMLElement | null\n\nconst noop = () => undefined\n\nconst FormContextKey: InjectionKey<FormComponentRef> = Symbol('InertiaFormContext')\n\nconst Form = defineComponent({\n  name: 'Form',\n  slots: Object as SlotsType<{\n    default: FormComponentSlotProps\n  }>,\n  props: {\n    action: {\n      type: [String, Object] as PropType<FormComponentProps['action']>,\n      default: '',\n    },\n    method: {\n      type: String as PropType<FormComponentProps['method']>,\n      default: 'get',\n    },\n    headers: {\n      type: Object as PropType<FormComponentProps['headers']>,\n      default: () => ({}),\n    },\n    queryStringArrayFormat: {\n      type: String as PropType<FormComponentProps['queryStringArrayFormat']>,\n      default: 'brackets',\n    },\n    errorBag: {\n      type: [String, null] as PropType<FormComponentProps['errorBag']>,\n      default: null,\n    },\n    showProgress: {\n      type: Boolean,\n      default: true,\n    },\n    transform: {\n      type: Function as PropType<FormComponentProps['transform']>,\n      default: (data: Record<string, FormDataConvertible>) => data,\n    },\n    options: {\n      type: Object as PropType<FormComponentProps['options']>,\n      default: () => ({}),\n    },\n    resetOnError: {\n      type: [Boolean, Array] as PropType<FormComponentProps['resetOnError']>,\n      default: false,\n    },\n    resetOnSuccess: {\n      type: [Boolean, Array] as PropType<FormComponentProps['resetOnSuccess']>,\n      default: false,\n    },\n    setDefaultsOnSuccess: {\n      type: Boolean as PropType<FormComponentProps['setDefaultsOnSuccess']>,\n      default: false,\n    },\n    onCancelToken: {\n      type: Function as PropType<FormComponentProps['onCancelToken']>,\n      default: noop,\n    },\n    onBefore: {\n      type: Function as PropType<FormComponentProps['onBefore']>,\n      default: noop,\n    },\n    onStart: {\n      type: Function as PropType<FormComponentProps['onStart']>,\n      default: noop,\n    },\n    onProgress: {\n      type: Function as PropType<FormComponentProps['onProgress']>,\n      default: noop,\n    },\n    onFinish: {\n      type: Function as PropType<FormComponentProps['onFinish']>,\n      default: noop,\n    },\n    onCancel: {\n      type: Function as PropType<FormComponentProps['onCancel']>,\n      default: noop,\n    },\n    onSuccess: {\n      type: Function as PropType<FormComponentProps['onSuccess']>,\n      default: noop,\n    },\n    onError: {\n      type: Function as PropType<FormComponentProps['onError']>,\n      default: noop,\n    },\n    onSubmitComplete: {\n      type: Function as PropType<FormComponentProps['onSubmitComplete']>,\n      default: noop,\n    },\n    disableWhileProcessing: {\n      type: Boolean,\n      default: false,\n    },\n    invalidateCacheTags: {\n      type: [String, Array] as PropType<FormComponentProps['invalidateCacheTags']>,\n      default: () => [],\n    },\n    validateFiles: {\n      type: Boolean as PropType<FormComponentProps['validateFiles']>,\n      default: false,\n    },\n    validationTimeout: {\n      type: Number as PropType<FormComponentProps['validationTimeout']>,\n      default: 1500,\n    },\n    withAllErrors: {\n      type: Boolean as PropType<FormComponentProps['withAllErrors']>,\n      default: null,\n    },\n  },\n  setup(props, { slots, attrs, expose }) {\n    const getTransformedData = (): Record<string, FormDataConvertible> => {\n      const [_url, data] = getUrlAndData()\n\n      return props.transform(data)\n    }\n\n    const form = useForm<Record<string, any>>({})\n      .withPrecognition(\n        () => method.value,\n        () => getUrlAndData()[0],\n      )\n      .transform(getTransformedData)\n      .setValidationTimeout(props.validationTimeout)\n\n    if (props.validateFiles) {\n      form.validateFiles()\n    }\n\n    if (props.withAllErrors ?? config.get('form.withAllErrors')) {\n      form.withAllErrors()\n    }\n\n    const formElement = ref()\n    const method = computed(() =>\n      isUrlMethodPair(props.action) ? props.action.method : (props.method.toLowerCase() as Method),\n    )\n\n    // Can't use computed because FormData is not reactive\n    const isDirty = ref(false)\n\n    const defaultData = ref(new FormData())\n\n    const onFormUpdate = (event: Event) => {\n      if (event.type === 'reset' && (event as CustomEvent).detail?.[FormComponentResetSymbol]) {\n        // When the form is reset programmatically, prevent native reset behavior\n        event.preventDefault()\n      }\n\n      isDirty.value = event.type === 'reset' ? false : !isEqual(getData(), formDataToObject(defaultData.value))\n    }\n\n    const formEvents: Array<keyof HTMLElementEventMap> = ['input', 'change', 'reset']\n\n    onMounted(() => {\n      defaultData.value = getFormData()\n\n      form.defaults(getData())\n\n      formEvents.forEach((e) => formElement.value.addEventListener(e, onFormUpdate))\n    })\n\n    watch(\n      () => props.validateFiles,\n      (value) => (value ? form.validateFiles() : form.withoutFileValidation()),\n    )\n\n    watch(\n      () => props.validationTimeout,\n      (value) => form.setValidationTimeout(value),\n    )\n\n    onBeforeUnmount(() => formEvents.forEach((e) => formElement.value?.removeEventListener(e, onFormUpdate)))\n\n    const getFormData = (submitter?: FormSubmitter): FormData => new FormData(formElement.value, submitter)\n\n    // Convert the FormData to an object because we can't compare two FormData\n    // instances directly (which is needed for isDirty), mergeDataIntoQueryString()\n    // expects an object, and submitting a FormData instance directly causes problems with nested objects.\n    const getData = (submitter?: FormSubmitter): Record<string, FormDataConvertible> =>\n      formDataToObject(getFormData(submitter))\n\n    const getUrlAndData = (submitter?: FormSubmitter): [string, Record<string, FormDataConvertible>] => {\n      return mergeDataIntoQueryString(\n        method.value,\n        isUrlMethodPair(props.action) ? props.action.url : props.action,\n        getData(submitter),\n        props.queryStringArrayFormat,\n      )\n    }\n\n    const submit = (submitter?: FormSubmitter) => {\n      const [url, data] = getUrlAndData(submitter)\n      const formTarget = (submitter as HTMLButtonElement | HTMLInputElement | null)?.getAttribute('formtarget')\n\n      if (formTarget === '_blank' && method.value === 'get') {\n        window.open(url, '_blank')\n        return\n      }\n\n      const maybeReset = (resetOption: boolean | string[]) => {\n        if (!resetOption) {\n          return\n        }\n\n        if (resetOption === true) {\n          reset()\n        } else if (resetOption.length > 0) {\n          reset(...resetOption)\n        }\n      }\n\n      const submitOptions: FormSubmitOptions = {\n        headers: props.headers,\n        queryStringArrayFormat: props.queryStringArrayFormat,\n        errorBag: props.errorBag,\n        showProgress: props.showProgress,\n        invalidateCacheTags: props.invalidateCacheTags,\n        onCancelToken: props.onCancelToken,\n        onBefore: props.onBefore,\n        onStart: props.onStart,\n        onProgress: props.onProgress,\n        onFinish: props.onFinish,\n        onCancel: props.onCancel,\n        onSuccess: (...args) => {\n          props.onSuccess?.(...args)\n          props.onSubmitComplete?.(exposed)\n          maybeReset(props.resetOnSuccess)\n\n          if (props.setDefaultsOnSuccess === true) {\n            defaults()\n          }\n        },\n        onError: (...args) => {\n          props.onError?.(...args)\n          maybeReset(props.resetOnError)\n        },\n        ...props.options,\n      }\n\n      // We need transform because we can't override the default data with different keys (by design)\n      form.transform(() => props.transform(data)).submit(method.value, url, submitOptions)\n\n      // Reset the transformer back so the submitter is not used for future submissions\n      form.transform(getTransformedData)\n    }\n\n    const reset = (...fields: string[]) => {\n      resetFormFields(formElement.value, defaultData.value, fields)\n\n      form.reset(...fields)\n    }\n\n    const clearErrors = (...fields: string[]) => {\n      form.clearErrors(...fields)\n    }\n\n    const resetAndClearErrors = (...fields: string[]) => {\n      clearErrors(...fields)\n      reset(...fields)\n    }\n\n    const defaults = () => {\n      defaultData.value = getFormData()\n      isDirty.value = false\n    }\n\n    const exposed = {\n      get errors() {\n        return form.errors\n      },\n      get hasErrors() {\n        return form.hasErrors\n      },\n      get processing() {\n        return form.processing\n      },\n      get progress() {\n        return form.progress\n      },\n      get wasSuccessful() {\n        return form.wasSuccessful\n      },\n      get recentlySuccessful() {\n        return form.recentlySuccessful\n      },\n      get validating() {\n        return form.validating\n      },\n      clearErrors,\n      resetAndClearErrors,\n      setError: (fieldOrFields: string | Record<string, string>, maybeValue?: string) =>\n        form.setError((typeof fieldOrFields === 'string' ? { [fieldOrFields]: maybeValue } : fieldOrFields) as Errors),\n      get isDirty() {\n        return isDirty.value\n      },\n      reset,\n      submit,\n      defaults,\n      getData,\n      getFormData,\n\n      // Precognition\n      touch: form.touch,\n      valid: form.valid,\n      invalid: form.invalid,\n      touched: form.touched,\n      validate: (field?: string | NamedInputEvent | ValidationConfig, config?: ValidationConfig) =>\n        form.validate(...UseFormUtils.mergeHeadersForValidation(field, config, props.headers)),\n      validator: () => form.validator(),\n    }\n\n    expose<FormComponentRef>(exposed)\n\n    provide(FormContextKey, exposed)\n\n    return () => {\n      return h(\n        'form',\n        {\n          ...attrs,\n          ref: formElement,\n          action: isUrlMethodPair(props.action) ? props.action.url : props.action,\n          method: method.value,\n          onSubmit: (event) => {\n            event.preventDefault()\n            submit(event.submitter)\n          },\n          inert: props.disableWhileProcessing && form.processing,\n        },\n        slots.default ? slots.default(exposed) : [],\n      )\n    }\n  },\n})\n\nexport function useFormContext(): FormComponentRef | undefined {\n  return inject(FormContextKey)\n}\n\nexport default Form\n"
  },
  {
    "path": "packages/vue3/src/head.ts",
    "content": "import { escape } from 'lodash-es'\nimport { defineComponent, DefineComponent, VNode } from 'vue'\n\nexport type InertiaHead = DefineComponent<{\n  title?: string\n}>\n\nconst Head: InertiaHead = defineComponent({\n  props: {\n    title: {\n      type: String,\n      required: false,\n    },\n  },\n  data() {\n    return {\n      provider: this.$headManager.createProvider(),\n    }\n  },\n  beforeUnmount() {\n    this.provider.disconnect()\n  },\n  methods: {\n    isUnaryTag(node: VNode) {\n      return (\n        typeof node.type === 'string' &&\n        [\n          'area',\n          'base',\n          'br',\n          'col',\n          'embed',\n          'hr',\n          'img',\n          'input',\n          'keygen',\n          'link',\n          'meta',\n          'param',\n          'source',\n          'track',\n          'wbr',\n        ].indexOf(node.type) > -1\n      )\n    },\n    renderTagStart(node: VNode) {\n      node.props = node.props || {}\n      node.props[this.provider.preferredAttribute()] =\n        node.props['head-key'] !== undefined ? node.props['head-key'] : ''\n\n      const attrs = Object.keys(node.props).reduce((carry, name) => {\n        const value = String(node.props![name])\n        if (['key', 'head-key'].includes(name)) {\n          return carry\n        } else if (value === '') {\n          return carry + ` ${name}`\n        } else {\n          return carry + ` ${name}=\"${escape(value)}\"`\n        }\n      }, '')\n\n      return `<${String(node.type)}${attrs}>`\n    },\n    renderTagChildren(node: VNode): string {\n      const { children } = node\n\n      if (typeof children === 'string') {\n        return children\n      }\n\n      if (Array.isArray(children)) {\n        return children.reduce<string>((html, child) => {\n          return html + this.renderTag(child as VNode)\n        }, '')\n      }\n\n      return ''\n    },\n    isFunctionNode(node: VNode): node is VNode & { type: () => VNode } {\n      return typeof node.type === 'function'\n    },\n    isComponentNode(node: VNode): node is VNode & { type: object } {\n      return typeof node.type === 'object'\n    },\n    isCommentNode(node: VNode) {\n      return /(comment|cmt)/i.test(node.type.toString())\n    },\n    isFragmentNode(node: VNode) {\n      return /(fragment|fgt|symbol\\(\\))/i.test(node.type.toString())\n    },\n    isTextNode(node: VNode) {\n      return /(text|txt)/i.test(node.type.toString())\n    },\n    renderTag(node: VNode): string {\n      if (this.isTextNode(node)) {\n        return String(node.children)\n      } else if (this.isFragmentNode(node)) {\n        return ''\n      } else if (this.isCommentNode(node)) {\n        return ''\n      }\n\n      let html = this.renderTagStart(node)\n\n      if (node.children) {\n        html += this.renderTagChildren(node)\n      }\n\n      if (!this.isUnaryTag(node)) {\n        html += `</${String(node.type)}>`\n      }\n\n      return html\n    },\n    addTitleElement(elements: string[]) {\n      if (this.title && !elements.find((tag) => tag.startsWith('<title'))) {\n        elements.push(`<title ${this.provider.preferredAttribute()}>${this.title}</title>`)\n      }\n\n      return elements\n    },\n    renderNodes(nodes: VNode[]) {\n      const elements = nodes\n        .flatMap((node) => this.resolveNode(node))\n        .map((node) => this.renderTag(node))\n        .filter((node) => node)\n\n      return this.addTitleElement(elements)\n    },\n    resolveNode(node: VNode): VNode | VNode[] {\n      if (this.isFunctionNode(node)) {\n        return this.resolveNode(node.type())\n      } else if (this.isComponentNode(node)) {\n        console.warn(`Using components in the <Head> component is not supported.`)\n        return []\n      } else if (this.isTextNode(node) && node.children) {\n        return node\n      } else if (this.isFragmentNode(node) && node.children) {\n        return (node.children as VNode[]).flatMap((child) => this.resolveNode(child))\n      } else if (this.isCommentNode(node)) {\n        return []\n      } else {\n        return node\n      }\n    },\n  },\n  render() {\n    this.provider.update(this.renderNodes(this.$slots.default ? this.$slots.default() : []))\n  },\n})\n\nexport default Head\n"
  },
  {
    "path": "packages/vue3/src/index.ts",
    "content": "import { config as coreConfig } from '@inertiajs/core'\nimport { VueInertiaAppConfig } from './types'\n\nexport { progress, router } from '@inertiajs/core'\nexport { default as App, usePage } from './app'\nexport { default as createInertiaApp } from './createInertiaApp'\nexport { default as Deferred } from './deferred'\nexport { default as Form, useFormContext } from './form'\nexport { default as Head } from './head'\nexport { default as InfiniteScroll } from './infiniteScroll'\nexport { InertiaLinkProps, default as Link } from './link'\nexport * from './types'\nexport { InertiaForm, InertiaFormProps, InertiaPrecognitiveForm, default as useForm } from './useForm'\nexport { default as usePoll } from './usePoll'\nexport { default as usePrefetch } from './usePrefetch'\nexport { default as useRemember } from './useRemember'\nexport { default as WhenVisible } from './whenVisible'\n\nexport const config = coreConfig.extend<VueInertiaAppConfig>({})\n"
  },
  {
    "path": "packages/vue3/src/infiniteScroll.ts",
    "content": "import {\n  getScrollableParent,\n  InfiniteScrollActionSlotProps,\n  InfiniteScrollComponentBaseProps,\n  InfiniteScrollRef,\n  InfiniteScrollSlotProps,\n  useInfiniteScroll,\n} from '@inertiajs/core'\nimport { computed, defineComponent, Fragment, h, onMounted, onUnmounted, PropType, ref, SlotsType, watch } from 'vue'\n\n// Vue-specific element resolver\nconst resolveHTMLElement = (\n  value: string | object | (() => HTMLElement | null),\n  fallback: HTMLElement | null,\n): HTMLElement | null => {\n  if (!value) {\n    return fallback\n  }\n\n  // CSS Selector string\n  if (typeof value === 'string') {\n    return document.querySelector(value) as HTMLElement | null\n  }\n\n  // Function that returns an element\n  if (typeof value === 'function') {\n    return value() || null\n  }\n\n  return fallback\n}\n\nconst InfiniteScroll = defineComponent({\n  name: 'InfiniteScroll',\n  slots: Object as SlotsType<{\n    default: InfiniteScrollSlotProps\n    previous: InfiniteScrollActionSlotProps\n    next: InfiniteScrollActionSlotProps\n    loading: InfiniteScrollActionSlotProps\n  }>,\n  props: {\n    data: {\n      type: String as PropType<InfiniteScrollComponentBaseProps['data']>,\n      required: true,\n    },\n    buffer: {\n      type: Number as PropType<InfiniteScrollComponentBaseProps['buffer']>,\n      default: 0,\n    },\n    onlyNext: {\n      type: Boolean,\n      default: false,\n    },\n    onlyPrevious: {\n      type: Boolean,\n      default: false,\n    },\n    as: {\n      type: String as PropType<InfiniteScrollComponentBaseProps['as']>,\n      default: 'div',\n    },\n    manual: {\n      type: Boolean as PropType<InfiniteScrollComponentBaseProps['manual']>,\n      default: false,\n    },\n    manualAfter: {\n      type: Number as PropType<InfiniteScrollComponentBaseProps['manualAfter']>,\n      default: 0,\n    },\n    preserveUrl: {\n      type: Boolean as PropType<InfiniteScrollComponentBaseProps['preserveUrl']>,\n      default: false,\n    },\n    reverse: {\n      type: Boolean as PropType<InfiniteScrollComponentBaseProps['reverse']>,\n      default: false,\n    },\n    autoScroll: {\n      type: Boolean as PropType<InfiniteScrollComponentBaseProps['autoScroll']>,\n      default: undefined,\n    },\n    itemsElement: {\n      type: [String, Function, Object] as PropType<string | (() => HTMLElement | null | undefined)>,\n      default: null,\n    },\n    startElement: {\n      type: [String, Function, Object] as PropType<string | (() => HTMLElement | null | undefined)>,\n      default: null,\n    },\n    endElement: {\n      type: [String, Function, Object] as PropType<string | (() => HTMLElement | null | undefined)>,\n      default: null,\n    },\n  },\n  inheritAttrs: false,\n  setup(props, { slots, attrs, expose }) {\n    const itemsElementRef = ref<HTMLElement | null>(null)\n    const startElementRef = ref<HTMLElement | null>(null)\n    const endElementRef = ref<HTMLElement | null>(null)\n\n    const itemsElement = computed<HTMLElement | null>(() =>\n      resolveHTMLElement(props.itemsElement, itemsElementRef.value),\n    )\n    const scrollableParent = computed(() => getScrollableParent(itemsElement.value))\n    const startElement = computed<HTMLElement | null>(() =>\n      resolveHTMLElement(props.startElement, startElementRef.value),\n    )\n    const endElement = computed<HTMLElement | null>(() => resolveHTMLElement(props.endElement, endElementRef.value))\n\n    const loadingPrevious = ref(false)\n    const loadingNext = ref(false)\n    const requestCount = ref(0)\n    const hasPreviousPage = ref(false)\n    const hasNextPage = ref(false)\n\n    const syncStateFromDataManager = () => {\n      requestCount.value = dataManager.getRequestCount()\n      hasPreviousPage.value = dataManager.hasPrevious()\n      hasNextPage.value = dataManager.hasNext()\n    }\n\n    const {\n      dataManager,\n      elementManager,\n      flush: flushInfiniteScroll,\n    } = useInfiniteScroll({\n      // Data\n      getPropName: () => props.data,\n      inReverseMode: () => props.reverse,\n      shouldFetchNext: () => !props.onlyPrevious,\n      shouldFetchPrevious: () => !props.onlyNext,\n      shouldPreserveUrl: () => props.preserveUrl,\n\n      // Elements\n      getTriggerMargin: () => props.buffer,\n      getStartElement: () => startElement.value!,\n      getEndElement: () => endElement.value!,\n      getItemsElement: () => itemsElement.value!,\n      getScrollableParent: () => scrollableParent.value,\n\n      // Request callbacks\n      onBeforePreviousRequest: () => (loadingPrevious.value = true),\n      onBeforeNextRequest: () => (loadingNext.value = true),\n      onCompletePreviousRequest: () => {\n        loadingPrevious.value = false\n        syncStateFromDataManager()\n      },\n      onCompleteNextRequest: () => {\n        loadingNext.value = false\n        syncStateFromDataManager()\n      },\n      onDataReset: syncStateFromDataManager,\n    })\n\n    syncStateFromDataManager()\n\n    const autoLoad = computed<boolean>(() => !manualMode.value)\n    const manualMode = computed<boolean>(\n      () => props.manual || (props.manualAfter > 0 && requestCount.value >= props.manualAfter),\n    )\n\n    const scrollToBottom = () => {\n      if (scrollableParent.value) {\n        scrollableParent.value.scrollTo({\n          top: scrollableParent.value.scrollHeight,\n          behavior: 'instant',\n        })\n      } else {\n        window.scrollTo({\n          top: document.body.scrollHeight,\n          behavior: 'instant',\n        })\n      }\n    }\n\n    onMounted(() => {\n      elementManager.setupObservers()\n      elementManager.processServerLoadedElements(dataManager.getLastLoadedPage())\n\n      // autoScroll defaults to reverse value if not explicitly set\n      const shouldAutoScroll = props.autoScroll !== undefined ? props.autoScroll : props.reverse\n\n      if (shouldAutoScroll) {\n        scrollToBottom()\n      }\n\n      if (autoLoad.value) {\n        elementManager.enableTriggers()\n      }\n    })\n\n    onUnmounted(flushInfiniteScroll)\n\n    watch(\n      () => [autoLoad.value, props.onlyNext, props.onlyPrevious],\n      ([enabled]) => {\n        enabled ? elementManager.enableTriggers() : elementManager.disableTriggers()\n      },\n    )\n\n    expose<InfiniteScrollRef>({\n      fetchNext: dataManager.fetchNext,\n      fetchPrevious: dataManager.fetchPrevious,\n      hasPrevious: dataManager.hasPrevious,\n      hasNext: dataManager.hasNext,\n    })\n\n    return () => {\n      const renderElements = []\n\n      const sharedExposed: Pick<\n        InfiniteScrollActionSlotProps,\n        'loadingPrevious' | 'loadingNext' | 'hasPrevious' | 'hasNext'\n      > = {\n        loadingPrevious: loadingPrevious.value,\n        loadingNext: loadingNext.value,\n        hasPrevious: hasPreviousPage.value,\n        hasNext: hasNextPage.value,\n      }\n\n      // Only render previous trigger if not using custom element\n      if (!props.startElement) {\n        const headerAutoMode = autoLoad.value && !props.onlyNext\n        const exposedPrevious: InfiniteScrollActionSlotProps = {\n          loading: loadingPrevious.value,\n          fetch: dataManager.fetchPrevious,\n          autoMode: headerAutoMode,\n          manualMode: !headerAutoMode,\n          hasMore: hasPreviousPage.value,\n          ...sharedExposed,\n        }\n\n        renderElements.push(\n          h(\n            'div',\n            { ref: startElementRef },\n            slots.previous\n              ? slots.previous(exposedPrevious)\n              : loadingPrevious.value\n                ? slots.loading?.(exposedPrevious)\n                : undefined,\n          ),\n        )\n      }\n\n      renderElements.push(\n        h(\n          props.as,\n          { ...attrs, ref: itemsElementRef },\n          slots.default?.({\n            loading: loadingPrevious.value || loadingNext.value,\n            loadingPrevious: loadingPrevious.value,\n            loadingNext: loadingNext.value,\n          }),\n        ),\n      )\n\n      // Only render next trigger if not using custom element\n      if (!props.endElement) {\n        const footerAutoMode = autoLoad.value && !props.onlyPrevious\n        const exposedNext: InfiniteScrollActionSlotProps = {\n          loading: loadingNext.value,\n          fetch: dataManager.fetchNext,\n          autoMode: footerAutoMode,\n          manualMode: !footerAutoMode,\n          hasMore: hasNextPage.value,\n          ...sharedExposed,\n        }\n\n        renderElements.push(\n          h(\n            'div',\n            { ref: endElementRef },\n            slots.next ? slots.next(exposedNext) : loadingNext.value ? slots.loading?.(exposedNext) : undefined,\n          ),\n        )\n      }\n\n      return h(Fragment, {}, props.reverse ? [...renderElements].reverse() : renderElements)\n    }\n  },\n})\n\nexport default InfiniteScroll\n"
  },
  {
    "path": "packages/vue3/src/link.ts",
    "content": "import {\n  ActiveVisit,\n  isUrlMethodPair,\n  LinkComponentBaseProps,\n  LinkPrefetchOption,\n  mergeDataIntoQueryString,\n  Method,\n  PendingVisit,\n  router,\n  shouldIntercept,\n  shouldNavigate,\n} from '@inertiajs/core'\nimport { Component, computed, defineComponent, DefineComponent, h, onMounted, onUnmounted, PropType, ref } from 'vue'\nimport { config } from '.'\n\nconst noop = () => {}\n\nexport interface InertiaLinkProps extends LinkComponentBaseProps {\n  as?: string | Component\n  onClick?: (event: MouseEvent) => void\n}\n\ntype InertiaLink = DefineComponent<InertiaLinkProps>\n\nconst Link: InertiaLink = defineComponent({\n  name: 'Link',\n  props: {\n    as: {\n      type: [String, Object] as PropType<InertiaLinkProps['as']>,\n      default: 'a',\n    },\n    data: {\n      type: Object as PropType<InertiaLinkProps['data']>,\n      default: () => ({}),\n    },\n    href: {\n      type: [String, Object] as PropType<InertiaLinkProps['href']>,\n      default: '',\n    },\n    method: {\n      type: String as PropType<InertiaLinkProps['method']>,\n      default: 'get',\n    },\n    replace: {\n      type: Boolean as PropType<InertiaLinkProps['replace']>,\n      default: false,\n    },\n    preserveScroll: {\n      type: [Boolean, String, Function] as PropType<InertiaLinkProps['preserveScroll']>,\n      default: false,\n    },\n    preserveState: {\n      type: [Boolean, String, Function] as PropType<InertiaLinkProps['preserveState']>,\n      default: null,\n    },\n    preserveUrl: {\n      type: Boolean as PropType<InertiaLinkProps['preserveUrl']>,\n      default: false,\n    },\n    only: {\n      type: Array as PropType<InertiaLinkProps['only']>,\n      default: () => [],\n    },\n    except: {\n      type: Array as PropType<InertiaLinkProps['except']>,\n      default: () => [],\n    },\n    headers: {\n      type: Object as PropType<InertiaLinkProps['headers']>,\n      default: () => ({}),\n    },\n    queryStringArrayFormat: {\n      type: String as PropType<InertiaLinkProps['queryStringArrayFormat']>,\n      default: 'brackets',\n    },\n    async: {\n      type: Boolean as PropType<InertiaLinkProps['async']>,\n      default: false,\n    },\n    prefetch: {\n      type: [Boolean, String, Array] as PropType<InertiaLinkProps['prefetch']>,\n      default: false,\n    },\n    cacheFor: {\n      type: [Number, String, Array] as PropType<InertiaLinkProps['cacheFor']>,\n      default: 0,\n    },\n    onStart: {\n      type: Function as PropType<InertiaLinkProps['onStart']>,\n      default: noop,\n    },\n    onProgress: {\n      type: Function as PropType<InertiaLinkProps['onProgress']>,\n      default: noop,\n    },\n    onFinish: {\n      type: Function as PropType<InertiaLinkProps['onFinish']>,\n      default: noop,\n    },\n    onBefore: {\n      type: Function as PropType<InertiaLinkProps['onBefore']>,\n      default: noop,\n    },\n    onCancel: {\n      type: Function as PropType<InertiaLinkProps['onCancel']>,\n      default: noop,\n    },\n    onSuccess: {\n      type: Function as PropType<InertiaLinkProps['onSuccess']>,\n      default: noop,\n    },\n    onError: {\n      type: Function as PropType<InertiaLinkProps['onError']>,\n      default: noop,\n    },\n    onCancelToken: {\n      type: Function as PropType<InertiaLinkProps['onCancelToken']>,\n      default: noop,\n    },\n    onPrefetching: {\n      type: Function as PropType<InertiaLinkProps['onPrefetching']>,\n      default: noop,\n    },\n    onPrefetched: {\n      type: Function as PropType<InertiaLinkProps['onPrefetched']>,\n      default: noop,\n    },\n    cacheTags: {\n      type: [String, Array] as PropType<InertiaLinkProps['cacheTags']>,\n      default: () => [],\n    },\n    viewTransition: {\n      type: [Boolean, Object] as PropType<InertiaLinkProps['viewTransition']>,\n      default: false,\n    },\n  },\n  setup(props, { slots, attrs }) {\n    const inFlightCount = ref(0)\n    const hoverTimeout = ref<ReturnType<typeof setTimeout>>()\n\n    const prefetchModes = computed<LinkPrefetchOption[]>(() => {\n      if (props.prefetch === true) {\n        return ['hover']\n      }\n\n      if (props.prefetch === false) {\n        return []\n      }\n\n      if (Array.isArray(props.prefetch)) {\n        return props.prefetch\n      }\n\n      return [props.prefetch] as LinkPrefetchOption[]\n    })\n\n    const cacheForValue = computed(() => {\n      if (props.cacheFor !== 0) {\n        // If they've provided a value, respect it\n        return props.cacheFor\n      }\n\n      if (prefetchModes.value.length === 1 && prefetchModes.value[0] === 'click') {\n        // If they've only provided a prefetch mode of 'click',\n        // we should only prefetch for the next request but not keep it around\n        return 0\n      }\n\n      // Otherwise, default to 30 seconds\n      return config.get('prefetch.cacheFor')\n    })\n\n    onMounted(() => {\n      if (prefetchModes.value.includes('mount')) {\n        prefetch()\n      }\n    })\n\n    onUnmounted(() => {\n      clearTimeout(hoverTimeout.value)\n    })\n\n    const method = computed(() =>\n      isUrlMethodPair(props.href) ? props.href.method : ((props.method ?? 'get').toLowerCase() as Method),\n    )\n    const as = computed(() => {\n      if (typeof props.as !== 'string' || props.as.toLowerCase() !== 'a') {\n        // Custom component or element\n        return props.as\n      }\n\n      return method.value !== 'get' ? 'button' : props.as.toLowerCase()\n    })\n    const mergeDataArray = computed(() =>\n      mergeDataIntoQueryString(\n        method.value,\n        isUrlMethodPair(props.href) ? props.href.url : (props.href as string),\n        props.data || {},\n        props.queryStringArrayFormat,\n      ),\n    )\n    const href = computed(() => mergeDataArray.value[0])\n    const data = computed(() => mergeDataArray.value[1])\n\n    const elProps = computed(() => {\n      if (as.value === 'button') {\n        return { type: 'button' }\n      }\n\n      if (as.value === 'a' || typeof as.value !== 'string') {\n        return { href: href.value }\n      }\n\n      return {}\n    })\n\n    const baseParams = computed(() => ({\n      data: data.value,\n      method: method.value,\n      replace: props.replace,\n      preserveScroll: props.preserveScroll,\n      preserveState: props.preserveState ?? method.value !== 'get',\n      preserveUrl: props.preserveUrl,\n      only: props.only,\n      except: props.except,\n      headers: props.headers,\n      async: props.async,\n    }))\n\n    const visitParams = computed(() => ({\n      ...baseParams.value,\n      viewTransition: props.viewTransition,\n      onCancelToken: props.onCancelToken,\n      onBefore: props.onBefore,\n      onStart: (visit: PendingVisit) => {\n        inFlightCount.value++\n        props.onStart?.(visit)\n      },\n      onProgress: props.onProgress,\n      onFinish: (visit: ActiveVisit) => {\n        inFlightCount.value--\n        props.onFinish?.(visit)\n      },\n      onCancel: props.onCancel,\n      onSuccess: props.onSuccess,\n      onError: props.onError,\n    }))\n\n    const prefetch = () => {\n      router.prefetch(\n        href.value,\n        {\n          ...baseParams.value,\n          onPrefetching: props.onPrefetching,\n          onPrefetched: props.onPrefetched,\n        },\n        {\n          cacheFor: cacheForValue.value,\n          cacheTags: props.cacheTags,\n        },\n      )\n    }\n\n    const regularEvents = {\n      onClick: (event: MouseEvent) => {\n        if (shouldIntercept(event)) {\n          event.preventDefault()\n          router.visit(href.value, visitParams.value)\n        }\n      },\n    }\n\n    const prefetchHoverEvents = {\n      onMouseenter: () => {\n        hoverTimeout.value = setTimeout(() => {\n          prefetch()\n        }, config.get('prefetch.hoverDelay'))\n      },\n      onMouseleave: () => {\n        clearTimeout(hoverTimeout.value)\n      },\n      onClick: regularEvents.onClick,\n    }\n\n    const prefetchClickEvents = {\n      onMousedown: (event: MouseEvent) => {\n        if (shouldIntercept(event)) {\n          event.preventDefault()\n          prefetch()\n        }\n      },\n      onKeydown: (event: KeyboardEvent) => {\n        if (shouldNavigate(event)) {\n          event.preventDefault()\n          prefetch()\n        }\n      },\n      onMouseup: (event: MouseEvent) => {\n        if (shouldIntercept(event)) {\n          event.preventDefault()\n          router.visit(href.value, visitParams.value)\n        }\n      },\n      onKeyup: (event: KeyboardEvent) => {\n        if (shouldNavigate(event)) {\n          event.preventDefault()\n          router.visit(href.value, visitParams.value)\n        }\n      },\n      onClick: (event: MouseEvent) => {\n        if (shouldIntercept(event)) {\n          // Let the mouseup/keyup event handle the visit\n          event.preventDefault()\n        }\n      },\n    }\n\n    return () => {\n      return h(\n        as.value as string | Component,\n        {\n          ...attrs,\n          ...elProps.value,\n          'data-loading': inFlightCount.value > 0 ? '' : undefined,\n          ...(() => {\n            if (prefetchModes.value.includes('hover')) {\n              return prefetchHoverEvents\n            }\n\n            if (prefetchModes.value.includes('click')) {\n              return prefetchClickEvents\n            }\n\n            return regularEvents\n          })(),\n        },\n        slots,\n      )\n    }\n  },\n})\n\nexport default Link\n"
  },
  {
    "path": "packages/vue3/src/remember.ts",
    "content": "import { router } from '@inertiajs/core'\nimport { cloneDeep } from 'lodash-es'\nimport { ComponentOptions } from 'vue'\n\nconst remember: ComponentOptions = {\n  created() {\n    if (!this.$options.remember) {\n      return\n    }\n\n    if (Array.isArray(this.$options.remember)) {\n      this.$options.remember = { data: this.$options.remember }\n    }\n\n    if (typeof this.$options.remember === 'string') {\n      this.$options.remember = { data: [this.$options.remember] }\n    }\n\n    if (typeof this.$options.remember.data === 'string') {\n      this.$options.remember = { data: [this.$options.remember.data] }\n    }\n\n    const rememberKey =\n      this.$options.remember.key instanceof Function\n        ? this.$options.remember.key.call(this)\n        : this.$options.remember.key\n\n    const restored = router.restore(rememberKey) as Record<string, unknown> | undefined\n\n    const rememberable = this.$options.remember.data.filter((key: string) => {\n      return !(this[key] !== null && typeof this[key] === 'object' && this[key].__rememberable === false)\n    }) as string[]\n\n    const hasCallbacks = (key: string) => {\n      return (\n        this[key] !== null &&\n        typeof this[key] === 'object' &&\n        typeof this[key].__remember === 'function' &&\n        typeof this[key].__restore === 'function'\n      )\n    }\n\n    rememberable.forEach((key: string) => {\n      if (this[key] !== undefined && restored !== undefined && restored[key] !== undefined) {\n        hasCallbacks(key) ? this[key].__restore(restored[key]) : (this[key] = restored[key])\n      }\n\n      this.$watch(\n        key,\n        () => {\n          router.remember(\n            rememberable.reduce(\n              (data, key) => ({\n                ...data,\n                [key]: cloneDeep(hasCallbacks(key) ? this[key].__remember() : this[key]),\n              }),\n              {},\n            ),\n            rememberKey,\n          )\n        },\n        { immediate: true, deep: true },\n      )\n    })\n  },\n}\n\nexport default remember\n"
  },
  {
    "path": "packages/vue3/src/server.ts",
    "content": "export { default as default } from '@inertiajs/core/server'\n"
  },
  {
    "path": "packages/vue3/src/types.ts",
    "content": "import { createHeadManager, Page, PageHandler, PageProps, router, SharedPageProps } from '@inertiajs/core'\nimport { DefineComponent } from 'vue'\nimport useForm from './useForm'\n\nexport type VuePageHandlerArgs = Parameters<PageHandler<DefineComponent>>[0]\nexport type VueInertiaAppConfig = {}\n\ndeclare module '@inertiajs/core' {\n  export interface Router {\n    form: typeof useForm\n  }\n}\n\ndeclare module 'vue' {\n  export interface ComponentCustomProperties {\n    $inertia: typeof router\n    $page: Page<PageProps & SharedPageProps>\n    $headManager: ReturnType<typeof createHeadManager>\n  }\n\n  export interface ComponentCustomOptions {\n    remember?:\n      | string\n      | string[]\n      | {\n          data: string | string[]\n          key?: string | (() => string)\n        }\n  }\n}\n"
  },
  {
    "path": "packages/vue3/src/useForm.ts",
    "content": "import {\n  CancelToken,\n  Errors,\n  ErrorValue,\n  FormDataErrors,\n  FormDataKeys,\n  FormDataType,\n  FormDataValues,\n  Method,\n  Progress,\n  RequestPayload,\n  router,\n  UrlMethodPair,\n  UseFormArguments,\n  UseFormSubmitArguments,\n  UseFormSubmitOptions,\n  UseFormTransformCallback,\n  UseFormUtils,\n  UseFormWithPrecognitionArguments,\n  VisitOptions,\n} from '@inertiajs/core'\nimport {\n  createValidator,\n  NamedInputEvent,\n  PrecognitionPath,\n  resolveName,\n  toSimpleValidationErrors,\n  ValidationConfig,\n  Validator,\n} from 'laravel-precognition'\nimport { cloneDeep, get, has, isEqual, set } from 'lodash-es'\nimport { reactive, watch } from 'vue'\nimport { config } from '.'\n\n// Reserved keys validation - logs console.error at runtime when form data keys conflict with form properties\nlet reservedFormKeys: Set<string> | null = null\nlet bootstrapping = false\n\nfunction validateFormDataKeys<TForm extends object>(data: TForm): void {\n  if (bootstrapping) {\n    return\n  }\n\n  if (reservedFormKeys === null) {\n    bootstrapping = true\n    reservedFormKeys = new Set(Object.keys(useForm({})))\n    bootstrapping = false\n  }\n\n  const conflicts = Object.keys(data).filter((key) => reservedFormKeys!.has(key))\n  if (conflicts.length > 0) {\n    console.error(\n      `[Inertia] useForm() data contains field(s) that conflict with form properties: ${conflicts.map((k) => `\"${k}\"`).join(', ')}. ` +\n        `These fields will be overwritten by form methods/properties. Please rename these fields.`,\n    )\n  }\n}\n\nexport interface InertiaFormProps<TForm extends object> {\n  isDirty: boolean\n  errors: FormDataErrors<TForm>\n  hasErrors: boolean\n  processing: boolean\n  progress: Progress | null\n  wasSuccessful: boolean\n  recentlySuccessful: boolean\n  data(): TForm\n  transform(callback: UseFormTransformCallback<TForm>): this\n  defaults(): this\n  defaults<T extends FormDataKeys<TForm>>(field: T, value: FormDataValues<TForm, T>): this\n  defaults(fields: Partial<TForm>): this\n  reset<K extends FormDataKeys<TForm>>(...fields: K[]): this\n  clearErrors<K extends FormDataKeys<TForm>>(...fields: K[]): this\n  resetAndClearErrors<K extends FormDataKeys<TForm>>(...fields: K[]): this\n  setError<K extends FormDataKeys<TForm>>(field: K, value: ErrorValue): this\n  setError(errors: FormDataErrors<TForm>): this\n  submit: (...args: UseFormSubmitArguments) => void\n  get(url: string, options?: UseFormSubmitOptions): void\n  post(url: string, options?: UseFormSubmitOptions): void\n  put(url: string, options?: UseFormSubmitOptions): void\n  patch(url: string, options?: UseFormSubmitOptions): void\n  delete(url: string, options?: UseFormSubmitOptions): void\n  cancel(): void\n  dontRemember<K extends FormDataKeys<TForm>>(...fields: K[]): this\n  withPrecognition(...args: UseFormWithPrecognitionArguments): InertiaPrecognitiveForm<TForm>\n}\n\ntype PrecognitionValidationConfig<TKeys> = ValidationConfig & {\n  only?: TKeys[] | Iterable<TKeys> | ArrayLike<TKeys>\n}\n\nexport interface InertiaFormValidationProps<TForm extends object> {\n  invalid<K extends FormDataKeys<TForm>>(field: K): boolean\n  setValidationTimeout(duration: number): this\n  touch<K extends FormDataKeys<TForm>>(field: K | NamedInputEvent | Array<K>, ...fields: K[]): this\n  touched<K extends FormDataKeys<TForm>>(field?: K): boolean\n  valid<K extends FormDataKeys<TForm>>(field: K): boolean\n  validate<K extends FormDataKeys<TForm> | PrecognitionPath<TForm>>(\n    field?: K | NamedInputEvent | PrecognitionValidationConfig<K>,\n    config?: PrecognitionValidationConfig<K>,\n  ): this\n  validateFiles(): this\n  validating: boolean\n  validator: () => Validator\n  withAllErrors(): this\n  withoutFileValidation(): this\n  // Backward compatibility for easy migration from the original Precognition libraries\n  setErrors(errors: FormDataErrors<TForm> | Record<string, string | string[]>): this\n  forgetError<K extends FormDataKeys<TForm> | NamedInputEvent>(field: K): this\n}\n\ninterface InternalPrecognitionState {\n  __touched: string[]\n  __valid: string[]\n}\n\ninterface InternalRememberState<TForm extends object> {\n  __rememberable: boolean\n  __remember: () => { data: TForm; errors: FormDataErrors<TForm> }\n  __restore: (restored: { data: TForm; errors: FormDataErrors<TForm> }) => void\n}\n\nexport type InertiaForm<TForm extends object> = TForm & InertiaFormProps<TForm>\nexport type InertiaPrecognitiveForm<TForm extends object> = InertiaForm<TForm> &\n  InertiaFormValidationProps<TForm> &\n  InternalPrecognitionState\n\ntype ReservedFormKeys = keyof InertiaFormProps<any>\n\ntype ValidateFormData<T> = {\n  [K in keyof T]: K extends ReservedFormKeys ? ['Error: This field name is reserved by useForm:', K] : T[K]\n}\n\nexport default function useForm<TForm extends FormDataType<TForm> & ValidateFormData<TForm>>(\n  method: Method | (() => Method),\n  url: string | (() => string),\n  data: TForm | (() => TForm),\n): InertiaPrecognitiveForm<TForm>\nexport default function useForm<TForm extends FormDataType<TForm> & ValidateFormData<TForm>>(\n  urlMethodPair: UrlMethodPair | (() => UrlMethodPair),\n  data: TForm | (() => TForm),\n): InertiaPrecognitiveForm<TForm>\nexport default function useForm<TForm extends FormDataType<TForm> & ValidateFormData<TForm>>(\n  rememberKey: string,\n  data: TForm | (() => TForm),\n): InertiaForm<TForm>\nexport default function useForm<TForm extends FormDataType<TForm> & ValidateFormData<TForm>>(\n  data: TForm | (() => TForm),\n): InertiaForm<TForm>\nexport default function useForm<TForm extends FormDataType<TForm>>(): InertiaForm<TForm>\nexport default function useForm<TForm extends FormDataType<TForm>>(\n  ...args: UseFormArguments<TForm>\n): InertiaForm<TForm> | InertiaPrecognitiveForm<TForm> {\n  let { rememberKey, data, precognitionEndpoint } = UseFormUtils.parseUseFormArguments<TForm>(...args)\n\n  const restored = rememberKey\n    ? (router.restore(rememberKey) as { data: TForm; errors: Record<FormDataKeys<TForm>, ErrorValue> })\n    : null\n  let defaults = typeof data === 'function' ? cloneDeep(data()) : cloneDeep(data)\n  validateFormDataKeys(defaults)\n  let cancelToken: CancelToken | null = null\n  let recentlySuccessfulTimeoutId: ReturnType<typeof setTimeout>\n  let transform: UseFormTransformCallback<TForm> = (data) => data\n\n  let validatorRef: Validator | null = null\n  let rememberExcludeKeys: FormDataKeys<TForm>[] = []\n\n  // Track if defaults was called manually during onSuccess to avoid\n  // overriding user's custom defaults with automatic behavior.\n  let defaultsCalledInOnSuccess = false\n\n  const form = reactive<InertiaForm<TForm>>({\n    ...(restored ? restored.data : cloneDeep(defaults)),\n    isDirty: false,\n    errors: (restored ? restored.errors : {}) as FormDataErrors<TForm>,\n    hasErrors: false,\n    processing: false,\n    progress: null as Progress | null,\n    wasSuccessful: false,\n    recentlySuccessful: false,\n    withPrecognition(...args: UseFormWithPrecognitionArguments): InertiaPrecognitiveForm<TForm> {\n      precognitionEndpoint = UseFormUtils.createWayfinderCallback(...args)\n\n      // Type assertion helper for accessing precognition state\n      // We're dynamically adding precognition properties to 'this', so we assert the type\n      const formWithPrecognition = this as any as InertiaPrecognitiveForm<TForm>\n\n      let withAllErrors: boolean | null = null\n      const validator = createValidator((client) => {\n        const { method, url } = precognitionEndpoint!()\n        const transformedData = cloneDeep(transform(this.data())) as Record<string, unknown>\n\n        return client[method](url, transformedData)\n      }, cloneDeep(defaults))\n\n      validatorRef = validator\n\n      validator\n        .on('validatingChanged', () => {\n          formWithPrecognition.validating = validator.validating()\n        })\n        .on('validatedChanged', () => {\n          formWithPrecognition.__valid = validator.valid()\n        })\n        .on('touchedChanged', () => {\n          formWithPrecognition.__touched = validator.touched()\n        })\n        .on('errorsChanged', () => {\n          const validationErrors =\n            (withAllErrors ?? config.get('form.withAllErrors'))\n              ? validator.errors()\n              : toSimpleValidationErrors(validator.errors())\n\n          this.errors = {} as FormDataErrors<TForm>\n\n          this.setError(validationErrors as FormDataErrors<TForm>)\n\n          formWithPrecognition.__valid = validator.valid()\n        })\n\n      const tap = <T>(value: T, callback: (value: T) => unknown): T => {\n        callback(value)\n        return value\n      }\n\n      Object.assign(formWithPrecognition, {\n        __touched: [],\n        __valid: [],\n        validating: false,\n        validator: () => validator,\n        withAllErrors: () => tap(formWithPrecognition, () => (withAllErrors = true)),\n        valid: (field: string) => formWithPrecognition.__valid.includes(field),\n        invalid: (field: string) => field in this.errors,\n        setValidationTimeout: (duration: number) => tap(formWithPrecognition, () => validator.setTimeout(duration)),\n        validateFiles: () => tap(formWithPrecognition, () => validator.validateFiles()),\n        withoutFileValidation: () => tap(formWithPrecognition, () => validator.withoutFileValidation()),\n        touch: (\n          field: FormDataKeys<TForm> | NamedInputEvent | Array<FormDataKeys<TForm>>,\n          ...fields: FormDataKeys<TForm>[]\n        ) => {\n          if (Array.isArray(field)) {\n            validator.touch(field)\n          } else if (typeof field === 'string') {\n            validator.touch([field, ...fields])\n          } else {\n            validator.touch(field)\n          }\n\n          return formWithPrecognition\n        },\n        touched: (field?: string): boolean =>\n          typeof field === 'string'\n            ? formWithPrecognition.__touched.includes(field)\n            : formWithPrecognition.__touched.length > 0,\n        validate: (field?: string | NamedInputEvent | ValidationConfig, config?: ValidationConfig) => {\n          // Handle config object passed as first argument\n          if (typeof field === 'object' && !('target' in field)) {\n            config = field\n            field = undefined\n          }\n\n          if (field === undefined) {\n            validator.validate(config)\n          } else {\n            const fieldName = resolveName(field)\n            const transformedData = transform(this.data()) as Record<string, unknown>\n            validator.validate(fieldName, get(transformedData, fieldName), config)\n          }\n\n          return formWithPrecognition\n        },\n        setErrors: (errors: FormDataErrors<TForm>) => tap(formWithPrecognition, () => this.setError(errors)),\n        forgetError: (field: FormDataKeys<TForm> | NamedInputEvent) =>\n          tap(formWithPrecognition, () =>\n            this.clearErrors(resolveName(field as string | NamedInputEvent) as FormDataKeys<TForm>),\n          ),\n      })\n\n      return formWithPrecognition\n    },\n    data() {\n      return (Object.keys(defaults) as Array<FormDataKeys<TForm>>).reduce((carry, key) => {\n        return set(carry, key, get(this, key))\n      }, {} as Partial<TForm>) as TForm\n    },\n    transform(callback: UseFormTransformCallback<TForm>) {\n      transform = callback\n\n      return this\n    },\n    defaults(fieldOrFields?: FormDataKeys<TForm> | Partial<TForm>, maybeValue?: unknown) {\n      if (typeof data === 'function') {\n        throw new Error('You cannot call `defaults()` when using a function to define your form data.')\n      }\n\n      defaultsCalledInOnSuccess = true\n\n      if (typeof fieldOrFields === 'undefined') {\n        defaults = cloneDeep(this.data())\n        this.isDirty = false\n      } else {\n        defaults =\n          typeof fieldOrFields === 'string'\n            ? set(cloneDeep(defaults), fieldOrFields, maybeValue)\n            : Object.assign({}, cloneDeep(defaults), fieldOrFields)\n      }\n\n      validatorRef?.defaults(defaults)\n\n      return this\n    },\n    reset(...fields: FormDataKeys<TForm>[]) {\n      const resolvedData = typeof data === 'function' ? cloneDeep(data()) : cloneDeep(defaults)\n      const clonedData = cloneDeep(resolvedData)\n      if (fields.length === 0) {\n        defaults = clonedData\n        Object.assign(this, resolvedData)\n      } else {\n        ;(fields as Array<FormDataKeys<TForm>>)\n          .filter((key) => has(clonedData, key))\n          .forEach((key) => {\n            set(defaults, key, get(clonedData, key))\n            set(this, key, get(resolvedData, key))\n          })\n      }\n\n      validatorRef?.reset(...fields)\n\n      return this\n    },\n    setError(fieldOrFields: FormDataKeys<TForm> | FormDataErrors<TForm>, maybeValue?: ErrorValue) {\n      const errors = typeof fieldOrFields === 'string' ? { [fieldOrFields]: maybeValue } : fieldOrFields\n\n      Object.assign(this.errors, errors)\n\n      this.hasErrors = Object.keys(this.errors).length > 0\n\n      validatorRef?.setErrors(errors as Errors)\n\n      return this\n    },\n    clearErrors(...fields: string[]) {\n      this.errors = Object.keys(this.errors).reduce(\n        (carry, field) => ({\n          ...carry,\n          ...(fields.length > 0 && !fields.includes(field) ? { [field]: (this.errors as Errors)[field] } : {}),\n        }),\n        {} as FormDataErrors<TForm>,\n      )\n\n      this.hasErrors = Object.keys(this.errors).length > 0\n\n      if (validatorRef) {\n        if (fields.length === 0) {\n          validatorRef.setErrors({})\n        } else {\n          fields.forEach(validatorRef.forgetError)\n        }\n      }\n\n      return this\n    },\n    resetAndClearErrors(...fields: FormDataKeys<TForm>[]) {\n      this.reset(...fields)\n      this.clearErrors(...fields)\n      return this\n    },\n    submit(...args: UseFormSubmitArguments) {\n      const { method, url, options } = UseFormUtils.parseSubmitArguments(args, precognitionEndpoint)\n\n      defaultsCalledInOnSuccess = false\n\n      const _options: VisitOptions = {\n        ...options,\n        onCancelToken: (token) => {\n          cancelToken = token\n\n          if (options.onCancelToken) {\n            return options.onCancelToken(token)\n          }\n        },\n        onBefore: (visit) => {\n          this.wasSuccessful = false\n          this.recentlySuccessful = false\n          clearTimeout(recentlySuccessfulTimeoutId)\n\n          if (options.onBefore) {\n            return options.onBefore(visit)\n          }\n        },\n        onStart: (visit) => {\n          this.processing = true\n\n          if (options.onStart) {\n            return options.onStart(visit)\n          }\n        },\n        onProgress: (event) => {\n          this.progress = event ?? null\n\n          if (options.onProgress) {\n            return options.onProgress(event)\n          }\n        },\n        onSuccess: async (page) => {\n          this.processing = false\n          this.progress = null\n          this.clearErrors()\n          this.wasSuccessful = true\n          this.recentlySuccessful = true\n          recentlySuccessfulTimeoutId = setTimeout(\n            () => (this.recentlySuccessful = false),\n            config.get('form.recentlySuccessfulDuration'),\n          )\n\n          const onSuccess = options.onSuccess ? await options.onSuccess(page) : null\n\n          if (!defaultsCalledInOnSuccess) {\n            defaults = cloneDeep(this.data())\n            this.isDirty = false\n          }\n\n          return onSuccess\n        },\n        onError: (errors) => {\n          this.processing = false\n          this.progress = null\n          this.clearErrors().setError(errors as FormDataErrors<TForm>)\n\n          if (options.onError) {\n            return options.onError(errors)\n          }\n        },\n        onCancel: () => {\n          this.processing = false\n          this.progress = null\n\n          if (options.onCancel) {\n            return options.onCancel()\n          }\n        },\n        onFinish: (visit) => {\n          this.processing = false\n          this.progress = null\n          cancelToken = null\n\n          if (options.onFinish) {\n            return options.onFinish(visit)\n          }\n        },\n      }\n\n      const transformedData = transform(this.data()) as RequestPayload\n\n      if (method === 'delete') {\n        router.delete(url, { ..._options, data: transformedData })\n      } else {\n        router[method](url, transformedData, _options)\n      }\n    },\n    get(url: string, options: VisitOptions) {\n      this.submit('get', url, options)\n    },\n    post(url: string, options: VisitOptions) {\n      this.submit('post', url, options)\n    },\n    put(url: string, options: VisitOptions) {\n      this.submit('put', url, options)\n    },\n    patch(url: string, options: VisitOptions) {\n      this.submit('patch', url, options)\n    },\n    delete(url: string, options: VisitOptions) {\n      this.submit('delete', url, options)\n    },\n    cancel() {\n      if (cancelToken) {\n        cancelToken.cancel()\n      }\n    },\n    dontRemember(...keys: FormDataKeys<TForm>[]) {\n      rememberExcludeKeys = keys\n      return this\n    },\n    __rememberable: rememberKey === null,\n    __remember() {\n      const data = this.data()\n      if (rememberExcludeKeys.length > 0) {\n        const filtered = { ...data } as Record<string, unknown>\n        rememberExcludeKeys.forEach((k) => delete filtered[k as string])\n        return { data: filtered as TForm, errors: this.errors }\n      }\n      return { data, errors: this.errors }\n    },\n    __restore(restored: { data: TForm; errors: FormDataErrors<TForm> }) {\n      Object.assign(this, restored.data)\n      this.setError(restored.errors)\n    },\n  })\n\n  const typedForm = form as any as InertiaForm<TForm>\n\n  watch(\n    typedForm as typeof typedForm & InternalRememberState<TForm>,\n    (newValue) => {\n      typedForm.isDirty = !isEqual(typedForm.data(), defaults)\n\n      const storedData = router.restore(rememberKey!)\n      const newData = cloneDeep(newValue.__remember())\n\n      if (rememberKey && !isEqual(storedData, newData)) {\n        router.remember(newData, rememberKey)\n      }\n    },\n    { immediate: true, deep: true },\n  )\n\n  return precognitionEndpoint ? typedForm.withPrecognition(precognitionEndpoint) : typedForm\n}\n"
  },
  {
    "path": "packages/vue3/src/usePoll.ts",
    "content": "import { PollOptions, ReloadOptions, router } from '@inertiajs/core'\nimport { onMounted, onUnmounted } from 'vue'\n\nexport default function usePoll(\n  interval: number,\n  requestOptions: ReloadOptions = {},\n  options: PollOptions = {\n    keepAlive: false,\n    autoStart: true,\n  },\n): {\n  stop: VoidFunction\n  start: VoidFunction\n} {\n  const { stop, start } = router.poll(interval, requestOptions, {\n    ...options,\n    autoStart: false,\n  })\n\n  onMounted(() => {\n    if (options.autoStart ?? true) {\n      start()\n    }\n  })\n\n  onUnmounted(() => {\n    stop()\n  })\n\n  return {\n    stop,\n    start,\n  }\n}\n"
  },
  {
    "path": "packages/vue3/src/usePrefetch.ts",
    "content": "import { router, VisitOptions } from '@inertiajs/core'\nimport { onMounted, onUnmounted, ref, Ref } from 'vue'\n\nexport default function usePrefetch(options: VisitOptions = {}): {\n  lastUpdatedAt: Ref<number | null>\n  isPrefetching: Ref<boolean>\n  isPrefetched: Ref<boolean>\n  flush: () => void\n} {\n  const isPrefetching = ref(false)\n  const lastUpdatedAt = ref<number | null>(null)\n  const isPrefetched = ref(false)\n\n  const cached = typeof window === 'undefined' ? null : router.getCached(window.location.pathname, options)\n  const inFlight = typeof window === 'undefined' ? null : router.getPrefetching(window.location.pathname, options)\n\n  lastUpdatedAt.value = cached?.staleTimestamp || null\n\n  isPrefetching.value = inFlight !== null\n  isPrefetched.value = cached !== null\n\n  let onPrefetchedListener: () => void\n  let onPrefetchingListener: () => void\n\n  onMounted(() => {\n    onPrefetchingListener = router.on('prefetching', (e) => {\n      if (e.detail.visit.url.pathname === window.location.pathname) {\n        isPrefetching.value = true\n      }\n    })\n\n    onPrefetchedListener = router.on('prefetched', (e) => {\n      if (e.detail.visit.url.pathname === window.location.pathname) {\n        isPrefetching.value = false\n        isPrefetched.value = true\n      }\n    })\n  })\n\n  onUnmounted(() => {\n    onPrefetchedListener()\n    onPrefetchingListener()\n  })\n\n  return {\n    lastUpdatedAt,\n    isPrefetching,\n    isPrefetched,\n    flush: () => router.flush(window.location.pathname, options),\n  }\n}\n"
  },
  {
    "path": "packages/vue3/src/useRemember.ts",
    "content": "import { router } from '@inertiajs/core'\nimport { cloneDeep } from 'lodash-es'\nimport { isReactive, reactive, ref, Ref, watch } from 'vue'\n\nexport default function useRemember<T extends object>(\n  data: T & { __rememberable?: boolean; __remember?: Function; __restore?: Function },\n  key?: string,\n): Ref<T> | T {\n  if (typeof data === 'object' && data !== null && data.__rememberable === false) {\n    return data\n  }\n\n  const restored = router.restore(key)\n  const type = isReactive(data) ? reactive : ref\n  const hasCallbacks = typeof data.__remember === 'function' && typeof data.__restore === 'function'\n  const remembered = type(\n    restored === undefined ? data : hasCallbacks ? data.__restore!(cloneDeep(restored)) : cloneDeep(restored),\n  )\n\n  watch(\n    remembered,\n    (newValue) => {\n      router.remember(cloneDeep(hasCallbacks ? data.__remember!() : newValue), key)\n    },\n    { immediate: true, deep: true },\n  )\n\n  return remembered\n}\n"
  },
  {
    "path": "packages/vue3/src/whenVisible.ts",
    "content": "import { ReloadOptions, router } from '@inertiajs/core'\nimport { defineComponent, h, PropType, SlotsType } from 'vue'\nimport { usePage } from './app'\n\nexport default defineComponent({\n  name: 'WhenVisible',\n  slots: Object as SlotsType<{\n    default: { fetching: boolean }\n    fallback: {}\n  }>,\n  props: {\n    data: {\n      type: [String, Array<String>],\n    },\n    params: {\n      type: Object as PropType<ReloadOptions>,\n    },\n    buffer: {\n      type: Number,\n      default: 0,\n    },\n    as: {\n      type: String,\n      default: 'div',\n    },\n    always: {\n      type: Boolean,\n      default: false,\n    },\n  },\n  data() {\n    return {\n      loaded: false,\n      fetching: false,\n      observer: null as IntersectionObserver | null,\n    }\n  },\n  unmounted() {\n    this.observer?.disconnect()\n  },\n  computed: {\n    keys(): string[] {\n      return this.data ? ((Array.isArray(this.data) ? this.data : [this.data]) as string[]) : []\n    },\n  },\n  created() {\n    const page = usePage()\n\n    this.$watch(\n      () => this.keys.map((key) => page.props[key]),\n      () => {\n        const exists = this.keys.length > 0 && this.keys.every((key) => page.props[key] !== undefined)\n        this.loaded = exists\n\n        if (exists && !this.always) {\n          return\n        }\n\n        if (!this.observer || !exists) {\n          this.$nextTick(this.registerObserver)\n        }\n      },\n      { immediate: true },\n    )\n  },\n  methods: {\n    registerObserver() {\n      this.observer?.disconnect()\n\n      this.observer = new IntersectionObserver(\n        (entries) => {\n          if (!entries[0].isIntersecting) {\n            return\n          }\n\n          if (this.fetching) {\n            return\n          }\n\n          if (!this.always && this.loaded) {\n            return\n          }\n\n          this.fetching = true\n\n          const reloadParams = this.getReloadParams()\n\n          router.reload({\n            ...reloadParams,\n            onStart: (e) => {\n              this.fetching = true\n              reloadParams.onStart?.(e)\n            },\n            onFinish: (e) => {\n              this.loaded = true\n              this.fetching = false\n              reloadParams.onFinish?.(e)\n\n              if (!this.always) {\n                this.observer?.disconnect()\n              }\n            },\n          })\n        },\n        {\n          rootMargin: `${this.$props.buffer}px`,\n        },\n      )\n\n      this.observer.observe(this.$el.nextSibling)\n    },\n    getReloadParams(): Partial<ReloadOptions> {\n      const reloadParams: Partial<ReloadOptions> = { ...this.$props.params }\n\n      if (this.$props.data) {\n        reloadParams.only = (Array.isArray(this.$props.data) ? this.$props.data : [this.$props.data]) as string[]\n      }\n\n      return reloadParams\n    },\n  },\n  render() {\n    const els = []\n\n    if (this.$props.always || !this.loaded) {\n      els.push(h(this.$props.as))\n    }\n\n    if (!this.loaded) {\n      els.push(this.$slots.fallback ? this.$slots.fallback({}) : null)\n    } else if (this.$slots.default) {\n      els.push(this.$slots.default({ fetching: this.fetching }))\n    }\n\n    return els\n  },\n})\n"
  },
  {
    "path": "packages/vue3/test-app/.gitignore",
    "content": "cypress/videos\ncypress/screenshots\napp/dist\nnode_modules\n"
  },
  {
    "path": "packages/vue3/test-app/Layouts/NestedLayout.vue",
    "content": "<script setup lang=\"ts\">\nimport { usePage } from '@inertiajs/vue3'\nimport { getCurrentInstance, onMounted, ref } from 'vue'\n\nconst createdAt = ref<number | null>(null)\n\nonMounted(() => {\n  window._inertia_nested_layout_id = getCurrentInstance()?.uid\n  window._inertia_nested_layout_props = usePage().props\n  createdAt.value = Date.now()\n})\n</script>\n\n<template>\n  <div>\n    <span>Nested Layout</span>\n    <span>{{ createdAt }}</span>\n    <div>\n      <slot />\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Layouts/Prefetch.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <Link href=\"/prefetch/1\" prefetch>On Hover (Default)</Link>\n    <Link href=\"/prefetch/2\" prefetch=\"mount\">On Mount</Link>\n    <Link href=\"/prefetch/3\" prefetch=\"click\">On Click</Link>\n    <Link href=\"/prefetch/4\" :prefetch=\"['hover', 'mount']\" cacheFor=\"1s\">On Hover + Mount</Link>\n    <Link href=\"/prefetch/5\" prefetch=\"mount\" cacheFor=\"0\">On Mount (Once)</Link>\n    <Link href=\"/prefetch/6\" prefetch=\"click\">On Enter</Link>\n    <Link href=\"/prefetch/7\" prefetch=\"click\" as=\"button\">On Spacebar</Link>\n    <div>\n      <slot />\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Layouts/SWR.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <Link href=\"/prefetch/swr/2\" prefetch cache-for=\"1s\">1s Expired</Link>\n    <Link href=\"/prefetch/swr/3\" prefetch :cache-for=\"1000\">1s Expired (Number)</Link>\n    <Link href=\"/prefetch/swr/4\" style=\"margin: 0 20px\" prefetch :cache-for=\"['1s', '3s']\">1s Stale, 2s Expired</Link>\n    <Link href=\"/prefetch/swr/5\" prefetch :cache-for=\"[1000, 3000]\"> 1s Stale, 2s Expired (Number) </Link>\n    <div>\n      <slot />\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Layouts/SiteLayout.vue",
    "content": "<script setup lang=\"ts\">\nimport { usePage } from '@inertiajs/vue3'\nimport { getCurrentInstance, onMounted, ref } from 'vue'\n\nconst createdAt = ref<number | null>(null)\n\nonMounted(() => {\n  window._inertia_layout_id = getCurrentInstance()?.uid\n  window._inertia_site_layout_props = usePage().props\n  createdAt.value = Date.now()\n})\n</script>\n\n<template>\n  <div>\n    <span>Site Layout</span>\n    <span>{{ createdAt }}</span>\n    <div>\n      <slot />\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Layouts/WithScrollRegion.vue",
    "content": "<script setup lang=\"ts\">\nimport { onMounted, onUnmounted, ref } from 'vue'\n\nconst documentScrollTop = ref(0)\nconst documentScrollLeft = ref(0)\nconst slotScrollTop = ref(0)\nconst slotScrollLeft = ref(0)\n\nconst handleScrollEvent = () => {\n  documentScrollTop.value = document.documentElement.scrollTop\n  documentScrollLeft.value = document.documentElement.scrollLeft\n  slotScrollTop.value = document.getElementById('slot')?.scrollTop || 0\n  slotScrollLeft.value = document.getElementById('slot')?.scrollLeft || 0\n}\n\nonMounted(() => {\n  document.addEventListener('scroll', handleScrollEvent)\n})\n\nonUnmounted(() => {\n  document.removeEventListener('scroll', handleScrollEvent)\n})\n</script>\n\n<template>\n  <div style=\"width: 200vw\">\n    <span class=\"layout-text\">With scroll regions</span>\n    <button @click=\"handleScrollEvent\">Update scroll positions</button>\n    <div class=\"document-position\">Document scroll position is {{ documentScrollLeft }} & {{ documentScrollTop }}</div>\n    <div style=\"height: 200vh\">\n      <span class=\"slot-position\">Slot scroll position is {{ slotScrollLeft }} & {{ slotScrollTop }}</span>\n      <div scroll-region id=\"slot\" style=\"height: 100px; width: 500px; overflow: scroll\" @scroll=\"handleScrollEvent\">\n        <slot />\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Layouts/WithoutScrollRegion.vue",
    "content": "<script setup lang=\"ts\">\nimport { onMounted, onUnmounted, ref } from 'vue'\n\nconst documentScrollTop = ref(0)\nconst documentScrollLeft = ref(0)\nconst slotScrollTop = ref(0)\nconst slotScrollLeft = ref(0)\n\nconst handleScrollEvent = () => {\n  documentScrollTop.value = document.documentElement.scrollTop\n  documentScrollLeft.value = document.documentElement.scrollLeft\n  slotScrollTop.value = document.getElementById('slot')?.scrollTop || 0\n  slotScrollLeft.value = document.getElementById('slot')?.scrollLeft || 0\n}\n\nonMounted(() => {\n  document.addEventListener('scroll', handleScrollEvent)\n})\n\nonUnmounted(() => {\n  document.removeEventListener('scroll', handleScrollEvent)\n})\n</script>\n\n<template>\n  <div style=\"width: 200vw\">\n    <span class=\"layout-text\">Without scroll regions</span>\n    <button @click=\"handleScrollEvent\">Update scroll positions</button>\n    <div class=\"document-position\">Document scroll position is {{ documentScrollLeft }} & {{ documentScrollTop }}</div>\n    <div style=\"height: 200vh\">\n      <span class=\"slot-position\">Slot scroll position is {{ slotScrollLeft }} & {{ slotScrollTop }}</span>\n      <div id=\"slot\" style=\"height: 100px; width: 500px; overflow: scroll\" @scroll=\"handleScrollEvent\">\n        <slot />\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Article.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\nimport { onMounted, onUnmounted, ref } from 'vue'\n\nconst enableSmoothScroll = () => {\n  document.documentElement.style.scrollBehavior = 'smooth'\n}\n\nconst scrollLog = ref<number[]>([])\n\nconst handleScrollEvent = () => {\n  scrollLog.value.push(document.documentElement.scrollTop)\n}\n\nonMounted(() => document.addEventListener('scroll', handleScrollEvent))\nonUnmounted(() => document.removeEventListener('scroll', handleScrollEvent))\n</script>\n\n<template>\n  <h1 :style=\"{ fontSize: '40px' }\">Article Header</h1>\n\n  <article :style=\"{ fontSize: '20px', maxWidth: '500px' }\">\n    <p>\n      Sunt culpa sit sunt enim aliquip. Esse ea ea quis voluptate. Enim consectetur aliqua ex ex magna cupidatat id\n      minim sit elit. Amet pariatur occaecat pariatur duis eiusmod dolore magna. Et commodo cupidatat in commodo elit\n      cupidatat minim qui id non enim ad. Culpa aliquip ad Lorem sit consectetur ullamco culpa duis nisi et fugiat\n      mollit eiusmod. Laboris voluptate veniam consequat proident in nulla irure velit.\n    </p>\n\n    <p>\n      Sit sint laboris sunt eiusmod ipsum laborum eiusmod amet commodo exercitation in duis magna. Proident sunt minim\n      in elit qui. Id pariatur commodo fugiat excepteur in deserunt Lorem ipsum occaecat est. Excepteur sit tempor ipsum\n      ex officia veniam enim amet velit fugiat mollit cillum. Incididunt aliqua nulla id occaecat nulla. Non ea ad est\n      occaecat deserunt officia qui commodo exercitation.\n    </p>\n\n    <p>\n      Voluptate laborum quis aliqua ullamco magna amet ullamco laborum qui cillum eu. Dolore dolore aliqua proident\n      proident sunt ipsum in. Enim velit dolore labore dolor quis incididunt duis culpa Lorem. Eu adipisicing non elit\n      fugiat voluptate labore ipsum dolore consectetur commodo. Et in et cillum duis consequat quis ex eu commodo.\n      Eiusmod aliqua excepteur consectetur eiusmod aute et consectetur sit pariatur dolore qui officia pariatur.\n    </p>\n\n    <p>\n      Non sunt eu mollit qui reprehenderit. Aute culpa anim voluptate do in esse duis laborum ad dolore. Ullamco nisi in\n      nostrud officia do. Duis pariatur officia id duis. Deserunt ad incididunt est sint consectetur reprehenderit\n      mollit est Lorem ea pariatur anim dolor adipisicing. Nostrud irure magna nostrud laboris aute sunt veniam laboris\n      veniam incididunt sit. Nulla proident ad aliqua fugiat culpa sunt est in dolor velit ad irure nulla.\n    </p>\n\n    <p>\n      Do aute laborum deserunt non laborum voluptate voluptate. Anim ut laborum magna sunt cupidatat irure. Cupidatat\n      fugiat minim sint cillum laborum excepteur irure id est irure ad occaecat adipisicing enim. Deserunt nulla anim\n      proident velit irure nostrud est est reprehenderit consequat pariatur qui. Fugiat Lorem sint eu laborum minim\n      pariatur cillum mollit nulla consequat ullamco ex. Ex consectetur ad ut irure fugiat occaecat aliqua exercitation\n      cillum ipsum anim dolore tempor.\n    </p>\n\n    <p>\n      Adipisicing consequat irure fugiat Lorem deserunt aliquip do cupidatat. Lorem labore elit ex qui nostrud qui\n      cillum sunt adipisicing occaecat. Sunt nostrud amet amet cupidatat fugiat Lorem quis nulla id cillum esse eu.\n      Ullamco aliqua dolore irure amet mollit anim velit dolore.\n    </p>\n\n    <p>\n      Veniam cupidatat ipsum ea officia ipsum nisi laborum culpa qui dolore. Aliqua Lorem nisi labore ea velit aliquip\n      irure excepteur eu. Laboris proident duis non labore sunt quis aute tempor laboris enim anim eiusmod.\n    </p>\n\n    <p>\n      Minim proident ut aliqua ea ut culpa fugiat ullamco nisi esse nostrud reprehenderit id. Id id ullamco velit anim\n      nisi magna Lorem tempor. Et veniam occaecat ut labore consequat fugiat duis.\n    </p>\n\n    <p>\n      Adipisicing ea consectetur adipisicing aute eu pariatur enim labore consequat occaecat consectetur minim nisi.\n      Cillum commodo sunt labore reprehenderit. Duis esse excepteur magna tempor eiusmod exercitation Lorem\n      reprehenderit excepteur pariatur. Esse cupidatat occaecat magna do aliquip Lorem. Consectetur adipisicing\n      consequat dolore nostrud esse eu cillum id commodo duis. Aliquip dolor cillum cupidatat fugiat.\n    </p>\n\n    <p>\n      Ex eiusmod id est laborum sunt ex ea aute adipisicing ad magna deserunt duis. Nostrud velit dolore id commodo quis\n      enim fugiat. Sint non quis consectetur voluptate aliqua dolore nulla. Irure sit reprehenderit sint laboris non\n      elit. Duis minim nisi esse dolor. Sit ex in consequat non occaecat commodo irure et. Commodo qui ipsum Lorem magna\n      consequat consequat et minim eiusmod Lorem eiusmod cupidatat voluptate.\n    </p>\n\n    <h2 id=\"far-down\">Far down</h2>\n\n    <p>\n      Ex eiusmod id est laborum sunt ex ea aute adipisicing ad magna deserunt duis. Nostrud velit dolore id commodo quis\n      enim fugiat. Sint non quis consectetur voluptate aliqua dolore nulla. Irure sit reprehenderit sint laboris non\n      elit. Duis minim nisi esse dolor. Sit ex in consequat non occaecat commodo irure et. Commodo qui ipsum Lorem magna\n      consequat consequat et minim eiusmod Lorem eiusmod cupidatat voluptate.\n    </p>\n  </article>\n\n  <div class=\"document-position\">Scroll log: {{ JSON.stringify(scrollLog) }}</div>\n\n  <Link id=\"home\" data-testid=\"home\" href=\"/\"> Home </Link>\n\n  <Link id=\"article-far-down\" data-testid=\"article-far-down\" href=\"/article#far-down\"> Article Far Down </Link>\n\n  <button id=\"enable-smooth-scroll\" data-testid=\"enable-smooth-scroll\" @click=\"enableSmoothScroll\">\n    Enable Smooth Scroll\n  </button>\n\n  <button id=\"clear-scroll-log\" data-testid=\"clear-scroll-log\" @click=\"scrollLog = []\">Clear Scroll Log</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/ClientSideVisit/Page1.vue",
    "content": "<script setup lang=\"ts\">\nimport { Page } from '@inertiajs/core'\nimport { router } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\ninterface PageProps {\n  foo: string\n  bar: string\n}\n\ndefineProps<PageProps>()\n\nconst errors = ref(0)\nconst finished = ref(0)\nconst success = ref(0)\nconst random = ref(Math.random())\n\nconst bagErrors = () => {\n  router.replace({\n    preserveState: true,\n    props: (props: Page['props']) => ({ ...props, errors: { bag: { foo: 'bar' } } }),\n    errorBag: 'bag',\n    onError: (err) => {\n      errors.value = Object.keys(err).length\n    },\n    onFinish: () => finished.value++,\n    onSuccess: () => success.value++,\n  })\n}\n\nconst defaultErrors = () => {\n  router.replace({\n    preserveState: true,\n    props: (props: PageProps) => ({ ...props, errors: { foo: 'bar', baz: 'qux' } }),\n    onError: (err) => {\n      errors.value = Object.keys(err).length\n    },\n    onFinish: () => finished.value++,\n    onSuccess: () => success.value++,\n  })\n}\n\nconst replace = () => {\n  router.replace({\n    preserveState: true,\n    props: (props) => ({ ...props, foo: 'foo from client' }),\n    onFinish: (visit) => {\n      if (visit.preserveState) {\n        finished.value++\n      }\n    },\n    onSuccess: (page) => {\n      if (page.props.foo === 'foo from client') {\n        success.value++\n      }\n    },\n  })\n}\n\nconst replaceAndPreserveStateWithErrors = (errors = {}) => {\n  router.replace({\n    preserveState: 'errors',\n    props: (props: PageProps) => ({ ...props, errors }),\n  })\n}\n\nconst push = () => {\n  router.push({\n    url: '/client-side-visit-2',\n    component: 'ClientSideVisit/Page2',\n    props: {\n      baz: 'baz from client',\n    },\n  })\n}\n</script>\n\n<template>\n  <div>{{ foo }}</div>\n  <div>{{ bar }}</div>\n  <button @click=\"replace\">Replace</button>\n  <button @click=\"() => replaceAndPreserveStateWithErrors({ name: 'Field is required' })\">Replace with errors</button>\n  <button @click=\"() => replaceAndPreserveStateWithErrors()\">Replace without errors</button>\n  <button @click=\"push\">Push</button>\n  <button @click=\"defaultErrors\">Errors (default)</button>\n  <button @click=\"bagErrors\">Errors (bag)</button>\n  <div>Errors: {{ errors }}</div>\n  <div>Finished: {{ finished }}</div>\n  <div>Success: {{ success }}</div>\n  <div id=\"random\">Random: {{ random }}</div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/ClientSideVisit/Page2.vue",
    "content": "<script setup lang=\"ts\">\ndefineProps<{\n  baz: string\n}>()\n</script>\n\n<template>\n  <div>{{ baz }}</div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/ClientSideVisit/Props.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\ninterface Tag {\n  id: number\n  name: string\n}\n\ninterface User {\n  name: string\n  age: number\n}\n\ndefineProps<{\n  items?: string[]\n  tags?: Tag[]\n  user?: User\n  count?: number\n  singleValue?: string | string[]\n  undefinedValue?: string | string[]\n}>()\n\nconst replacePropString = () => {\n  router.replaceProp('user.name', 'Jane Smith')\n}\n\nconst replacePropNumber = () => {\n  router.replaceProp('count', 10)\n}\n\nconst replacePropFunction = () => {\n  router.replaceProp('count', (oldValue: number) => oldValue * 2)\n}\n\nconst appendToPropArray = () => {\n  router.appendToProp('items', 'item3')\n}\n\nconst appendToPropMultiple = () => {\n  router.appendToProp('items', ['item4', 'item5'])\n}\n\nconst appendToPropFunction = () => {\n  router.appendToProp('tags', () => ({ id: 3, name: 'tag3' }))\n}\n\nconst appendArrayToArray = () => {\n  router.appendToProp('tags', [\n    { id: 3, name: 'tag3' },\n    { id: 4, name: 'tag4' },\n  ])\n}\n\nconst prependToPropArray = () => {\n  router.prependToProp('items', 'item0')\n}\n\nconst prependToPropMultiple = () => {\n  router.prependToProp('items', ['itemA', 'itemB'])\n}\n\nconst prependToPropFunction = () => {\n  router.prependToProp('tags', () => ({ id: 0, name: 'tag0' }))\n}\n\n// Edge case tests for mergeArrays behavior\nconst appendToNonArray = () => {\n  router.appendToProp('singleValue', 'world')\n}\n\nconst prependToNonArray = () => {\n  router.prependToProp('singleValue', 'hey')\n}\n\nconst appendArrayToNonArray = () => {\n  router.appendToProp('singleValue', ['there', 'world'])\n}\n\nconst prependArrayToNonArray = () => {\n  router.prependToProp('singleValue', ['hey', 'hi'])\n}\n\nconst appendToUndefined = () => {\n  router.appendToProp('undefinedValue', 'new value')\n}\n\nconst prependToUndefined = () => {\n  router.prependToProp('undefinedValue', 'start value')\n}\n</script>\n\n<template>\n  <div>\n    <h1>Client Side Visit Props Testing</h1>\n\n    <div>User: {{ user?.name || 'Unknown' }} (Age: {{ user?.age || 'Unknown' }})</div>\n    <div>Count: {{ count }}</div>\n\n    <div>Items: {{ JSON.stringify(items) }}</div>\n    <div>Tags: {{ JSON.stringify(tags) }}</div>\n    <div>Single Value: {{ JSON.stringify(singleValue) }}</div>\n    <div>Undefined Value: {{ JSON.stringify(undefinedValue) }}</div>\n\n    <hr />\n\n    <h2>Replace Prop Tests</h2>\n    <button @click=\"replacePropString\">Replace user.name</button>\n    <button @click=\"replacePropNumber\">Replace count</button>\n    <button @click=\"replacePropFunction\">Replace count (function)</button>\n\n    <h2>Append To Prop Tests</h2>\n    <button @click=\"appendToPropArray\">Append to items (single)</button>\n    <button @click=\"appendToPropMultiple\">Append to items (multiple)</button>\n    <button @click=\"appendToPropFunction\">Append to tags (function)</button>\n    <button @click=\"appendArrayToArray\">Append array to array (objects)</button>\n\n    <h2>Prepend To Prop Tests</h2>\n    <button @click=\"prependToPropArray\">Prepend to items (single)</button>\n    <button @click=\"prependToPropMultiple\">Prepend to items (multiple)</button>\n    <button @click=\"prependToPropFunction\">Prepend to tags (function)</button>\n\n    <h2>Edge Case Tests (mergeArrays behavior)</h2>\n    <button @click=\"appendToNonArray\">Append to non-array (single + single)</button>\n    <button @click=\"prependToNonArray\">Prepend to non-array (single + single)</button>\n    <button @click=\"appendArrayToNonArray\">Append array to non-array (single + array)</button>\n    <button @click=\"prependArrayToNonArray\">Prepend array to non-array (array + single)</button>\n    <button @click=\"appendToUndefined\">Append to undefined</button>\n    <button @click=\"prependToUndefined\">Prepend to undefined</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/ClientSideVisit/Sequential.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\ndefineProps<{\n  foo?: string\n  bar?: string\n}>()\n\nconst replaceSequentially = () => {\n  router.replaceProp('foo', 'baz')\n  router.replaceProp('bar', 'qux')\n}\n</script>\n\n<template>\n  <div>\n    <p>Foo: {{ foo }}</p>\n    <p>Bar: {{ bar }}</p>\n\n    <button @click=\"replaceSequentially\">Replace foo and bar sequentially</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/ComplexMergeSelective.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\ndefineProps<{\n  mixed: {\n    name: string\n    users: string[]\n    chat: { data: number[] }\n    post: { id: number; comments: { allowed: boolean; data: string[] } }\n  }\n}>()\n\nconst reload = () => {\n  router.reload({\n    only: ['mixed'],\n  })\n}\n</script>\n\n<template>\n  <div>\n    <div>name is {{ mixed.name }}</div>\n    <div>users: {{ mixed.users.join(', ') }}</div>\n    <div>chat.data: {{ mixed.chat.data.join(', ') }}</div>\n    <div>post.id: {{ mixed.post.id }}</div>\n    <div>post.comments.allowed: {{ mixed.post.comments.allowed ? 'true' : 'false' }}</div>\n    <div>post.comments.data: {{ mixed.post.comments.data.join(', ') }}</div>\n    <button @click=\"reload\">Reload</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/CustomConfig.vue",
    "content": "<script setup lang=\"ts\">\nimport { VisitOptions } from '@inertiajs/core'\nimport { config, Link, useForm, usePage } from '@inertiajs/vue3'\n\nconst page = usePage()\nconst form = useForm({})\n\nconst submit = () => {\n  form.post(page.url)\n}\n\nconfig.set({\n  'form.recentlySuccessfulDuration': 1000,\n  'prefetch.cacheFor': '2s',\n})\n\nconfig.set('visitOptions', (href: string, options: VisitOptions) => {\n  if (href !== '/dump/post') {\n    return {}\n  }\n\n  return { headers: { ...options.headers, 'X-From-Callback': 'bar' } }\n})\n</script>\n\n<template>\n  <Link prefetch href=\"/dump/get\">Prefetch Link</Link>\n  <Link method=\"post\" :headers=\"{ 'X-From-Link': 'foo' }\" href=\"/dump/post\">Post Dump</Link>\n  <button @click=\"submit\">Submit Form</button>\n  <p v-if=\"form.recentlySuccessful\">Form was recently successful!</p>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/DeepMergeProps.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Page } from '@inertiajs/core'\nimport { router } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\ninterface ComponentProps {\n  foo: {\n    data: { id: number; name: string }[]\n    page: number\n    per_page: number\n    meta: { label: string }\n  }\n  bar: number[]\n  baz: number[]\n}\n\nconst props = defineProps<ComponentProps>()\n\nconst page = ref(props.foo.page)\n\nconst reloadIt = () => {\n  router.reload({\n    data: {\n      page: page.value,\n    },\n    only: ['foo', 'baz'],\n    onSuccess(visit: Page) {\n      // TODO: Refactor 'unknown' and make Page<ComponentProps> work\n      const visitProps = visit.props as unknown as Pick<ComponentProps, 'foo' | 'baz'>\n      page.value = visitProps.foo.page\n    },\n  })\n}\n\nconst getFresh = () => {\n  page.value = 0\n  router.visit('/deep-merge-props', {\n    reset: ['foo', 'baz'],\n  })\n}\n</script>\n\n<template>\n  <div>bar count is {{ bar.length }}</div>\n  <div>baz count is {{ baz.length }}</div>\n  <div>foo.data count is {{ foo.data.length }}</div>\n  <div>foo.page is {{ foo.page }}</div>\n  <div>foo.per_page is {{ foo.per_page }}</div>\n  <div>foo.meta.label is {{ foo.meta.label }}</div>\n  <button @click=\"reloadIt\">Reload</button>\n  <button @click=\"getFresh\">Get Fresh</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/DeferredProps/BackButton/PageA.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, Link } from '@inertiajs/vue3'\n\ndefineProps<{\n  fastProp?: string\n  slowProp?: string\n}>()\n</script>\n\n<template>\n  <Deferred data=\"fastProp\">\n    <template #fallback>\n      <div>Loading fast prop...</div>\n    </template>\n    {{ fastProp }}\n  </Deferred>\n\n  <Deferred data=\"slowProp\">\n    <template #fallback>\n      <div>Loading slow prop...</div>\n    </template>\n    {{ slowProp }}\n  </Deferred>\n\n  <Link href=\"/deferred-props/back-button/b\">Go to Page B</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/DeferredProps/BackButton/PageB.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, Link } from '@inertiajs/vue3'\n\ndefineProps<{\n  data?: string\n}>()\n</script>\n\n<template>\n  <Deferred data=\"data\">\n    <template #fallback>\n      <div>Loading data...</div>\n    </template>\n    {{ data }}\n  </Deferred>\n\n  <Link href=\"/deferred-props/back-button/a\">Go to Page A</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/DeferredProps/InstantReload.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, router } from '@inertiajs/vue3'\nimport { onMounted } from 'vue'\n\ndefineProps<{\n  foo?: { text: string }\n  bar?: { text: string }\n}>()\n\nonMounted(() => {\n  router.reload({\n    only: ['foo'],\n  })\n})\n</script>\n\n<template>\n  <Deferred data=\"foo\">\n    <template #fallback>\n      <div>Loading foo...</div>\n    </template>\n    <div>{{ foo?.text }}</div>\n  </Deferred>\n\n  <Deferred data=\"bar\">\n    <template #fallback>\n      <div>Loading bar...</div>\n    </template>\n    <div>{{ bar?.text }}</div>\n  </Deferred>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/DeferredProps/ManyGroups.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, Link } from '@inertiajs/vue3'\n\ndefineProps<{\n  foo?: { text: string }\n  bar?: { text: string }\n  baz?: { text: string }\n  qux?: { text: string }\n  quux?: { text: string }\n}>()\n</script>\n\n<template>\n  <Deferred data=\"foo\">\n    <template #fallback>\n      <div>Loading foo...</div>\n    </template>\n    <div>{{ foo?.text }}</div>\n  </Deferred>\n\n  <Deferred data=\"bar\">\n    <template #fallback>\n      <div>Loading bar...</div>\n    </template>\n    <div>{{ bar?.text }}</div>\n  </Deferred>\n\n  <Deferred data=\"baz\">\n    <template #fallback>\n      <div>Loading baz...</div>\n    </template>\n    <div>{{ baz?.text }}</div>\n  </Deferred>\n\n  <Deferred data=\"qux\">\n    <template #fallback>\n      <div>Loading qux...</div>\n    </template>\n    <div>{{ qux?.text }}</div>\n  </Deferred>\n\n  <Deferred data=\"quux\">\n    <template #fallback>\n      <div>Loading quux...</div>\n    </template>\n    <div>{{ quux?.text }}</div>\n  </Deferred>\n\n  <Link href=\"/deferred-props/page-1\">Page 1</Link>\n  <Link href=\"/deferred-props/page-2\">Page 2</Link>\n  <Link href=\"/deferred-props/many-groups\">Many groups</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/DeferredProps/Page1.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, Link } from '@inertiajs/vue3'\n\ndefineProps<{\n  foo?: { text: string }\n  bar?: { text: string }\n}>()\n</script>\n\n<template>\n  <Deferred data=\"foo\">\n    <template #fallback>\n      <div>Loading foo...</div>\n    </template>\n    {{ foo?.text }}\n  </Deferred>\n\n  <Deferred data=\"bar\">\n    <template #fallback>\n      <div>Loading bar...</div>\n    </template>\n    {{ bar?.text }}\n  </Deferred>\n\n  <Link href=\"/deferred-props/page-1\">Page 1</Link>\n  <Link href=\"/deferred-props/page-2\">Page 2</Link>\n  <Link href=\"/deferred-props/page-3\" prefetch>Page 3</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/DeferredProps/Page2.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred } from '@inertiajs/vue3'\n\ndefineProps<{\n  baz?: string\n  qux?: string\n}>()\n</script>\n\n<template>\n  <Deferred data=\"baz\">\n    <template #fallback>\n      <div>Loading baz...</div>\n    </template>\n    {{ baz }}\n  </Deferred>\n\n  <Deferred data=\"qux\">\n    <template #fallback>\n      <div>Loading qux...</div>\n    </template>\n    {{ qux }}\n  </Deferred>\n\n  <Deferred :data=\"['baz', 'qux']\">\n    <template #fallback>\n      <div>Loading baz and qux...</div>\n    </template>\n    both {{ baz }} and {{ qux }}\n  </Deferred>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/DeferredProps/Page3.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred } from '@inertiajs/vue3'\n\ndefineProps<{\n  alpha?: string\n  beta?: string\n}>()\n</script>\n\n<template>\n  <Deferred data=\"alpha\">\n    <template #fallback>\n      <div>Loading alpha...</div>\n    </template>\n    {{ alpha }}\n  </Deferred>\n\n  <Deferred data=\"beta\">\n    <template #fallback>\n      <div>Loading beta...</div>\n    </template>\n    {{ beta }}\n  </Deferred>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/DeferredProps/PartialReloads.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, router } from '@inertiajs/vue3'\n\ndefineProps<{\n  foo?: { timestamp: string }\n  bar?: { timestamp: string }\n}>()\n\nconst reloadOnlyFoo = () => {\n  router.reload({\n    only: ['foo'],\n  })\n}\n\nconst reloadOnlyBar = () => {\n  router.reload({\n    only: ['bar'],\n  })\n}\n\nconst reloadBoth = () => {\n  router.reload({\n    only: ['foo', 'bar'],\n  })\n}\n</script>\n\n<template>\n  <Deferred data=\"foo\">\n    <template #fallback>\n      <div>Loading foo...</div>\n    </template>\n    <div id=\"foo-timestamp\">{{ foo?.timestamp }}</div>\n  </Deferred>\n\n  <Deferred data=\"bar\">\n    <template #fallback>\n      <div>Loading bar...</div>\n    </template>\n    <div id=\"bar-timestamp\">{{ bar?.timestamp }}</div>\n  </Deferred>\n\n  <button @click=\"reloadOnlyFoo\">Reload foo only</button>\n  <button @click=\"reloadOnlyBar\">Reload bar only</button>\n  <button @click=\"reloadBoth\">Reload both</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/DeferredProps/RapidNavigation.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, Link, router } from '@inertiajs/vue3'\n\ndefineProps<{\n  id: string\n  users?: { text: string }\n  stats?: { text: string }\n  activity?: { text: string }\n}>()\n\nconst handleOnBeforeClick = () => {\n  const shouldNavigate = confirm('Navigate away?')\n  if (shouldNavigate) {\n    router.visit('/deferred-props/page-2')\n  }\n}\n</script>\n\n<template>\n  <div>Page: {{ id }}</div>\n\n  <Deferred data=\"users\">\n    <div>{{ users?.text }}</div>\n    <template #fallback>\n      <div>Loading users...</div>\n    </template>\n  </Deferred>\n\n  <Deferred data=\"stats\">\n    <div>{{ stats?.text }}</div>\n    <template #fallback>\n      <div>Loading stats...</div>\n    </template>\n  </Deferred>\n\n  <Deferred data=\"activity\">\n    <div>{{ activity?.text }}</div>\n    <template #fallback>\n      <div>Loading activity...</div>\n    </template>\n  </Deferred>\n\n  <Link href=\"/deferred-props/rapid-navigation/a\">Page A</Link>\n  <Link href=\"/deferred-props/rapid-navigation/b\">Page B</Link>\n  <Link href=\"/deferred-props/rapid-navigation/c\">Page C</Link>\n  <Link href=\"/deferred-props/page-1\">Navigate Away</Link>\n\n  <button @click=\"handleOnBeforeClick\">Navigate with onBefore</button>\n\n  <button @click=\"router.reload()\">Plain reload</button>\n\n  <button @click=\"router.visit(`/deferred-props/rapid-navigation/${id}?foo=bar`)\">Add query param</button>\n\n  <button @click=\"router.prefetch('/deferred-props/page-1')\">Prefetch Page 1</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/DeferredProps/ReloadWithoutOptionalChaining.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, router } from '@inertiajs/vue3'\n\ndefineProps<{\n  results: { data: string[]; page: number }\n}>()\n\nconst handleReload = () => {\n  router.reload({\n    data: { page: 2 },\n  })\n}\n</script>\n\n<template>\n  <Deferred data=\"results\">\n    <template #fallback>\n      <div>Loading results...</div>\n    </template>\n    <div id=\"results-data\">{{ results.data.join(', ') }}</div>\n    <div id=\"results-page\">Page: {{ results.page }}</div>\n  </Deferred>\n\n  <button @click=\"handleReload\">Reload with page 2</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/DeferredProps/WithErrors.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, useForm } from '@inertiajs/vue3'\n\ndefineProps<{\n  foo?: { text: string }\n}>()\n\nconst form = useForm({\n  name: '',\n})\n\nconst submit = () => {\n  form.post('/deferred-props/with-errors')\n}\n</script>\n\n<template>\n  <Deferred data=\"foo\">\n    <template #fallback>\n      <div>Loading foo...</div>\n    </template>\n\n    <div id=\"foo\">{{ foo?.text }}</div>\n  </Deferred>\n\n  <p v-if=\"$page.props.errors?.name\" id=\"page-error\">{{ $page.props.errors.name }}</p>\n  <p v-if=\"form.errors.name\" id=\"form-error\">{{ form.errors.name }}</p>\n\n  <button type=\"button\" @click=\"submit\">Submit</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/DeferredProps/WithQueryParams.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred } from '@inertiajs/vue3'\n\ndefineProps<{\n  filter: string\n  users?: { text: string }\n}>()\n</script>\n\n<template>\n  <div>Filter: {{ filter }}</div>\n\n  <Deferred data=\"users\">\n    <template #fallback>\n      <div>Loading users...</div>\n    </template>\n    <div>{{ users?.text }}</div>\n  </Deferred>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/DeferredProps/WithReload.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, router } from '@inertiajs/vue3'\n\ndefineProps<{\n  results?: { data: string[]; page: number }\n}>()\n\nconst handleReload = () => {\n  router.reload({\n    data: { page: 2 },\n  })\n}\n</script>\n\n<template>\n  <Deferred data=\"results\">\n    <template #fallback>\n      <div>Loading results...</div>\n    </template>\n    <div id=\"results-data\">{{ results?.data?.join(', ') }}</div>\n    <div id=\"results-page\">Page: {{ results?.page }}</div>\n  </Deferred>\n\n  <button @click=\"handleReload\">Reload with page 2</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Dump.vue",
    "content": "<script setup lang=\"ts\">\nimport { Method } from '@inertiajs/core'\nimport { usePage } from '@inertiajs/vue3'\nimport { onBeforeMount } from 'vue'\nimport type { MulterFile } from '../types'\n\nconst props = defineProps<{\n  headers: Record<string, string>\n  method: Method\n  form: Record<string, unknown> | undefined\n  files: MulterFile[] | object\n  query: Record<string, unknown>\n  url: string\n}>()\n\nconst page = usePage()\n\nconst dump = {\n  headers: props.headers,\n  method: props.method,\n  form: props.form,\n  files: props.files ? props.files : {},\n  query: props.query,\n  url: props.url,\n  $page: page,\n}\n\nonBeforeMount(() => {\n  window._inertia_request_dump = dump\n})\n</script>\n\n<template>\n  <div>\n    <div class=\"text\">This is Inertia page component containing a data dump of the request</div>\n    <hr />\n    <pre class=\"dump\">{{ dump }}</pre>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/ErrorModal.vue",
    "content": "<script setup lang=\"ts\">\nconst props = defineProps<{\n  dialog: boolean\n}>()\n\nimport { config, router } from '@inertiajs/vue3'\n\nconst invalidVisit = () => {\n  router.post('/non-inertia')\n}\n\nconst invalidVisitJson = () => {\n  router.post('/json')\n}\n\nif (props.dialog) {\n  config.set('future.useDialogForErrorModal', true)\n}\n</script>\n\n<template>\n  <div>\n    <span @click=\"invalidVisit\" class=\"invalid-visit\">Invalid Visit</span>\n    <span @click=\"invalidVisitJson\" class=\"invalid-visit-json\">Invalid Visit (JSON response)</span>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Events.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, router, usePage } from '@inertiajs/vue3'\n\ndeclare global {\n  interface Window {\n    messages: unknown[]\n  }\n}\n\nconst payloadWithFile = {\n  file: new File(['foobar'], 'example.bin'),\n}\n\nconst page = usePage()\n\nwindow.messages = []\n\nconst internalAlert = (...args: unknown[]) => {\n  window.messages.push(...args)\n}\n\nconst withoutEventListeners = () => {\n  router.post(page.url, {})\n}\n\nconst removeInertiaListener = () => {\n  const removeEventListener = router.on('before', () => internalAlert('Inertia.on(before)'))\n\n  internalAlert('Removing Inertia.on Listener')\n  removeEventListener()\n\n  router.post(\n    page.url,\n    {},\n    {\n      onBefore: () => internalAlert('onBefore'),\n      onStart: () => internalAlert('onStart'),\n    },\n  )\n}\n\nconst beforeVisit = () => {\n  router.on('before', (event) => {\n    internalAlert('Inertia.on(before)')\n    internalAlert(event)\n  })\n\n  document.addEventListener('inertia:before', (event) => {\n    internalAlert('addEventListener(inertia:before)')\n    internalAlert(event)\n  })\n\n  router.post(\n    page.url,\n    {},\n    {\n      onBefore: (event) => {\n        internalAlert('onBefore')\n        internalAlert(event)\n      },\n      onStart: () => internalAlert('onStart'),\n    },\n  )\n}\n\nconst beforeVisitPreventLocal = () => {\n  document.addEventListener('inertia:before', () => internalAlert('addEventListener(inertia:before)'))\n  router.on('before', () => internalAlert('Inertia.on(before)'))\n\n  router.post(\n    page.url,\n    {},\n    {\n      onBefore: () => {\n        internalAlert('onBefore')\n        return false\n      },\n      onStart: () => internalAlert('This listener should not have been called.'),\n    },\n  )\n}\n\nconst beforeVisitPreventGlobalInertia = () => {\n  document.addEventListener('inertia:before', () => internalAlert('addEventListener(inertia:before)'))\n  router.on('before', () => {\n    internalAlert('Inertia.on(before)')\n    return false\n  })\n\n  router.post(\n    page.url,\n    {},\n    {\n      onBefore: () => internalAlert('onBefore'),\n      onStart: () => internalAlert('This listener should not have been called.'),\n    },\n  )\n}\n\nconst beforeVisitPreventGlobalNative = () => {\n  router.on('before', () => internalAlert('Inertia.on(before)'))\n  document.addEventListener('inertia:before', (event) => {\n    internalAlert('addEventListener(inertia:before)')\n    event.preventDefault()\n  })\n\n  router.post(\n    page.url,\n    {},\n    {\n      onBefore: () => internalAlert('onBefore'),\n      onStart: () => internalAlert('This listener should not have been called.'),\n    },\n  )\n}\n\nconst cancelTokenVisit = () => {\n  // @ts-expect-error - We're testing that the router doesn't have an onCancelToken listener\n  router.on('cancelToken', () => internalAlert('This listener should not have been called.'))\n  document.addEventListener('inertia:cancelToken', () => internalAlert('This listener should not have been called.'))\n\n  router.post(\n    page.url,\n    {},\n    {\n      onCancelToken: (event) => {\n        internalAlert('onCancelToken')\n        internalAlert(event)\n      },\n    },\n  )\n}\n\nconst startVisit = () => {\n  router.on('start', (event) => {\n    internalAlert('Inertia.on(start)')\n    internalAlert(event)\n  })\n\n  document.addEventListener('inertia:start', (event) => {\n    internalAlert('addEventListener(inertia:start)')\n    internalAlert(event)\n  })\n\n  router.post(\n    page.url,\n    {},\n    {\n      onStart: (event) => {\n        internalAlert('onStart')\n        internalAlert(event)\n      },\n    },\n  )\n}\n\nconst progressVisit = () => {\n  router.on('progress', (event) => {\n    internalAlert('Inertia.on(progress)')\n    internalAlert(event)\n  })\n\n  document.addEventListener('inertia:progress', (event) => {\n    internalAlert('addEventListener(inertia:progress)')\n    internalAlert(event)\n  })\n\n  router.post(page.url, payloadWithFile, {\n    onProgress: (event) => {\n      internalAlert('onProgress')\n      internalAlert(event)\n    },\n  })\n}\n\nconst progressNoFilesVisit = () => {\n  router.on('progress', (event) => {\n    internalAlert('Inertia.on(progress)')\n    internalAlert(event)\n  })\n\n  document.addEventListener('inertia:progress', (event) => {\n    internalAlert('addEventListener(inertia:progress)')\n    internalAlert(event)\n  })\n\n  router.post(\n    page.url,\n    {},\n    {\n      onBefore: () => internalAlert('progressNoFilesOnBefore'),\n      onProgress: (event) => {\n        internalAlert('onProgress')\n        internalAlert(event)\n      },\n    },\n  )\n}\n\nconst cancelVisit = () => {\n  router.on('cancel', (event) => {\n    internalAlert('Inertia.on(cancel)')\n    internalAlert(event)\n  })\n\n  document.addEventListener('inertia:cancel', (event) => {\n    internalAlert('addEventListener(inertia:cancel)')\n    internalAlert(event)\n  })\n\n  router.post(\n    page.url,\n    {},\n    {\n      onCancelToken: (token) => token.cancel(),\n      // @ts-expect-error - We're testing that the onCancel callback has no arguments, so event will be undefined\n      onCancel: (event) => {\n        internalAlert('onCancel')\n        internalAlert(event)\n      },\n    },\n  )\n}\n\nconst errorVisit = () => {\n  router.on('error', (event) => {\n    internalAlert('Inertia.on(error)')\n    internalAlert(event)\n  })\n\n  document.addEventListener('inertia:error', (event) => {\n    internalAlert('addEventListener(inertia:error)')\n    internalAlert(event)\n  })\n\n  router.post(\n    '/events/errors',\n    {},\n    {\n      onError: (errors) => {\n        internalAlert('onError')\n        internalAlert(errors)\n      },\n    },\n  )\n}\n\nconst errorPromiseVisit = () => {\n  router.post(\n    '/events/errors',\n    {},\n    {\n      onError: () => callbackSuccessErrorPromise('onError'),\n      onSuccess: () => internalAlert('This listener should not have been called'),\n      onFinish: () => internalAlert('onFinish'),\n    },\n  )\n}\n\nconst successVisit = () => {\n  router.on('success', (event) => {\n    internalAlert('Inertia.on(success)')\n    internalAlert(event)\n  })\n\n  document.addEventListener('inertia:success', (event) => {\n    internalAlert('addEventListener(inertia:success)')\n    internalAlert(event)\n  })\n\n  router.post(\n    page.url,\n    {},\n    {\n      onError: () => internalAlert('This listener should not have been called'),\n      onSuccess: (page) => {\n        internalAlert('onSuccess')\n        internalAlert(page)\n      },\n    },\n  )\n}\n\nconst successPromiseVisit = () => {\n  router.post(\n    page.url,\n    {},\n    {\n      onSuccess: () => callbackSuccessErrorPromise('onSuccess'),\n      onError: () => internalAlert('This listener should not have been called'),\n      onFinish: () => internalAlert('onFinish'),\n    },\n  )\n}\n\nconst finishVisit = () => {\n  router.on('finish', (event) => {\n    internalAlert('Inertia.on(finish)')\n    internalAlert(event)\n  })\n\n  document.addEventListener('inertia:finish', (event) => {\n    internalAlert('addEventListener(inertia:finish)')\n    internalAlert(event)\n  })\n\n  router.post(\n    page.url,\n    {},\n    {\n      onFinish: (event) => {\n        internalAlert('onFinish')\n        internalAlert(event)\n      },\n    },\n  )\n}\n\nconst invalidVisit = () => {\n  router.on('invalid', (event) => {\n    internalAlert('Inertia.on(invalid)')\n    internalAlert(event)\n  })\n\n  document.addEventListener('inertia:invalid', (event) => {\n    internalAlert('addEventListener(inertia:invalid)')\n    internalAlert(event)\n  })\n\n  router.post(\n    '/non-inertia',\n    {},\n    {\n      // @ts-expect-error - We're testing that the VisitCallbacks interface does not have an onInvalid method\n      onInvalid: () => internalAlert('This listener should not have been called.'),\n    },\n  )\n}\n\nconst exceptionVisit = () => {\n  router.on('exception', (event) => {\n    internalAlert('Inertia.on(exception)')\n    internalAlert(event)\n  })\n\n  document.addEventListener('inertia:exception', (event) => {\n    internalAlert('addEventListener(inertia:exception)')\n    internalAlert(event)\n  })\n\n  router.post(\n    '/disconnect',\n    {},\n    {\n      // @ts-expect-error - We're testing that the VisitCallbacks interface does not have an onException method\n      onException: () => internalAlert('This listener should not have been called.'),\n    },\n  )\n}\n\nconst navigateVisit = () => {\n  router.on('navigate', (event) => {\n    internalAlert('Inertia.on(navigate)')\n    internalAlert(event)\n  })\n\n  document.addEventListener('inertia:navigate', (event) => {\n    internalAlert('addEventListener(inertia:navigate)')\n    internalAlert(event)\n  })\n\n  router.get(\n    '/',\n    {},\n    {\n      // @ts-expect-error - We're testing that the VisitCallbacks interface does not have an onNavigate method\n      onNavigate: () => internalAlert('This listener should not have been called.'),\n    },\n  )\n}\n\nconst registerAllListeners = () => {\n  router.on('before', () => internalAlert('Inertia.on(before)'))\n  // @ts-expect-error - We're testing that the router doesn't have an onCancelToken listener\n  router.on('cancelToken', () => internalAlert('Inertia.on(cancelToken)'))\n  router.on('cancel', () => internalAlert('Inertia.on(cancel)'))\n  router.on('start', () => internalAlert('Inertia.on(start)'))\n  router.on('progress', () => internalAlert('Inertia.on(progress)'))\n  router.on('error', () => internalAlert('Inertia.on(error)'))\n  router.on('success', () => internalAlert('Inertia.on(success)'))\n  router.on('invalid', () => internalAlert('Inertia.on(invalid)'))\n  router.on('exception', () => internalAlert('Inertia.on(exception)'))\n  router.on('finish', () => internalAlert('Inertia.on(finish)'))\n  router.on('navigate', () => internalAlert('Inertia.on(navigate)'))\n  document.addEventListener('inertia:before', () => internalAlert('addEventListener(inertia:before)'))\n  document.addEventListener('inertia:cancelToken', () => internalAlert('addEventListener(inertia:cancelToken)'))\n  document.addEventListener('inertia:cancel', () => internalAlert('addEventListener(inertia:cancel)'))\n  document.addEventListener('inertia:start', () => internalAlert('addEventListener(inertia:start)'))\n  document.addEventListener('inertia:progress', () => internalAlert('addEventListener(inertia:progress)'))\n  document.addEventListener('inertia:error', () => internalAlert('addEventListener(inertia:error)'))\n  document.addEventListener('inertia:success', () => internalAlert('addEventListener(inertia:success)'))\n  document.addEventListener('inertia:invalid', () => internalAlert('addEventListener(inertia:invalid)'))\n  document.addEventListener('inertia:exception', () => internalAlert('addEventListener(inertia:exception)'))\n  document.addEventListener('inertia:finish', () => internalAlert('addEventListener(inertia:finish)'))\n  document.addEventListener('inertia:navigate', () => internalAlert('addEventListener(inertia:navigate)'))\n\n  return {\n    onBefore: () => internalAlert('onBefore'),\n    onCancelToken: () => internalAlert('onCancelToken'),\n    onCancel: () => internalAlert('onCancel'),\n    onStart: () => internalAlert('onStart'),\n    onProgress: () => internalAlert('onProgress'),\n    onError: () => internalAlert('onError'),\n    onSuccess: () => internalAlert('onSuccess'),\n    onInvalid: () => internalAlert('onInvalid'), // Does not exist.\n    onException: () => internalAlert('onException'), // Does not exist.\n    onFinish: () => internalAlert('onFinish'),\n    onNavigate: () => internalAlert('onNavigate'), // Does not exist.\n  }\n}\n\nconst lifecycleSuccess = () => {\n  router.post(page.url, payloadWithFile, registerAllListeners())\n}\n\nconst lifecycleError = () => {\n  router.post('/events/errors', payloadWithFile, registerAllListeners())\n}\n\nconst lifecycleCancel = () => {\n  router.post('/sleep', payloadWithFile, {\n    ...registerAllListeners(),\n    onCancelToken: (token) => {\n      internalAlert('onCancelToken')\n\n      setTimeout(() => {\n        internalAlert('CANCELLING!')\n        token.cancel()\n      }, 250)\n    },\n  })\n}\n\nconst lifecycleCancelAfterFinish = () => {\n  type CancelToken = {\n    cancel: () => void\n  }\n\n  let cancelToken = <CancelToken | null>null\n\n  router.post(page.url, payloadWithFile, {\n    ...registerAllListeners(),\n    onCancelToken: (token: CancelToken) => {\n      internalAlert('onCancelToken')\n      cancelToken = token\n    },\n    onFinish: () => {\n      internalAlert('onFinish')\n      internalAlert('CANCELLING!')\n      cancelToken?.cancel()\n    },\n  })\n}\n\nconst callbackSuccessErrorPromise = (eventName: string) => {\n  internalAlert(eventName)\n  setTimeout(() => internalAlert('onFinish should have been fired by now if Promise functionality did not work'), 5)\n  return new Promise((resolve) => setTimeout(resolve, 20))\n}\n</script>\n\n<template>\n  <div>\n    <!-- Listeners -->\n    <a href=\"#\" @click.prevent=\"withoutEventListeners\" class=\"without-listeners\">Basic Visit</a>\n    <a href=\"#\" @click.prevent=\"removeInertiaListener\" class=\"remove-inertia-listener\">Remove Inertia Listener</a>\n\n    <!-- Events: Before -->\n    <a href=\"#\" @click.prevent=\"beforeVisit\" class=\"before\">Before Event</a>\n    <a href=\"#\" @click.prevent=\"beforeVisitPreventLocal\" class=\"before-prevent-local\">Before Event (Prevent)</a>\n    <Link\n      :href=\"$page.url\"\n      method=\"post\"\n      @before=\"(visit) => internalAlert('linkOnBefore', visit)\"\n      @start=\"() => internalAlert('linkOnStart')\"\n      class=\"link-before\"\n      >Before Event Link</Link\n    >\n    <Link\n      :href=\"$page.url\"\n      method=\"post\"\n      @before=\"\n        () => {\n          internalAlert('linkOnBefore')\n          return false\n        }\n      \"\n      @start=\"() => internalAlert('This listener should not have been called.')\"\n      class=\"link-before-prevent-local\"\n      >Before Event Link (Prevent)</Link\n    >\n    <a href=\"#\" @click.prevent=\"beforeVisitPreventGlobalInertia\" class=\"before-prevent-global-inertia\"\n      >Before Event - Prevent globally using Inertia Event Listener</a\n    >\n    <a href=\"#\" @click.prevent=\"beforeVisitPreventGlobalNative\" class=\"before-prevent-global-native\"\n      >Before Event - Prevent globally using Native Event Listeners</a\n    >\n\n    <!-- Events: CancelToken -->\n    <a href=\"#\" @click.prevent=\"cancelTokenVisit\" class=\"canceltoken\">Cancel Token Event</a>\n    <Link\n      :href=\"$page.url\"\n      method=\"post\"\n      @cancelToken=\"(event) => internalAlert('linkOnCancelToken', event)\"\n      class=\"link-canceltoken\"\n      >Cancel Token Event Link</Link\n    >\n\n    <!-- Events: Cancel -->\n    <a href=\"#\" @click.prevent=\"cancelVisit\" class=\"cancel\">Cancel Event</a>\n\n    <!-- @vue-expect-error - We're testing that the onCancel callback has no arguments, so event will be undefined -->\n    <Link\n      :href=\"$page.url\"\n      method=\"post\"\n      @cancelToken=\"(token) => token.cancel()\"\n      @cancel=\"(event) => internalAlert('linkOnCancel', event)\"\n      class=\"link-cancel\"\n      >Cancel Event Link</Link\n    >\n\n    <!-- Events: Start -->\n    <a href=\"#\" @click.prevent=\"startVisit\" class=\"start\">Start Event</a>\n    <Link :href=\"$page.url\" method=\"post\" @start=\"(event) => internalAlert('linkOnStart', event)\" class=\"link-start\"\n      >Start Event Link</Link\n    >\n\n    <!-- Events: Progress -->\n    <a href=\"#\" @click.prevent=\"progressVisit\" class=\"progress\">Progress Event</a>\n    <a href=\"#\" @click.prevent=\"progressNoFilesVisit\" class=\"progress-no-files\">Missing Progress Event (no files)</a>\n    <Link\n      :href=\"$page.url\"\n      method=\"post\"\n      :data=\"payloadWithFile\"\n      @progress=\"(event) => internalAlert('linkOnProgress', event)\"\n      class=\"link-progress\"\n      >Progress Event Link</Link\n    >\n    <Link\n      :href=\"$page.url\"\n      method=\"post\"\n      @before=\"() => internalAlert('linkProgressNoFilesOnBefore')\"\n      @progress=\"(event) => internalAlert('linkOnProgress', event)\"\n      class=\"link-progress-no-files\"\n      >Progress Event Link (no files)</Link\n    >\n\n    <!-- Events: Error -->\n    <a href=\"#\" @click.prevent=\"errorVisit\" class=\"error\">Error Event</a>\n    <a href=\"#\" @click.prevent=\"errorPromiseVisit\" class=\"error-promise\">Error Event (delaying onFinish w/ Promise)</a>\n    <Link\n      href=\"/events/errors\"\n      method=\"post\"\n      @error=\"(errors) => internalAlert('linkOnError', errors)\"\n      @success=\"() => internalAlert('This listener should not have been called')\"\n      class=\"link-error\"\n      >Error Event Link</Link\n    >\n    <Link\n      href=\"/events/errors\"\n      method=\"post\"\n      @error=\"() => callbackSuccessErrorPromise('linkOnError')\"\n      @success=\"() => internalAlert('This listener should not have been called')\"\n      @finish=\"() => internalAlert('linkOnFinish')\"\n      class=\"link-error-promise\"\n      >Error Event Link (delaying onFinish w/ Promise)</Link\n    >\n\n    <!-- Events: Success -->\n    <a href=\"#\" @click.prevent=\"successVisit\" class=\"success\">Success Event</a>\n    <a href=\"#\" @click.prevent=\"successPromiseVisit\" class=\"success-promise\"\n      >Success Event (delaying onFinish w/ Promise)</a\n    >\n    <Link\n      :href=\"$page.url\"\n      method=\"post\"\n      @error=\"() => internalAlert('This listener should not have been called')\"\n      @success=\"(event) => internalAlert('linkOnSuccess', event)\"\n      class=\"link-success\"\n      >Success Event Link</Link\n    >\n    <Link\n      :href=\"$page.url\"\n      method=\"post\"\n      @error=\"() => internalAlert('This listener should not have been called')\"\n      @success=\"() => callbackSuccessErrorPromise('linkOnSuccess')\"\n      @finish=\"() => internalAlert('linkOnFinish')\"\n      class=\"link-success-promise\"\n      >Success Event Link (delaying onFinish w/ Promise)</Link\n    >\n\n    <!-- Events: Invalid -->\n    <a href=\"#\" @click.prevent=\"invalidVisit\" class=\"invalid\">Invalid Event</a>\n\n    <!-- Events: Exception -->\n    <a href=\"#\" @click.prevent=\"exceptionVisit\" class=\"exception\">Exception Event</a>\n\n    <!-- Events: Finish -->\n    <a href=\"#\" @click.prevent=\"finishVisit\" class=\"finish\">Finish Event</a>\n    <Link :href=\"$page.url\" method=\"post\" @finish=\"(event) => internalAlert('linkOnFinish', event)\" class=\"link-finish\"\n      >Finish Event Link</Link\n    >\n\n    <!-- Events: Navigate -->\n    <a href=\"#\" @click.prevent=\"navigateVisit\" class=\"navigate\">Navigate Event</a>\n\n    <!-- Events: Prefetch -->\n    <Link\n      as=\"button\"\n      href=\"/prefetch/2\"\n      prefetch=\"hover\"\n      @prefetching=\"(visit) => internalAlert('linkOnPrefetching', visit)\"\n      @prefetched=\"(response, visit) => internalAlert('linkOnPrefetched', response, visit)\"\n      class=\"link-prefetch-hover\"\n    >\n      Prefetch Event Link (Hover)\n    </Link>\n\n    <!-- Lifecycles -->\n    <a href=\"#\" @click.prevent=\"lifecycleSuccess\" class=\"lifecycle-success\">Lifecycle Success</a>\n    <a href=\"#\" @click.prevent=\"lifecycleError\" class=\"lifecycle-error\">Lifecycle Error</a>\n    <a href=\"#\" @click.prevent=\"lifecycleCancel\" class=\"lifecycle-cancel\">Lifecycle Cancel</a>\n    <a href=\"#\" @click.prevent=\"lifecycleCancelAfterFinish\" class=\"lifecycle-cancel-after-finish\"\n      >Lifecycle Cancel - After Finish</a\n    >\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Flash/ClientSideVisits.vue",
    "content": "<script setup lang=\"ts\">\nimport { router, usePage } from '@inertiajs/vue3'\n\ndeclare global {\n  interface Window {\n    flashCount: number\n  }\n}\n\nwindow.flashCount ??= 0\n\nconst page = usePage()\n\nconst withFlash = () => {\n  router.replace({\n    flash: { foo: 'bar' },\n    onFlash: () => window.flashCount++,\n  })\n}\n\nconst withFlashFunction = () => {\n  router.replace({\n    flash: (flash) => ({ ...flash, bar: 'baz' }),\n    onFlash: () => window.flashCount++,\n  })\n}\n\nconst withoutFlash = () => {\n  router.replace({\n    props: (props) => ({ ...props }),\n    onFlash: () => window.flashCount++,\n  })\n}\n</script>\n\n<template>\n  <div>\n    <span id=\"flash\">{{ JSON.stringify(page.flash) }}</span>\n\n    <button @click=\"withFlash\">With flash object</button>\n    <button @click=\"withFlashFunction\">With flash function</button>\n    <button @click=\"withoutFlash\">Without flash</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Flash/Events.vue",
    "content": "<script setup lang=\"ts\">\nimport { router, usePage } from '@inertiajs/vue3'\n\ndeclare global {\n  interface Window {\n    messages: unknown[]\n  }\n}\n\nconst page = usePage()\n\nwindow.messages = []\n\nconst internalAlert = (...args: unknown[]) => {\n  window.messages.push(...args)\n}\n\nconst visitWithFlash = () => {\n  router.on('flash', (event) => {\n    internalAlert('Inertia.on(flash)')\n    internalAlert(event.detail.flash)\n  })\n\n  document.addEventListener('inertia:flash', (event) => {\n    internalAlert('addEventListener(inertia:flash)')\n    internalAlert((event as CustomEvent).detail.flash)\n  })\n\n  router.post(\n    '/flash/events/with-data',\n    {},\n    {\n      onFlash: (flash) => {\n        internalAlert('onFlash')\n        internalAlert(flash)\n      },\n      onSuccess: (page) => {\n        internalAlert('onSuccess')\n        internalAlert(page.flash)\n      },\n    },\n  )\n}\n\nconst visitWithoutFlash = () => {\n  router.on('flash', () => {\n    internalAlert('Inertia.on(flash)')\n  })\n\n  document.addEventListener('inertia:flash', () => {\n    internalAlert('addEventListener(inertia:flash)')\n  })\n\n  router.post(\n    '/flash/events/without-data',\n    {},\n    {\n      onFlash: () => {\n        internalAlert('onFlash')\n      },\n      onSuccess: () => {\n        internalAlert('onSuccess')\n      },\n    },\n  )\n}\n\nconst navigateAway = () => {\n  router.get('/')\n}\n</script>\n\n<template>\n  <div>\n    <span id=\"flash\">{{ JSON.stringify(page.flash) }}</span>\n\n    <a href=\"#\" @click.prevent=\"visitWithFlash\" class=\"with-flash\">Visit with flash</a>\n    <a href=\"#\" @click.prevent=\"visitWithoutFlash\" class=\"without-flash\">Visit without flash</a>\n    <a href=\"#\" @click.prevent=\"navigateAway\" class=\"navigate-away\">Navigate away</a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Flash/InitialFlash.vue",
    "content": "<script setup lang=\"ts\">\nimport { router, usePage } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst page = usePage()\nconst flashEvents = ref<Record<string, unknown>[]>([])\n\nrouter.on('flash', (e) => {\n  flashEvents.value.push(e.detail.flash)\n})\n</script>\n\n<template>\n  <div>\n    <span id=\"flash\">{{ page.flash ? JSON.stringify(page.flash) : 'no-flash' }}</span>\n    <span id=\"flash-events\">{{ JSON.stringify(flashEvents) }}</span>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Flash/Partial.vue",
    "content": "<script setup lang=\"ts\">\nimport { router, usePage } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\ndefineProps<{\n  count: number\n}>()\n\nconst page = usePage()\nconst flashEventCount = ref(0)\n\nrouter.on('flash', () => {\n  flashEventCount.value++\n})\n\nconst reloadWithSameFlash = () => {\n  router.reload({ only: ['count'], data: { flashType: 'same', count: Date.now() } })\n}\n\nconst reloadWithDifferentFlash = () => {\n  router.reload({ only: ['count'], data: { flashType: 'different', count: Date.now() } })\n}\n</script>\n\n<template>\n  <div>\n    <span id=\"flash\">{{ JSON.stringify(page.flash) }}</span>\n    <span id=\"flash-event-count\">{{ flashEventCount }}</span>\n    <span id=\"count\">{{ count }}</span>\n\n    <button @click=\"reloadWithSameFlash\">Reload with same flash</button>\n    <button @click=\"reloadWithDifferentFlash\">Reload with different flash</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Flash/RouterFlash.vue",
    "content": "<script setup lang=\"ts\">\nimport { router, usePage } from '@inertiajs/vue3'\n\nconst page = usePage()\n\nconst setFlash = () => {\n  router.flash({ foo: 'bar' })\n}\n\nconst setFlashKeyValue = () => {\n  router.flash('foo', 'bar')\n}\n\nconst mergeFlash = () => {\n  router.flash((current) => ({ ...current, bar: 'baz' }))\n}\n\nconst clearFlash = () => {\n  router.flash(() => ({}))\n}\n</script>\n\n<template>\n  <div>\n    <span id=\"flash\">{{ JSON.stringify(page.flash) }}</span>\n\n    <button @click=\"setFlash\">Set flash</button>\n    <button @click=\"setFlashKeyValue\">Set flash key-value</button>\n    <button @click=\"mergeFlash\">Merge flash</button>\n    <button @click=\"clearFlash\">Clear flash</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Flash/WithDeferred.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, router, usePage } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\ndefineProps<{\n  data?: string\n}>()\n\nconst page = usePage()\nconst flashEventCount = ref(0)\n\nrouter.on('flash', () => {\n  flashEventCount.value++\n})\n</script>\n\n<template>\n  <div>\n    <span id=\"flash\">{{ JSON.stringify(page.flash) }}</span>\n    <span id=\"flash-event-count\">{{ flashEventCount }}</span>\n\n    <Deferred data=\"data\">\n      <template #fallback>\n        <div id=\"loading\">Loading...</div>\n      </template>\n      <div id=\"data\">{{ data }}</div>\n    </Deferred>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Flash/WithInfiniteScroll.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll, router, usePage } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\ndefineProps<{\n  users: {\n    data: { id: number; name: string }[]\n  }\n}>()\n\nconst page = usePage()\nconst flashEventCount = ref(0)\n\nrouter.on('flash', () => {\n  flashEventCount.value++\n})\n</script>\n\n<template>\n  <div>\n    <span id=\"flash\">{{ JSON.stringify(page.flash) }}</span>\n    <span id=\"flash-event-count\">{{ flashEventCount }}</span>\n\n    <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\">\n      <div v-for=\"user in users.data\" :key=\"user.id\" style=\"height: 15vh; border: 1px solid #ccc\">\n        {{ user.name }}\n      </div>\n    </InfiniteScroll>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Context/ChildComponent.vue",
    "content": "<script setup lang=\"ts\">\nimport { useFormContext } from '@inertiajs/vue3'\n\ndefineProps<{\n  formId?: string\n}>()\n\nconst form = useFormContext()\n</script>\n\n<template>\n  <div v-if=\"form\">\n    <span>Child: Form is {{ form.isDirty ? 'dirty' : 'clean' }}</span>\n    <span v-if=\"form.hasErrors\"> | Child: Form has errors</span>\n    <span v-if=\"form.processing\"> | Child: Form is processing</span>\n    <span v-if=\"form.wasSuccessful\"> | Child: Form was successful</span>\n    <span v-if=\"form.recentlySuccessful\"> | Child: Form recently successful</span>\n    <span v-if=\"form.errors.name\"> | Error: {{ form.errors.name }}</span>\n  </div>\n  <div v-else>No form context available</div>\n\n  <button type=\"button\" @click=\"form?.setError('name', formId ? 'Error from child' : 'Error set from child component')\">\n    Set Error\n  </button>\n  <button type=\"button\" @click=\"form?.clearErrors('name')\">Clear Error</button>\n  <button v-if=\"!formId\" type=\"button\" @click=\"form?.submit()\">Submit from Child</button>\n  <button v-if=\"!formId\" type=\"button\" @click=\"form?.reset()\">Reset from Child</button>\n  <button v-if=\"!formId\" type=\"button\" @click=\"form?.defaults()\">Set Defaults</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Context/DeeplyNestedComponent.vue",
    "content": "<script setup lang=\"ts\">\nimport { useFormContext } from '@inertiajs/vue3'\n\nconst form = useFormContext()\n</script>\n\n<template>\n  <div v-if=\"form\">\n    <span>Deeply Nested: Form is {{ form.isDirty ? 'dirty' : 'clean' }}</span>\n  </div>\n  <div v-else>No context</div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Context/Default.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\nimport ChildComponent from './ChildComponent.vue'\nimport NestedComponent from './NestedComponent.vue'\nimport OutsideFormComponent from './OutsideFormComponent.vue'\n</script>\n\n<template>\n  <Form action=\"/dump/post\" method=\"post\" #default=\"{ isDirty, hasErrors, errors }\">\n    <div>\n      <span>Parent: Form is {{ isDirty ? 'dirty' : 'clean' }}</span>\n      <span v-if=\"hasErrors\"> | Parent: Form has errors</span>\n      <span v-if=\"errors.name\"> | {{ errors.name }}</span>\n    </div>\n\n    <input type=\"text\" name=\"name\" value=\"John Doe\" />\n    <input type=\"email\" name=\"email\" value=\"john@example.com\" />\n\n    <ChildComponent />\n    <NestedComponent />\n  </Form>\n\n  <OutsideFormComponent />\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Context/Methods.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\nimport MethodsTestComponent from './MethodsTestComponent.vue'\n</script>\n\n<template>\n  <Form action=\"/form-component/context/methods\" method=\"post\" #default=\"{ errors }\">\n    <pre v-if=\"Object.keys(errors).length\">{{ JSON.stringify(errors, null, 2) }}</pre>\n\n    <input type=\"text\" name=\"name\" value=\"Initial Name\" />\n    <input type=\"email\" name=\"email\" value=\"initial@example.com\" />\n    <textarea name=\"bio\">Initial bio</textarea>\n\n    <MethodsTestComponent />\n  </Form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Context/MethodsTestComponent.vue",
    "content": "<script setup lang=\"ts\">\nimport { useFormContext } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst form = useFormContext()\n\nconst getDataResult = ref('')\nconst getFormDataResult = ref('')\n\nfunction testGetData() {\n  if (form) {\n    getDataResult.value = JSON.stringify(form.getData(), null, 2)\n  }\n}\n\nfunction testGetFormData() {\n  if (form) {\n    const formData = form.getFormData()\n    const obj: Record<string, FormDataEntryValue> = {}\n    formData.forEach((value, key) => {\n      obj[key] = value\n    })\n    getFormDataResult.value = JSON.stringify(obj, null, 2)\n  }\n}\n</script>\n\n<template>\n  <div v-if=\"form\">\n    <span v-if=\"form.processing\">Child: processing</span>\n    <span v-if=\"form.wasSuccessful\">Child: was successful</span>\n    <span v-if=\"form.recentlySuccessful\">Child: recently successful</span>\n    <pre v-if=\"form.hasErrors\">{{ JSON.stringify(form.errors, null, 2) }}</pre>\n\n    <button type=\"button\" @click=\"form.submit()\">submit()</button>\n    <button type=\"button\" @click=\"form.reset()\">reset()</button>\n    <button type=\"button\" @click=\"form.reset('name')\">reset('name')</button>\n    <button type=\"button\" @click=\"form.reset('name', 'email')\">reset('name', 'email')</button>\n\n    <button type=\"button\" @click=\"form.clearErrors()\">clearErrors()</button>\n    <button type=\"button\" @click=\"form.clearErrors('name')\">clearErrors('name')</button>\n    <button type=\"button\" @click=\"form.setError('name', 'Name is invalid')\">setError('name')</button>\n    <button\n      type=\"button\"\n      @click=\"\n        form.setError({\n          name: 'Name error from child',\n          email: 'Email error from child',\n          bio: 'Bio error from child',\n        })\n      \"\n    >\n      setError({...})\n    </button>\n\n    <button type=\"button\" @click=\"form.resetAndClearErrors()\">resetAndClearErrors()</button>\n    <button type=\"button\" @click=\"form.resetAndClearErrors('name')\">resetAndClearErrors('name')</button>\n\n    <button type=\"button\" @click=\"testGetData\">getData()</button>\n    <button type=\"button\" @click=\"testGetFormData\">getFormData()</button>\n\n    <pre v-if=\"getDataResult\" id=\"get-data-result\">{{ getDataResult }}</pre>\n    <pre v-if=\"getFormDataResult\" id=\"get-form-data-result\">{{ getFormDataResult }}</pre>\n  </div>\n  <div v-else>No form context available</div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Context/Multiple.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\nimport ChildComponent from './ChildComponent.vue'\n</script>\n\n<template>\n  <Form action=\"/dump/post\" method=\"post\" #default=\"{ isDirty, errors }\">\n    <div>\n      <span>Form 1 Parent: {{ isDirty ? 'dirty' : 'clean' }}</span>\n      <span v-if=\"errors.name\"> | Error: {{ errors.name }}</span>\n    </div>\n    <input type=\"text\" name=\"name\" value=\"Form 1 Name\" />\n    <ChildComponent form-id=\"form1\" />\n  </Form>\n\n  <Form action=\"/dump/post\" method=\"post\" #default=\"{ isDirty, errors }\">\n    <div>\n      <span>Form 2 Parent: {{ isDirty ? 'dirty' : 'clean' }}</span>\n      <span v-if=\"errors.name\"> | Error: {{ errors.name }}</span>\n    </div>\n    <input type=\"text\" name=\"name\" value=\"Form 2 Name\" />\n    <ChildComponent form-id=\"form2\" />\n  </Form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Context/NestedComponent.vue",
    "content": "<script setup lang=\"ts\">\nimport DeeplyNestedComponent from './DeeplyNestedComponent.vue'\n</script>\n\n<template>\n  <DeeplyNestedComponent />\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Context/OutsideFormComponent.vue",
    "content": "<script setup lang=\"ts\">\nimport { useFormContext } from '@inertiajs/vue3'\n\nconst form = useFormContext()\n</script>\n\n<template>\n  <div v-if=\"form === undefined\">Correctly returns undefined when used outside a Form component</div>\n  <div v-else>Unexpectedly has form context</div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/DataMethods.vue",
    "content": "<script setup lang=\"ts\">\nimport { FormDataConvertible } from '@inertiajs/core'\nimport { Form } from '@inertiajs/vue3'\n\nfunction testGetData(getData: () => Record<string, FormDataConvertible>) {\n  const data = getData()\n  console.log('getData result: ' + JSON.stringify(data))\n}\n\nfunction testGetFormData(getFormData: () => FormData) {\n  const formData = getFormData()\n  console.log('getFormData entries: ' + JSON.stringify(Object.fromEntries(formData.entries())))\n}\n</script>\n\n<template>\n  <div>\n    <h1>Test getData() and getFormData() Methods</h1>\n\n    <Form v-slot=\"{ getData, getFormData }\">\n      <input id=\"name\" type=\"text\" name=\"name\" />\n\n      <button type=\"button\" @click=\"testGetData(getData)\">Test getData()</button>\n\n      <button type=\"button\" @click=\"testGetFormData(getFormData)\">Test getFormData()</button>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/DefaultValue.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n\ndefineProps<{\n  user: {\n    name: string\n  }\n}>()\n</script>\n\n<template>\n  <Form action=\"/form-component/default-value\" method=\"patch\" v-slot=\"{ errors }\">\n    <h1>Form Default Values</h1>\n\n    <div>\n      <label for=\"name\">Name</label>\n      <input type=\"text\" name=\"name\" id=\"name\" :defaultValue=\"user.name\" />\n      <div id=\"error_name\">{{ errors['user.name'] }}</div>\n    </div>\n\n    <button type=\"submit\">Submit</button>\n  </Form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/DisableWhileProcessing.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\ndefineProps<{\n  disable: boolean\n}>()\n</script>\n\n<template>\n  <div>\n    <h1>Form Disable While Processing Test</h1>\n\n    <Form\n      method=\"post\"\n      :action=\"`/form-component/disable-while-processing/${disable ? 'yes' : 'no'}/submit`\"\n      :disable-while-processing=\"disable\"\n    >\n      <div>\n        <input type=\"text\" name=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n      </div>\n\n      <div>\n        <button type=\"submit\">Submit</button>\n      </div>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/DottedKeys.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <h1>Dotted Keys Form Test</h1>\n\n    <!-- Test basic and nested dotted keys -->\n    <Form action=\"/dump/post\" method=\"post\">\n      <h2>Basic Dotted Keys</h2>\n      <input type=\"text\" name=\"user.name\" placeholder=\"User Name\" />\n      <input type=\"text\" name=\"user.profile.city\" placeholder=\"City\" />\n      <input type=\"text\" name=\"user.skills[]\" placeholder=\"First Skill\" />\n      <input type=\"text\" name=\"user.skills[]\" placeholder=\"Second Skill\" />\n      <input type=\"text\" name=\"company.address.street\" placeholder=\"Street\" />\n      <button type=\"submit\">Submit Basic</button>\n    </Form>\n\n    <!-- Test escaped dots (literal keys) -->\n    <Form action=\"/dump/post\" method=\"post\">\n      <h2>Escaped Dots</h2>\n      <input type=\"text\" name=\"config\\.app\\.name\" placeholder=\"App Name\" />\n      <input type=\"text\" name=\"settings.theme\\.mode\" placeholder=\"Theme Mode\" />\n      <button type=\"submit\">Submit Escaped</button>\n    </Form>\n\n    <!-- Test mixed bracket and dotted notation -->\n    <Form action=\"/dump/post\" method=\"post\">\n      <h2>Mixed Notation</h2>\n      <input type=\"text\" name=\"user[roles][]\" value=\"admin\" />\n      <input type=\"text\" name=\"user[roles][]\" value=\"editor\" />\n      <input type=\"text\" name=\"settings.ui.theme\" placeholder=\"UI Theme\" />\n      <button type=\"submit\">Submit Mixed</button>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Elements.vue",
    "content": "<script setup lang=\"ts\">\nimport { QueryStringArrayFormatOption } from '@inertiajs/core'\nimport { config, Form } from '@inertiajs/vue3'\n\nconst props = defineProps<{\n  queryStringArrayFormat: QueryStringArrayFormatOption | 'force-brackets'\n}>()\n\nconst format = props.queryStringArrayFormat === 'force-brackets' ? 'brackets' : props.queryStringArrayFormat\n\nif (props.queryStringArrayFormat === 'force-brackets') {\n  config.set('form.forceIndicesArrayFormatInFormData', false)\n}\n</script>\n\n<template>\n  <Form action=\"/dump/post\" method=\"post\" v-slot=\"{ isDirty }\" :queryStringArrayFormat=\"format\">\n    <h1>Form Elements</h1>\n    <div>Form is <span v-if=\"isDirty\">dirty</span><span v-else>clean</span></div>\n\n    <!-- Text input -->\n    <div>\n      <input type=\"text\" name=\"name\" id=\"name\" placeholder=\"Name\" />\n    </div>\n\n    <!-- Select with default selected option -->\n    <div>\n      <select name=\"country\" id=\"country\">\n        <option value=\"us\">United States</option>\n        <option value=\"ca\">Canada</option>\n        <option value=\"uk\" selected>United Kingdom</option>\n      </select>\n    </div>\n\n    <!-- Select with default disabled option -->\n    <div>\n      <select name=\"role\" id=\"role\">\n        <option value=\"\" disabled selected>Role</option>\n        <option>User</option>\n        <option>Admin</option>\n        <option>Super</option>\n      </select>\n    </div>\n\n    <!-- Radio buttons -->\n    <div>\n      <label><input type=\"radio\" name=\"plan\" value=\"free\" /> Free</label>\n      <label><input type=\"radio\" name=\"plan\" value=\"pro\" /> Pro</label>\n      <label><input type=\"radio\" name=\"plan\" value=\"enterprise\" /> Enterprise</label>\n    </div>\n\n    <!-- Checkbox (single) -->\n    <div>\n      <input type=\"checkbox\" name=\"subscribe\" value=\"yes\" id=\"subscribe\" />\n      <label for=\"subscribe\">Subscribe to newsletter</label>\n    </div>\n\n    <!-- Checkbox (multiple) -->\n    <div>\n      <label><input type=\"checkbox\" name=\"interests[]\" value=\"sports\" /> Sports</label>\n      <label><input type=\"checkbox\" name=\"interests[]\" value=\"music\" /> Music</label>\n      <label><input type=\"checkbox\" name=\"interests[]\" value=\"tech\" /> Tech</label>\n    </div>\n\n    <!-- Multiple select -->\n    <div>\n      <select name=\"skills[]\" id=\"skills\" multiple>\n        <option disabled selected>Skills</option>\n        <option value=\"vue\">Vue</option>\n        <option value=\"react\">React</option>\n        <option value=\"angular\">Angular</option>\n        <option value=\"svelte\">Svelte</option>\n      </select>\n    </div>\n\n    <!-- File input (single) -->\n\n    <div>\n      <input type=\"file\" name=\"avatar\" id=\"avatar\" placeholder=\"Avatar\" />\n    </div>\n\n    <!-- File input (multiple) -->\n    <div>\n      <input type=\"file\" name=\"documents[]\" id=\"documents\" multiple placeholder=\"Documents\" />\n    </div>\n\n    <!-- Textarea -->\n    <div>\n      <textarea name=\"bio\" id=\"bio\" rows=\"3\" placeholder=\"Bio\"></textarea>\n    </div>\n\n    <!-- Hidden input -->\n    <div>\n      <input type=\"hidden\" name=\"token\" id=\"token\" value=\"abc123\" />\n    </div>\n\n    <!-- Number input -->\n    <div>\n      <input type=\"number\" name=\"age\" id=\"age\" placeholder=\"Age\" />\n    </div>\n\n    <!-- Deep nested input -->\n    <div>\n      <input type=\"text\" name=\"user[address][street]\" id=\"nested_street\" placeholder=\"Street\" />\n    </div>\n\n    <!-- Indexed array of objects -->\n    <div>\n      <input type=\"text\" name=\"items[0][name]\" value=\"Item A\" id=\"item_a\" />\n      <input type=\"text\" name=\"items[1][name]\" value=\"Item B\" id=\"item_b\" />\n    </div>\n\n    <!-- Disabled input (should be ignored) -->\n    <div>\n      <input type=\"text\" name=\"disabled_field\" value=\"Ignore me\" disabled />\n    </div>\n\n    <button type=\"submit\">Submit</button>\n    <button type=\"reset\">Reset</button>\n  </Form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/EmptyAction.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <h1>Form Empty Action Test</h1>\n\n    <Form method=\"post\" #default=\"{ errors }\">\n      <div>\n        <input type=\"text\" name=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n        <p v-if=\"errors.name\" id=\"error_name\">{{ errors.name }}</p>\n      </div>\n\n      <div>\n        <button type=\"submit\">Submit</button>\n      </div>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Errors.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst errorBag = ref<string | null>(null)\n\nfunction setErrorBag(bag: string) {\n  errorBag.value = bag\n}\n</script>\n\n<template>\n  <Form\n    :action=\"errorBag ? '/form-component/errors/bag' : '/form-component/errors'\"\n    method=\"post\"\n    v-slot=\"{ errors, hasErrors, setError, clearErrors }\"\n    v-bind=\"errorBag ? { errorBag } : {}\"\n  >\n    <h1>Form Errors</h1>\n\n    <div>\n      <div v-if=\"hasErrors\">Form has errors</div>\n      <div v-else>No errors</div>\n    </div>\n\n    <div>\n      <label for=\"name\">Name</label>\n      <input type=\"text\" name=\"name\" id=\"name\" />\n      <div id=\"error_name\">{{ errors.name }}</div>\n    </div>\n\n    <div>\n      <label for=\"handle\">Handle</label>\n      <input type=\"text\" name=\"handle\" id=\"handle\" />\n      <div id=\"error_handle\">{{ errors.handle }}</div>\n    </div>\n\n    <div>\n      <button\n        type=\"button\"\n        @click=\"\n          setError({\n            name: 'The name field is required.',\n            handle: 'The handle field is invalid.',\n          })\n        \"\n      >\n        Set Errors\n      </button>\n      <button type=\"button\" @click=\"clearErrors()\">Clear Errors</button>\n      <button type=\"button\" @click=\"clearErrors('name')\">Clear Name Error</button>\n      <button type=\"button\" @click=\"setErrorBag('bag')\">Use Error Bag</button>\n    </div>\n\n    <button type=\"submit\">Submit</button>\n  </Form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Events.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\nimport { computed, ref } from 'vue'\n\nconst events = ref<string[]>([])\nconst cancelInOnBefore = ref(false)\nconst shouldFail = ref(false)\nconst shouldDelay = ref(false)\n\nlet cancelToken: { cancel: () => void } | null = null\n\nfunction log(eventName: string) {\n  events.value.push(eventName)\n}\n\nconst action = computed(() => {\n  if (shouldFail.value) {\n    return '/form-component/events/errors'\n  }\n\n  if (shouldDelay.value) {\n    return '/form-component/events/delay'\n  }\n\n  return '/form-component/events/success'\n})\n\nfunction formEvents() {\n  return {\n    onBefore: () => {\n      log('onBefore')\n\n      if (cancelInOnBefore.value) {\n        log('onCancel')\n        return false\n      }\n    },\n    onStart: () => log('onStart'),\n    onProgress: () => log('onProgress'),\n    onFinish: () => log('onFinish'),\n    onCancel: () => log('onCancel'),\n    onSuccess: () => log('onSuccess'),\n    onError: () => log('onError'),\n    onCancelToken: (token: { cancel: () => void }) => {\n      log('onCancelToken')\n      cancelToken = token\n    },\n  }\n}\n\nfunction cancelVisit() {\n  if (cancelToken) {\n    cancelToken.cancel()\n    cancelToken = null\n  }\n}\n</script>\n\n<template>\n  <Form\n    :action=\"action\"\n    method=\"post\"\n    v-bind=\"formEvents()\"\n    v-slot=\"{ processing, progress, wasSuccessful, recentlySuccessful }\"\n  >\n    <h1>Form Events & State</h1>\n\n    <div>\n      Events: <span id=\"events\">{{ events.join(',') }}</span>\n    </div>\n\n    <div>\n      Processing: <span id=\"processing\">{{ processing }}</span>\n    </div>\n\n    <div>\n      Progress:\n      <span id=\"progress\" :class=\"progress?.percentage ? 'uploading' : undefined\">{{ progress?.percentage || 0 }}</span>\n    </div>\n\n    <div>\n      Was successful: <span id=\"was-successful\">{{ wasSuccessful }}</span>\n    </div>\n\n    <div>\n      Recently successful: <span id=\"recently-successful\">{{ recentlySuccessful }}</span>\n    </div>\n\n    <div>\n      <input type=\"file\" name=\"avatar\" id=\"avatar\" />\n    </div>\n\n    <div>\n      <button type=\"button\" @click=\"cancelInOnBefore = true\">Cancel in onBefore</button>\n      <button type=\"button\" @click=\"shouldFail = true\">Fail Request</button>\n      <button type=\"button\" @click=\"shouldDelay = true\">Should Delay</button>\n      <button type=\"button\" @click=\"cancelVisit\">Cancel Visit</button>\n      <button type=\"submit\">Submit</button>\n    </div>\n  </Form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/FormTarget.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <Form action=\"/non-inertia/download\" method=\"get\">\n    <input type=\"text\" name=\"search\" id=\"search\" value=\"test-query\" />\n\n    <button type=\"submit\" formtarget=\"_blank\" name=\"format\" value=\"csv\" id=\"button-blank\">\n      Button with formTarget blank\n    </button>\n    <input type=\"submit\" formtarget=\"_blank\" name=\"type\" value=\"export\" id=\"input-blank\" />\n  </Form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Headers.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst headers = ref<Record<string, string>>({\n  'X-Foo': 'Bar',\n})\n\nfunction addCustomHeader() {\n  headers.value['X-Custom'] = 'MyCustomValue'\n}\n</script>\n\n<template>\n  <Form action=\"/dump/post\" method=\"post\" :headers=\"headers\">\n    <h1>Form Headers</h1>\n\n    <div>\n      <button type=\"button\" @click=\"addCustomHeader\">Add Custom Header</button>\n    </div>\n\n    <button type=\"submit\">Submit</button>\n  </Form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/InvalidateTags.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form, Link } from '@inertiajs/vue3'\n\ndefineProps({\n  lastLoaded: Number,\n  propType: String,\n})\n</script>\n\n<template>\n  <div>\n    <div id=\"links\">\n      <Link href=\"/prefetch/tags/1\" prefetch=\"hover\" :cache-tags=\"propType === 'string' ? 'user' : ['user']\">\n        User Tagged Page\n      </Link>\n      <Link href=\"/prefetch/tags/2\" prefetch=\"hover\" :cache-tags=\"propType === 'string' ? 'product' : ['product']\">\n        Product Tagged Page\n      </Link>\n    </div>\n\n    <div id=\"form-section\">\n      <h3>Form Component with invalidateCacheTags</h3>\n      <Form action=\"/dump/post\" method=\"post\" :invalidate-cache-tags=\"propType === 'string' ? 'user' : ['user']\">\n        <input id=\"form-name\" name=\"name\" type=\"text\" placeholder=\"Enter name\" />\n        <button id=\"submit-invalidate-user\" type=\"submit\">Submit (Invalidate User Tags)</button>\n      </Form>\n    </div>\n\n    <div>\n      <div>Form Component Invalidate Tags Test Page</div>\n      <div>\n        Last loaded at <span id=\"last-loaded\">{{ lastLoaded }}</span>\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Methods.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Method } from '@inertiajs/core'\nimport { Form } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst method = ref<Method>('get')\n</script>\n\n<template>\n  <div>\n    <h1>HTTP Methods</h1>\n\n    <div>\n      <button @click=\"method = 'get'\">GET</button>\n      <button @click=\"method = 'post'\">POST</button>\n      <button @click=\"method = 'put'\">PUT</button>\n      <button @click=\"method = 'patch'\">PATCH</button>\n      <button @click=\"method = 'delete'\">DELETE</button>\n    </div>\n\n    <div>Current method: {{ method }}</div>\n\n    <Form :action=\"`/dump/${method}`\" :method=\"method\">\n      <div>\n        <input type=\"text\" name=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n      </div>\n\n      <div>\n        <input type=\"checkbox\" name=\"active\" value=\"true\" checked />\n        <label>Active</label>\n      </div>\n\n      <div>\n        <button type=\"submit\">Submit {{ method.toUpperCase() }}</button>\n      </div>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/MixedKeySerialization.vue",
    "content": "<script setup lang=\"ts\">\nimport { FormComponentRef } from '@inertiajs/core'\nimport { Form } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst formRef = ref<FormComponentRef | null>(null)\n</script>\n\n<template>\n  <div>\n    <h1>Mixed Key Serialization</h1>\n\n    <Form ref=\"formRef\" action=\"/dump/post\" method=\"post\">\n      <div>\n        <input type=\"text\" name=\"fields[entries][100][name]\" placeholder=\"Name for ID 100\" value=\"John Doe\" />\n      </div>\n\n      <div>\n        <input\n          type=\"email\"\n          name=\"fields[entries][100][email]\"\n          placeholder=\"Email for ID 100\"\n          value=\"john@example.com\"\n        />\n      </div>\n\n      <div>\n        <input type=\"text\" name=\"fields[entries][new:1][name]\" placeholder=\"Name for new entry\" value=\"Jane Smith\" />\n      </div>\n\n      <div>\n        <input\n          type=\"email\"\n          name=\"fields[entries][new:1][email]\"\n          placeholder=\"Email for new entry\"\n          value=\"jane@example.com\"\n        />\n      </div>\n\n      <button type=\"submit\">Submit</button>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Options.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Method, QueryStringArrayFormatOption } from '@inertiajs/core'\nimport { Form } from '@inertiajs/vue3'\nimport { computed, ref } from 'vue'\nimport Article from './../Article.vue'\n\nconst only = ref<string[]>([])\nconst except = ref<string[]>([])\nconst reset = ref<string[]>([])\nconst replace = ref(false)\nconst state = ref('Default State')\nconst preserveScroll = ref(false)\nconst preserveState = ref(false)\nconst preserveUrl = ref(false)\nconst queryStringArrayFormat = ref<QueryStringArrayFormatOption | undefined>(undefined)\n\nfunction setOnly() {\n  only.value = ['users']\n}\n\nfunction setExcept() {\n  except.value = ['stats']\n}\n\nfunction setReset() {\n  reset.value = ['orders']\n}\n\nfunction enableReplace() {\n  replace.value = true\n}\n\nfunction enablePreserveScroll() {\n  preserveScroll.value = true\n}\n\nfunction enablePreserveState() {\n  preserveState.value = true\n  state.value = 'Replaced State'\n}\n\nfunction enablePreserveUrl() {\n  preserveUrl.value = true\n}\n\nconst action = computed(() => {\n  if (preserveScroll.value) {\n    return '/article'\n  }\n\n  if (preserveState.value) {\n    return '/form-component/options'\n  }\n\n  if (preserveUrl.value) {\n    return '/form-component/options?page=2'\n  }\n\n  return queryStringArrayFormat.value ? '/dump/get' : '/dump/post'\n})\n\nconst method = computed((): Method => {\n  if (preserveScroll.value || preserveState.value || preserveUrl.value) {\n    return 'get'\n  }\n\n  return queryStringArrayFormat.value ? 'get' : 'post'\n})\n</script>\n\n<template>\n  <Form\n    :action=\"action\"\n    :method=\"method\"\n    :options=\"{\n      only,\n      except,\n      reset,\n      replace,\n      preserveScroll,\n      preserveState,\n      preserveUrl,\n    }\"\n    :query-string-array-format=\"queryStringArrayFormat\"\n  >\n    <h1>Form Options</h1>\n\n    <input type=\"text\" name=\"tags[]\" value=\"alpha\" />\n    <input type=\"text\" name=\"tags[]\" value=\"beta\" />\n\n    <div>\n      State: <span id=\"state\">{{ state }}</span>\n    </div>\n\n    <div>\n      <button type=\"button\" @click=\"setOnly\">Set Only (users)</button>\n      <button type=\"button\" @click=\"setExcept\">Set Except (stats)</button>\n      <button type=\"button\" @click=\"setReset\">Set Reset (orders)</button>\n      <button type=\"button\" @click=\"queryStringArrayFormat = 'brackets'\">Use Brackets Format</button>\n      <button type=\"button\" @click=\"queryStringArrayFormat = 'indices'\">Use Indices Format</button>\n      <button type=\"button\" @click=\"enablePreserveScroll\">Enable Preserve Scroll</button>\n      <button type=\"button\" @click=\"enablePreserveState\">Enable Preserve State</button>\n      <button type=\"button\" @click=\"enablePreserveUrl\">Enable Preserve URL</button>\n      <button type=\"button\" @click=\"enableReplace\">Enable Replace</button>\n      <button type=\"submit\">Submit</button>\n    </div>\n  </Form>\n\n  <Article v-if=\"preserveScroll\" />\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Precognition/BeforeValidation.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\nimport { isEqual } from 'lodash-es'\n\nconst handleBeforeValidation = (\n  newRequest: { data: Record<string, unknown> | null; touched: string[] },\n  oldRequest: { data: Record<string, unknown> | null; touched: string[] },\n) => {\n  const payloadIsCorrect =\n    isEqual(newRequest, { data: { name: 'block' }, touched: ['name'] }) &&\n    isEqual(oldRequest, { data: {}, touched: [] })\n\n  if (payloadIsCorrect && newRequest.data?.name === 'block') {\n    return false\n  }\n\n  return true\n}\n</script>\n\n<template>\n  <div>\n    <h1>Precognition - onBefore</h1>\n\n    <Form\n      action=\"/precognition/default\"\n      method=\"post\"\n      #default=\"{ errors, invalid, validate, validating }\"\n      :validation-timeout=\"100\"\n    >\n      <div>\n        <label for=\"name\">Name:</label>\n        <input\n          id=\"name\"\n          name=\"name\"\n          @change=\"\n            validate('name', {\n              onBeforeValidation: handleBeforeValidation,\n            })\n          \"\n        />\n        <p v-if=\"invalid('name')\" class=\"error\">{{ errors.name }}</p>\n      </div>\n\n      <div>\n        <label for=\"email\">Email:</label>\n        <input id=\"email\" name=\"email\" @change=\"validate('email')\" />\n        <p v-if=\"invalid('email')\" class=\"error\">{{ errors.email }}</p>\n      </div>\n\n      <p v-if=\"validating\" class=\"validating\">Validating...</p>\n\n      <button type=\"submit\">Submit</button>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Precognition/Callbacks.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst successCalled = ref(false)\nconst errorCalled = ref(false)\nconst finishCalled = ref(false)\n</script>\n\n<template>\n  <div>\n    <h1>Form Precognition Callbacks</h1>\n\n    <h2>Callbacks Test</h2>\n    <Form action=\"/precognition/default\" method=\"post\" :validationTimeout=\"100\">\n      <template #default=\"{ validate, validating, touch }\">\n        <div>\n          <input name=\"name\" placeholder=\"Name\" @blur=\"() => touch('name')\" />\n        </div>\n\n        <p v-if=\"validating\">Validating...</p>\n        <p v-if=\"successCalled\">onPrecognitionSuccess called!</p>\n        <p v-if=\"errorCalled\">onValidationError called!</p>\n        <p v-if=\"finishCalled\">onFinish called!</p>\n\n        <button\n          type=\"button\"\n          @click=\"\n            () => {\n              successCalled = false\n              errorCalled = false\n              finishCalled = false\n              validate({\n                onPrecognitionSuccess: () => {\n                  successCalled = true\n                },\n                onValidationError: () => {\n                  errorCalled = true\n                },\n                onFinish: () => {\n                  finishCalled = true\n                },\n              })\n            }\n          \"\n        >\n          Validate\n        </button>\n      </template>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Precognition/Cancel.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <h1>Precognition - Cancel Tests</h1>\n\n    <h2>Auto Cancel Test</h2>\n    <Form\n      action=\"/precognition/default?slow=1\"\n      method=\"post\"\n      :validation-timeout=\"100\"\n      #default=\"{ invalid, errors, validate, validating }\"\n    >\n      <div>\n        <input id=\"auto-cancel-name-input\" name=\"name\" placeholder=\"Name\" @blur=\"validate('name')\" />\n        <p v-if=\"invalid('name')\" class=\"error\">\n          {{ errors.name }}\n        </p>\n      </div>\n\n      <p v-if=\"validating\" class=\"validating\">Validating...</p>\n\n      <button type=\"submit\">Submit</button>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Precognition/Default.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <h1>Form Precognition</h1>\n\n    <Form\n      action=\"/precognition/default\"\n      method=\"post\"\n      :validation-timeout=\"100\"\n      #default=\"{ invalid, errors, validate, valid, validating }\"\n    >\n      <div>\n        <input name=\"name\" placeholder=\"Name\" @blur=\"validate('name')\" />\n        <p v-if=\"invalid('name')\">\n          {{ errors.name }}\n        </p>\n        <p v-if=\"valid('name')\">Name is valid!</p>\n      </div>\n\n      <div>\n        <input name=\"email\" placeholder=\"Email\" @blur=\"validate('email')\" />\n        <p v-if=\"invalid('email')\">\n          {{ errors.email }}\n        </p>\n        <p v-if=\"valid('email')\">Email is valid!</p>\n      </div>\n\n      <p v-if=\"validating\">Validating...</p>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Precognition/DynamicArrayInputs.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst items = ref<Array<{ name: string }>>([])\n\nfunction addItem() {\n  items.value.push({ name: '' })\n}\n</script>\n\n<template>\n  <div>\n    <button id=\"add-item\" @click=\"addItem\">Add Item</button>\n\n    <Form\n      action=\"/precognition/dynamic-array-inputs\"\n      method=\"post\"\n      :validation-timeout=\"100\"\n      #default=\"{ invalid, errors, validate, validating }\"\n    >\n      <div v-for=\"(item, idx) in items\" :key=\"idx\">\n        <input v-model=\"item.name\" :name=\"`items.${idx}.name`\" @blur=\"validate(`items.${idx}.name`)\" />\n        <p v-if=\"invalid(`items.${idx}.name`)\" :id=\"`items.${idx}.name-error`\">{{ errors[`items.${idx}.name`] }}</p>\n      </div>\n\n      <p v-if=\"validating\">Validating...</p>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Precognition/ErrorSync.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <h1>Precognition Error Sync Test</h1>\n\n    <Form\n      action=\"/precognition/error-sync\"\n      method=\"post\"\n      :validation-timeout=\"100\"\n      #default=\"{ invalid, errors, validate, validating }\"\n    >\n      <div>\n        <input name=\"name\" placeholder=\"Name\" @blur=\"validate('name')\" />\n        <p v-if=\"invalid('name')\" id=\"name-error\">\n          {{ errors.name }}\n        </p>\n      </div>\n\n      <div>\n        <input name=\"email\" placeholder=\"Email\" @blur=\"validate('email')\" />\n        <p v-if=\"invalid('email')\" id=\"email-error\">\n          {{ errors.email }}\n        </p>\n      </div>\n\n      <p v-if=\"validating\" id=\"validating\">Validating...</p>\n\n      <button type=\"submit\" id=\"submit-btn\">Submit</button>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Precognition/Files.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst validateFilesEnabled = ref(false)\n</script>\n\n<template>\n  <div>\n    <h1>Form Precognition Files</h1>\n\n    <Form\n      action=\"/precognition/files\"\n      method=\"post\"\n      :validation-timeout=\"100\"\n      :validate-files=\"validateFilesEnabled\"\n      #default=\"{ invalid, errors, validate, valid, validating }\"\n    >\n      <div>\n        <input name=\"name\" placeholder=\"Name\" @blur=\"validate('name')\" />\n        <p v-if=\"invalid('name')\">\n          {{ errors.name }}\n        </p>\n        <p v-if=\"valid('name')\">Name is valid!</p>\n      </div>\n\n      <div>\n        <input type=\"file\" name=\"avatar\" id=\"avatar\" />\n        <p v-if=\"invalid('avatar')\">\n          {{ errors.avatar }}\n        </p>\n        <p v-if=\"valid('avatar')\">Avatar is valid!</p>\n      </div>\n\n      <p v-if=\"validating\">Validating...</p>\n\n      <button type=\"button\" @click=\"validateFilesEnabled = !validateFilesEnabled\">\n        Toggle Validate Files ({{ validateFilesEnabled ? 'enabled' : 'disabled' }})\n      </button>\n\n      <button type=\"button\" @click=\"validate({ only: ['name', 'avatar'] })\">Validate Both</button>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Precognition/Headers.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <h1>Precognition - Custom Headers</h1>\n\n    <Form\n      action=\"/precognition/headers\"\n      method=\"post\"\n      :headers=\"{ 'X-Custom-Header': 'custom-value' }\"\n      :validation-timeout=\"100\"\n      #default=\"{ invalid, errors, validate, validating }\"\n    >\n      <div>\n        <input name=\"name\" placeholder=\"Name\" @blur=\"validate('name')\" />\n        <p v-if=\"invalid('name')\">\n          {{ errors.name }}\n        </p>\n      </div>\n\n      <p v-if=\"validating\">Validating...</p>\n\n      <button type=\"submit\">Submit</button>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Precognition/Methods.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <h1>Form Precognition - Touch, Reset & Validate</h1>\n\n    <Form\n      action=\"/precognition/default\"\n      method=\"post\"\n      :validation-timeout=\"100\"\n      #default=\"{ invalid, errors, validate, touch, touched, validating, reset }\"\n    >\n      <div>\n        <input name=\"name\" placeholder=\"Name\" @blur=\"touch('name')\" />\n        <p v-if=\"invalid('name')\">\n          {{ errors.name }}\n        </p>\n      </div>\n\n      <div>\n        <input name=\"email\" placeholder=\"Email\" @blur=\"touch('email')\" />\n        <p v-if=\"invalid('email')\">\n          {{ errors.email }}\n        </p>\n      </div>\n\n      <p v-if=\"validating\">Validating...</p>\n\n      <p id=\"name-touched\">{{ touched('name') ? 'Name is touched' : 'Name is not touched' }}</p>\n      <p id=\"email-touched\">{{ touched('email') ? 'Email is touched' : 'Email is not touched' }}</p>\n      <p id=\"any-touched\">{{ touched() ? 'Form has touched fields' : 'Form has no touched fields' }}</p>\n\n      <button type=\"button\" @click=\"validate()\">Validate All Touched</button>\n      <button type=\"button\" @click=\"validate('name')\">Validate Name</button>\n      <button type=\"button\" @click=\"validate({ only: ['name', 'email'] })\">Validate Name and Email</button>\n      <button type=\"button\" @click=\"touch('name', 'email')\">Touch Name and Email</button>\n      <button\n        type=\"button\"\n        @click=\"\n          () => {\n            touch('name')\n            touch('name')\n          }\n        \"\n      >\n        Touch Name Twice\n      </button>\n      <button type=\"button\" @click=\"reset()\">Reset All</button>\n      <button type=\"button\" @click=\"reset('name')\">Reset Name</button>\n      <button type=\"button\" @click=\"reset('name', 'email')\">Reset Name and Email</button>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Precognition/Transform.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <h1>Form Precognition Transform</h1>\n\n    <Form\n      action=\"/precognition/default\"\n      method=\"post\"\n      :validationTimeout=\"100\"\n      :transform=\"(data) => ({ name: String(data.name || '').repeat(2) })\"\n    >\n      <template #default=\"{ invalid, errors, validate, valid, validating }\">\n        <div>\n          <input name=\"name\" placeholder=\"Name\" @blur=\"() => validate('name')\" />\n          <p v-if=\"invalid('name')\">{{ errors.name }}</p>\n          <p v-if=\"valid('name')\">Name is valid!</p>\n        </div>\n\n        <p v-if=\"validating\">Validating...</p>\n      </template>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Precognition/TransformKeys.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst transformData = (data: Record<string, any>) => {\n  const document = data.document || {}\n  return document\n}\n</script>\n\n<template>\n  <div>\n    <h1>Form Precognition Transform Keys</h1>\n\n    <Form action=\"/precognition/transform-keys\" method=\"post\" :validationTimeout=\"100\" :transform=\"transformData\">\n      <template #default=\"{ invalid, errors, validate, valid, validating }\">\n        <div>\n          <input\n            id=\"email-input\"\n            name=\"document[customer][email]\"\n            placeholder=\"Email\"\n            @blur=\"() => validate('customer.email')\"\n          />\n          <p v-if=\"invalid('customer.email')\">{{ errors['customer.email'] }}</p>\n          <p v-if=\"valid('customer.email')\">Email is valid!</p>\n        </div>\n\n        <p v-if=\"validating\">Validating...</p>\n      </template>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Precognition/WithAllErrors.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <h1>Form Precognition - All Errors</h1>\n\n    <Form\n      action=\"/precognition/with-all-errors\"\n      method=\"post\"\n      :validation-timeout=\"100\"\n      with-all-errors\n      #default=\"{ invalid, errors, validate, valid, validating }\"\n    >\n      <div>\n        <input name=\"name\" placeholder=\"Name\" @blur=\"validate('name')\" />\n        <div v-if=\"invalid('name')\">\n          <template v-if=\"Array.isArray(errors.name)\">\n            <p v-for=\"(error, index) in errors.name\" :key=\"index\" :id=\"`name-error-${index}`\">\n              {{ error }}\n            </p>\n          </template>\n          <p v-else id=\"name-error-0\">{{ errors.name }}</p>\n        </div>\n        <p v-if=\"valid('name')\">Name is valid!</p>\n      </div>\n\n      <div>\n        <input name=\"email\" placeholder=\"Email\" @blur=\"validate('email')\" />\n        <div v-if=\"invalid('email')\">\n          <template v-if=\"Array.isArray(errors.email)\">\n            <p v-for=\"(error, index) in errors.email\" :key=\"index\" :id=\"`email-error-${index}`\">\n              {{ error }}\n            </p>\n          </template>\n          <p v-else id=\"email-error-0\">{{ errors.email }}</p>\n        </div>\n        <p v-if=\"valid('email')\">Email is valid!</p>\n      </div>\n\n      <p v-if=\"validating\">Validating...</p>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Precognition/WithAllErrorsConfig.vue",
    "content": "<script setup lang=\"ts\">\nimport { config, Form } from '@inertiajs/vue3'\n\n// Set global config for withAllErrors (no prop on the Form component)\nconfig.set('form.withAllErrors', true)\n</script>\n\n<template>\n  <div>\n    <h1>Form Precognition - All Errors via Config</h1>\n\n    <Form\n      action=\"/precognition/with-all-errors\"\n      method=\"post\"\n      :validation-timeout=\"100\"\n      #default=\"{ invalid, errors, validate, valid, validating }\"\n    >\n      <div>\n        <input name=\"name\" placeholder=\"Name\" @blur=\"validate('name')\" />\n        <div v-if=\"invalid('name')\">\n          <template v-if=\"Array.isArray(errors.name)\">\n            <p v-for=\"(error, index) in errors.name\" :key=\"index\" :id=\"`name-error-${index}`\">\n              {{ error }}\n            </p>\n          </template>\n          <p v-else id=\"name-error-0\">{{ errors.name }}</p>\n        </div>\n        <p v-if=\"valid('name')\">Name is valid!</p>\n      </div>\n\n      <div>\n        <input name=\"email\" placeholder=\"Email\" @blur=\"validate('email')\" />\n        <div v-if=\"invalid('email')\">\n          <template v-if=\"Array.isArray(errors.email)\">\n            <p v-for=\"(error, index) in errors.email\" :key=\"index\" :id=\"`email-error-${index}`\">\n              {{ error }}\n            </p>\n          </template>\n          <p v-else id=\"email-error-0\">{{ errors.email }}</p>\n        </div>\n        <p v-if=\"valid('email')\">Email is valid!</p>\n      </div>\n\n      <p v-if=\"validating\">Validating...</p>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Precognition/WithoutAllErrors.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <h1>Form Precognition - Array Errors</h1>\n\n    <Form\n      action=\"/precognition/with-all-errors\"\n      method=\"post\"\n      :validation-timeout=\"100\"\n      #default=\"{ invalid, errors, validate, valid, validating }\"\n    >\n      <div>\n        <input name=\"name\" placeholder=\"Name\" @blur=\"validate('name')\" />\n        <p v-if=\"invalid('name')\">\n          {{ errors.name }}\n        </p>\n        <p v-if=\"valid('name')\">Name is valid!</p>\n      </div>\n\n      <div>\n        <input name=\"email\" placeholder=\"Email\" @blur=\"validate('email')\" />\n        <p v-if=\"invalid('email')\">\n          {{ errors.email }}\n        </p>\n        <p v-if=\"valid('email')\">Email is valid!</p>\n      </div>\n\n      <p v-if=\"validating\">Validating...</p>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Progress.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\nimport { onMounted, onUnmounted, ref } from 'vue'\n\nconst showProgress = ref<boolean | undefined>(undefined)\n\nconst nprogressVisible = ref(false)\nconst nprogressApperances = ref(0)\n\nfunction disableProgress() {\n  showProgress.value = false\n}\n\nonMounted(() => {\n  const observer = new MutationObserver(() => {\n    const nprogressElement = document.querySelector('#nprogress') as HTMLElement | null\n    const nprogressIsVisible = nprogressElement && nprogressElement.style.display !== 'none'\n\n    if (nprogressIsVisible) {\n      if (!nprogressVisible.value) {\n        nprogressVisible.value = true\n        nprogressApperances.value++\n      }\n    } else {\n      nprogressVisible.value = false\n    }\n  })\n\n  observer.observe(document.body, { childList: true, subtree: true })\n\n  onUnmounted(() => {\n    observer.disconnect()\n  })\n})\n</script>\n\n<template>\n  <Form action=\"/form-component/progress\" method=\"post\" :show-progress=\"showProgress\">\n    <h1>Progress</h1>\n\n    <div>\n      Nprogress appearances: <span id=\"nprogress-appearances\">{{ nprogressApperances }}</span>\n    </div>\n\n    <div>\n      <button type=\"button\" @click=\"disableProgress\">Disable Progress</button>\n      <button type=\"submit\">Submit</button>\n    </div>\n  </Form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Ref.vue",
    "content": "<script setup lang=\"ts\">\nimport { FormComponentRef } from '@inertiajs/core'\nimport { Form } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst formRef = ref<FormComponentRef | null>(null)\n\nconst submitProgrammatically = () => {\n  formRef.value?.submit()\n}\n\nconst resetForm = () => {\n  formRef.value?.reset()\n}\n\nconst resetNameField = () => {\n  formRef.value?.reset('name')\n}\n\nconst clearAllErrors = () => {\n  formRef.value?.clearErrors()\n}\n\nconst setTestError = () => {\n  formRef.value?.setError('name', 'This is a test error')\n}\n\nconst setCurrentAsDefaults = () => {\n  formRef.value?.defaults()\n}\n\nconst callPrecognitionMethods = () => {\n  const validator = formRef.value?.validator()\n\n  if (validator && !formRef.value?.touched('company') && !formRef.value?.valid('company')) {\n    formRef.value?.validate({ only: ['company'] })\n  }\n}\n</script>\n\n<template>\n  <div>\n    <h1>Form Ref Test</h1>\n\n    <Form ref=\"formRef\" action=\"/dump/post\" method=\"post\" #default=\"{ isDirty, hasErrors, errors }\">\n      <!-- State display for testing -->\n      <div>Form is <span v-if=\"isDirty\">dirty</span><span v-else>clean</span></div>\n      <div v-if=\"hasErrors\">Form has errors</div>\n      <div v-if=\"errors.name\" id=\"error_name\">{{ errors.name }}</div>\n\n      <div>\n        <input type=\"text\" name=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n      </div>\n\n      <div>\n        <input type=\"email\" name=\"email\" placeholder=\"Email\" value=\"john@example.com\" />\n      </div>\n\n      <div>\n        <button type=\"submit\">Submit via Form</button>\n      </div>\n    </Form>\n\n    <div>\n      <button @click=\"submitProgrammatically\">Submit Programmatically</button>\n      <button @click=\"resetForm\">Reset Form</button>\n      <button @click=\"resetNameField\">Reset Name Field</button>\n      <button @click=\"clearAllErrors\">Clear Errors</button>\n      <button @click=\"setTestError\">Set Test Error</button>\n      <button @click=\"setCurrentAsDefaults\">Set Current as Defaults</button>\n      <button @click=\"callPrecognitionMethods\">Call Precognition Methods</button>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Reset.vue",
    "content": "<script setup lang=\"ts\">\nimport { FormComponentRef } from '@inertiajs/core'\nimport { Form } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst formRef = ref<FormComponentRef | null>(null)\n\ndeclare global {\n  interface Window {\n    resetForm: (...fields: string[]) => void\n  }\n}\n\n// Expose reset function to window for testing\nwindow.resetForm = (...fields: string[]) => {\n  formRef.value?.reset(...fields)\n}\n</script>\n\n<template>\n  <Form action=\"/dump/post\" method=\"post\" ref=\"formRef\">\n    <h1>Form Reset</h1>\n\n    <!-- Basic Text Inputs -->\n    <h2>Basic Text Inputs</h2>\n    <input type=\"text\" name=\"name\" id=\"name\" value=\"John Doe\" />\n    <input type=\"email\" name=\"email\" id=\"email\" value=\"john@example.com\" />\n\n    <!-- Select Elements -->\n    <h2>Select Elements</h2>\n    <select name=\"country\" id=\"country\">\n      <option value=\"us\">United States</option>\n      <option value=\"ca\">Canada</option>\n      <option value=\"uk\" selected>United Kingdom</option>\n    </select>\n    <select name=\"role\" id=\"role\">\n      <option value=\"\">Select a role</option>\n      <option value=\"user\">User</option>\n      <option value=\"admin\">Admin</option>\n      <option value=\"super\">Super</option>\n    </select>\n\n    <!-- Radio Buttons -->\n    <h2>Radio Buttons</h2>\n\n    <!-- Radio buttons with default checked -->\n    <div>\n      <label><input type=\"radio\" name=\"plan\" id=\"plan_free\" value=\"free\" /> Free</label>\n      <label><input type=\"radio\" name=\"plan\" id=\"plan_pro\" value=\"pro\" checked /> Pro</label>\n      <label><input type=\"radio\" name=\"plan\" id=\"plan_enterprise\" value=\"enterprise\" /> Enterprise</label>\n    </div>\n\n    <!-- Radio buttons without default -->\n    <div>\n      <label><input type=\"radio\" name=\"payment\" id=\"payment_card\" value=\"card\" /> Card</label>\n      <label><input type=\"radio\" name=\"payment\" id=\"payment_bank\" value=\"bank\" /> Bank</label>\n      <label><input type=\"radio\" name=\"payment\" id=\"payment_paypal\" value=\"paypal\" /> PayPal</label>\n    </div>\n\n    <!-- Radio buttons designed to test multiple defaults edge case -->\n    <div>\n      <label><input type=\"radio\" name=\"priority\" id=\"priority_low\" value=\"low\" checked /> Low</label>\n      <label><input type=\"radio\" name=\"priority\" id=\"priority_medium\" value=\"medium\" /> Medium</label>\n      <label><input type=\"radio\" name=\"priority\" id=\"priority_high\" value=\"high\" /> High</label>\n    </div>\n\n    <!-- Checkboxes -->\n    <h2>Checkboxes</h2>\n\n    <!-- Checkbox (single) with default checked -->\n    <div>\n      <input type=\"checkbox\" name=\"subscribe\" id=\"subscribe\" value=\"yes\" checked />\n      <label for=\"subscribe\">Subscribe to newsletter</label>\n    </div>\n\n    <!-- Checkbox (single) without default -->\n    <div>\n      <input type=\"checkbox\" name=\"terms\" id=\"terms\" value=\"accepted\" />\n      <label for=\"terms\">Accept terms</label>\n    </div>\n\n    <!-- Checkbox (multiple) with some checked -->\n    <div>\n      <label><input type=\"checkbox\" name=\"interests[]\" id=\"interests_sports\" value=\"sports\" checked /> Sports</label>\n      <label><input type=\"checkbox\" name=\"interests[]\" id=\"interests_music\" value=\"music\" /> Music</label>\n      <label><input type=\"checkbox\" name=\"interests[]\" id=\"interests_tech\" value=\"tech\" checked /> Tech</label>\n      <label><input type=\"checkbox\" name=\"interests[]\" id=\"interests_art\" value=\"art\" /> Art</label>\n    </div>\n\n    <!-- Multiple Select Elements -->\n    <h2>Multiple Select Elements</h2>\n    <select name=\"skills[]\" id=\"skills\" multiple>\n      <option value=\"vue\" selected>Vue</option>\n      <option value=\"react\">React</option>\n      <option value=\"angular\" selected>Angular</option>\n      <option value=\"svelte\">Svelte</option>\n    </select>\n    <select name=\"languages[]\" id=\"languages\" multiple>\n      <option value=\"javascript\">JavaScript</option>\n      <option value=\"typescript\">TypeScript</option>\n      <option value=\"python\">Python</option>\n      <option value=\"php\">PHP</option>\n    </select>\n    <select name=\"tools[]\" id=\"tools\" multiple>\n      <option value=\"vscode\" selected>VSCode</option>\n      <option value=\"webstorm\" selected>WebStorm</option>\n      <option value=\"sublime\" selected>Sublime</option>\n    </select>\n    <select name=\"editor\" id=\"editor\">\n      <option value=\"\">Select Editor</option>\n      <option value=\"vim\" selected>Vim</option>\n      <option value=\"emacs\">Emacs</option>\n      <option value=\"nano\">Nano</option>\n    </select>\n\n    <!-- File Inputs & Textareas -->\n    <h2>File Inputs & Textareas</h2>\n    <input type=\"file\" name=\"avatar\" id=\"avatar\" />\n    <input type=\"file\" name=\"documents[]\" id=\"documents\" multiple />\n    <textarea name=\"bio\" id=\"bio\" rows=\"3\">Default bio text here.</textarea>\n    <textarea name=\"notes\" id=\"notes\" rows=\"2\"></textarea>\n\n    <!-- HTML5 Input Types -->\n    <h2>HTML5 Input Types</h2>\n    <input type=\"hidden\" name=\"token\" id=\"token\" value=\"abc123\" />\n    <input type=\"number\" name=\"age\" id=\"age\" value=\"25\" />\n    <input type=\"number\" name=\"quantity\" id=\"quantity\" />\n    <input type=\"range\" name=\"volume\" id=\"volume\" min=\"0\" max=\"100\" value=\"50\" />\n    <input type=\"date\" name=\"birthdate\" id=\"birthdate\" value=\"1990-01-01\" />\n    <input type=\"time\" name=\"appointment\" id=\"appointment\" value=\"14:30\" />\n    <input type=\"color\" name=\"favorite_color\" id=\"favorite_color\" value=\"#ff0000\" />\n    <input type=\"url\" name=\"website\" id=\"website\" value=\"https://example.com\" />\n    <input type=\"tel\" name=\"phone\" id=\"phone\" value=\"+1234567890\" />\n    <input type=\"password\" name=\"password\" id=\"password\" value=\"secret123\" />\n\n    <!-- Complex Nested Fields -->\n    <h2>Complex Nested Fields</h2>\n    <input type=\"text\" name=\"user[address][street]\" id=\"nested_street\" value=\"123 Main St\" />\n    <input type=\"text\" name=\"user[address][city]\" id=\"nested_city\" value=\"New York\" />\n    <input type=\"text\" name=\"items[0][name]\" id=\"item_0_name\" value=\"Item A\" />\n    <input type=\"number\" name=\"items[0][quantity]\" id=\"item_0_quantity\" value=\"5\" />\n    <input type=\"text\" name=\"items[1][name]\" id=\"item_1_name\" value=\"Item B\" />\n    <input type=\"number\" name=\"items[1][quantity]\" id=\"item_1_quantity\" value=\"10\" />\n\n    <!-- Special Cases -->\n    <h2>Special Cases</h2>\n    <input type=\"text\" name=\"disabled_field\" id=\"disabled_field\" value=\"Ignore me\" disabled />\n    <input type=\"button\" name=\"button_input\" value=\"Click me\" />\n    <input type=\"submit\" name=\"submit_input\" value=\"Submit Form\" />\n    <input type=\"reset\" name=\"reset_input\" value=\"Reset Form\" />\n    <button type=\"reset\" name=\"reset_button\">Reset Form</button>\n\n    <!-- Dotted & Array Notation -->\n    <h2>Dotted & Array Notation</h2>\n    <input type=\"text\" name=\"user.name\" id=\"user_name\" value=\"Default User\" />\n    <input type=\"text\" name=\"user.email\" id=\"user_email\" value=\"user@default.com\" />\n    <input type=\"text\" name=\"company.name\" id=\"company_name\" value=\"Default Corp\" />\n    <input type=\"text\" name=\"tags[]\" id=\"tag_0\" value=\"javascript\" />\n    <input type=\"text\" name=\"tags[]\" id=\"tag_1\" value=\"vue\" />\n    <input type=\"text\" name=\"tags[]\" id=\"tag_2\" value=\"inertia\" />\n\n    <!-- Numeric Values -->\n    <h2>Numeric Values</h2>\n    <div>\n      <label><input type=\"radio\" name=\"rating\" id=\"rating_1\" value=\"1\" checked /> 1 Star</label>\n      <label><input type=\"radio\" name=\"rating\" id=\"rating_2\" value=\"2\" /> 2 Stars</label>\n      <label><input type=\"radio\" name=\"rating\" id=\"rating_3\" value=\"3\" /> 3 Stars</label>\n    </div>\n    <div>\n      <label><input type=\"checkbox\" name=\"years[]\" id=\"years_2020\" value=\"2020\" checked /> 2020</label>\n      <label><input type=\"checkbox\" name=\"years[]\" id=\"years_2021\" value=\"2021\" /> 2021</label>\n      <label><input type=\"checkbox\" name=\"years[]\" id=\"years_2022\" value=\"2022\" checked /> 2022</label>\n    </div>\n    <select name=\"version\" id=\"version\">\n      <option value=\"1\" selected>Version 1</option>\n      <option value=\"2\">Version 2</option>\n      <option value=\"3\">Version 3</option>\n    </select>\n    <select name=\"ports[]\" id=\"ports\" multiple>\n      <option value=\"80\" selected>Port 80</option>\n      <option value=\"443\" selected>Port 443</option>\n      <option value=\"8080\">Port 8080</option>\n    </select>\n\n    <!-- Submit button -->\n    <h2>Submit</h2>\n    <button type=\"submit\">Submit</button>\n  </Form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/ResetAttributes/ResetOnError.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <Form method=\"post\" action=\"/form-component/reset-on-error\" reset-on-error>\n    <div>\n      <label for=\"name\">Name</label>\n      <input type=\"text\" name=\"name\" id=\"name\" value=\"John Doe\" />\n      <p id=\"error_name\">{{ $page.props.errors?.name }}</p>\n    </div>\n\n    <div>\n      <label for=\"email\">Email</label>\n      <input type=\"email\" name=\"email\" id=\"email\" value=\"john@doe.biz\" />\n      <p id=\"error_email\">{{ $page.props.errors?.email }}</p>\n    </div>\n\n    <button type=\"submit\">Submit</button>\n  </Form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/ResetAttributes/ResetOnErrorFields.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <Form method=\"post\" action=\"/form-component/reset-on-error-fields\" :reset-on-error=\"['name']\">\n    <div>\n      <label for=\"name\">Name</label>\n      <input type=\"text\" name=\"name\" id=\"name\" value=\"John Doe\" />\n      <p id=\"error_name\">{{ $page.props.errors?.name }}</p>\n    </div>\n\n    <div>\n      <label for=\"email\">Email</label>\n      <input type=\"email\" name=\"email\" id=\"email\" value=\"john@doe.biz\" />\n      <p id=\"error_email\">{{ $page.props.errors?.email }}</p>\n    </div>\n\n    <button type=\"submit\">Submit</button>\n  </Form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccess.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <Form method=\"post\" action=\"/form-component/reset-on-success\" reset-on-success>\n    <div>\n      <label for=\"name\">Name</label>\n      <input type=\"text\" name=\"name\" id=\"name\" value=\"John Doe\" />\n      <p id=\"error_name\">{{ $page.props.errors?.name }}</p>\n    </div>\n\n    <div>\n      <label for=\"email\">Email</label>\n      <input type=\"email\" name=\"email\" id=\"email\" value=\"john@doe.biz\" />\n      <p id=\"error_email\">{{ $page.props.errors?.email }}</p>\n    </div>\n\n    <button type=\"submit\">Submit</button>\n  </Form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccessFields.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <Form method=\"post\" action=\"/form-component/reset-on-success-fields\" :reset-on-success=\"['name']\">\n    <div>\n      <label for=\"name\">Name</label>\n      <input type=\"text\" name=\"name\" id=\"name\" value=\"John Doe\" />\n      <p id=\"error_name\">{{ $page.props.errors?.name }}</p>\n    </div>\n\n    <div>\n      <label for=\"email\">Email</label>\n      <input type=\"email\" name=\"email\" id=\"email\" value=\"john@doe.biz\" />\n      <p id=\"error_email\">{{ $page.props.errors?.email }}</p>\n    </div>\n\n    <button type=\"submit\">Submit</button>\n  </Form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/SetDefaultsOnSuccess.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <Form method=\"post\" action=\"/form-component/set-defaults-on-success\" set-defaults-on-success>\n    <template #default=\"{ isDirty }\">\n      <p id=\"dirty-status\">{{ isDirty ? 'Form is dirty' : 'Form is clean' }}</p>\n\n      <div>\n        <label for=\"name\">Name</label>\n        <input type=\"text\" name=\"name\" id=\"name\" value=\"John Doe\" />\n        <p id=\"error_name\">{{ $page.props.errors?.name }}</p>\n      </div>\n\n      <div>\n        <label for=\"email\">Email</label>\n        <input type=\"email\" name=\"email\" id=\"email\" value=\"john@doe.biz\" />\n        <p id=\"error_email\">{{ $page.props.errors?.email }}</p>\n      </div>\n\n      <button type=\"submit\">Submit</button>\n    </template>\n  </Form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/SubmitButton.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <Form action=\"/dump/post\" method=\"post\">\n    <h1>Submit Button Test</h1>\n\n    <input type=\"text\" name=\"name\" id=\"name\" value=\"John Doe\" />\n\n    <button type=\"submit\" name=\"action\" value=\"save\" id=\"save-button\">Save</button>\n    <button type=\"submit\" name=\"action\" value=\"draft\" id=\"draft-button\">Save as Draft</button>\n    <button type=\"submit\" id=\"no-name-button\">Submit Without Name</button>\n  </Form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/SubmitComplete/Defaults.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <h1>OnSubmitComplete Defaults Test</h1>\n\n    <Form method=\"post\" #default=\"{ errors, isDirty }\" @submit-complete=\"(props) => props.defaults()\">\n      <div>\n        <p id=\"dirty-status\">{{ isDirty ? 'Form is dirty' : 'Form is clean' }}</p>\n      </div>\n\n      <div>\n        <input type=\"text\" name=\"name\" id=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n        <p v-if=\"errors.name\" id=\"error_name\">{{ errors.name }}</p>\n      </div>\n\n      <div>\n        <input type=\"email\" name=\"email\" id=\"email\" placeholder=\"Email\" value=\"john@doe.biz\" />\n        <p v-if=\"errors.email\" id=\"error_email\">{{ errors.email }}</p>\n      </div>\n\n      <div>\n        <button type=\"submit\">Submit</button>\n      </div>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/SubmitComplete/Redirect.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <h1>Form Redirect Test</h1>\n\n    <Form method=\"post\" #default=\"{ errors }\" @submit-complete=\"(form) => form.reset('name')\">\n      <div>\n        <input type=\"text\" name=\"name\" id=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n        <p v-if=\"errors.name\" id=\"error_name\">{{ errors.name }}</p>\n      </div>\n\n      <div>\n        <button type=\"submit\">Submit</button>\n      </div>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/SubmitComplete/Reset.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <h1>OnSubmitComplete Reset Test</h1>\n\n    <Form method=\"post\" #default=\"{ errors }\" @submit-complete=\"(props) => props.reset('name')\">\n      <div>\n        <input type=\"text\" name=\"name\" id=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n        <p v-if=\"errors.name\" id=\"error_name\">{{ errors.name }}</p>\n      </div>\n\n      <div>\n        <input type=\"email\" name=\"email\" id=\"email\" placeholder=\"Email\" value=\"john@doe.biz\" />\n        <p v-if=\"errors.email\" id=\"error_email\">{{ errors.email }}</p>\n      </div>\n\n      <div>\n        <button type=\"submit\">Submit</button>\n      </div>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Transform.vue",
    "content": "<script setup lang=\"ts\">\nimport type { FormDataConvertible } from '@inertiajs/core'\nimport { Form } from '@inertiajs/vue3'\nimport { computed, ref } from 'vue'\n\nconst transformType = ref('none')\n\nconst transformFunction = computed(() => {\n  switch (transformType.value) {\n    case 'uppercase':\n      return (data: Record<string, FormDataConvertible>) => ({\n        ...data,\n        name: typeof data.name === 'string' ? data.name.toUpperCase() : data.name,\n      })\n    case 'format':\n      return (data: Record<string, FormDataConvertible>) => ({\n        ...data,\n        fullName: `${data.firstName} ${data.lastName}`,\n      })\n    default:\n      return (data: Record<string, FormDataConvertible>) => data\n  }\n})\n</script>\n\n<template>\n  <div>\n    <h1>Transform Function</h1>\n\n    <div>\n      <button @click=\"transformType = 'none'\">None</button>\n      <button @click=\"transformType = 'uppercase'\">Uppercase</button>\n      <button @click=\"transformType = 'format'\">Format</button>\n    </div>\n\n    <div>Current transform: {{ transformType }}</div>\n\n    <Form action=\"/dump/post\" method=\"post\" :transform=\"transformFunction\">\n      <div>\n        <input type=\"text\" name=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n      </div>\n\n      <div>\n        <input type=\"text\" name=\"firstName\" placeholder=\"First Name\" value=\"John\" />\n      </div>\n\n      <div>\n        <input type=\"text\" name=\"lastName\" placeholder=\"Last Name\" value=\"Doe\" />\n      </div>\n\n      <div>\n        <button type=\"submit\">Submit with Transform</button>\n      </div>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/UppercaseMethod.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <h1>Uppercase Method Test</h1>\n\n    <!-- Test with uppercase POST -->\n    <Form action=\"/dump/post\" method=\"POST\">\n      <div>\n        <input type=\"text\" name=\"name\" placeholder=\"Name\" value=\"Test POST\" />\n      </div>\n      <button type=\"submit\">Submit POST</button>\n    </Form>\n\n    <!-- Test with uppercase GET -->\n    <Form action=\"/dump/get\" method=\"GET\">\n      <div>\n        <input type=\"text\" name=\"query\" placeholder=\"Query\" value=\"Test GET\" />\n      </div>\n      <button type=\"submit\">Submit GET</button>\n    </Form>\n\n    <!-- Test with uppercase PUT -->\n    <Form action=\"/dump/put\" method=\"PUT\">\n      <div>\n        <input type=\"text\" name=\"data\" placeholder=\"Data\" value=\"Test PUT\" />\n      </div>\n      <button type=\"submit\">Submit PUT</button>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/ViewTransition.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <Form\n    action=\"/form-component/view-transition\"\n    method=\"post\"\n    :options=\"{\n      viewTransition: (viewTransition: ViewTransition) => {\n        viewTransition.ready.then(() => console.log('ready'))\n        viewTransition.updateCallbackDone.then(() => console.log('updateCallbackDone'))\n        viewTransition.finished.then(() => console.log('finished'))\n      },\n    }\"\n  >\n    <button type=\"submit\">Submit with View Transition</button>\n  </Form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormComponent/Wayfinder.vue",
    "content": "<script setup lang=\"ts\">\nimport { Form } from '@inertiajs/vue3'\n\nconst wayfinderUrl = (): {\n  url: string\n  method: 'post'\n} => ({\n  url: '/dump/post',\n  method: 'post',\n})\n</script>\n\n<template>\n  <div>\n    <h1>Wayfinder Example</h1>\n\n    <Form :action=\"wayfinderUrl()\">\n      <div>\n        <input type=\"text\" name=\"name\" placeholder=\"Name\" value=\"John Doe\" />\n      </div>\n\n      <div>\n        <input type=\"checkbox\" name=\"active\" value=\"true\" checked />\n        <label>Active</label>\n      </div>\n\n      <div>\n        <button type=\"submit\">Submit</button>\n      </div>\n    </Form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Data.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm, usePage } from '@inertiajs/vue3'\n\nconst form = useForm({\n  name: 'foo',\n  handle: 'example',\n  remember: false as boolean,\n})\n\nconst page = usePage()\n\nconst submit = () => {\n  form.post(page.url)\n}\n\nconst submitAndReset = () => {\n  form.post('/form-helper/data/redirect-back', {\n    onSuccess: () => form.reset(),\n  })\n}\n\nconst resetAll = () => {\n  form.reset()\n}\n\nconst resetOne = () => {\n  form.reset('handle')\n}\n\nconst reassign = () => {\n  form.defaults()\n}\n\nconst reassignObject = () => {\n  form.defaults({\n    handle: 'updated handle',\n    remember: true,\n  })\n}\n\nconst reassignSingle = () => {\n  form.defaults('name', 'single value')\n}\n</script>\n\n<template>\n  <div>\n    <label>\n      Full Name\n      <input type=\"text\" id=\"name\" name=\"name\" v-model=\"form.name\" />\n    </label>\n    <span class=\"name_error\" v-if=\"form.errors.name\">{{ form.errors.name }}</span>\n    <label>\n      Handle\n      <input type=\"text\" id=\"handle\" name=\"handle\" v-model=\"form.handle\" />\n    </label>\n    <span class=\"handle_error\" v-if=\"form.errors.handle\">{{ form.errors.handle }}</span>\n    <label>\n      Remember Me\n      <input type=\"checkbox\" id=\"remember\" name=\"remember\" v-model=\"form.remember\" />\n    </label>\n    <span class=\"remember_error\" v-if=\"form.errors.remember\">{{ form.errors.remember }}</span>\n\n    <button @click=\"submit\" class=\"submit\">Submit form</button>\n    <button @click=\"submitAndReset\" class=\"submit\">Submit form and reset</button>\n\n    <button @click=\"resetAll\" class=\"reset\">Reset all data</button>\n    <button @click=\"resetOne\" class=\"reset-one\">Reset one field</button>\n\n    <button @click=\"reassign\" class=\"reassign\">Reassign current as defaults</button>\n    <button @click=\"reassignObject\" class=\"reassign-object\">Reassign default values</button>\n    <button @click=\"reassignSingle\" class=\"reassign-single\">Reassign single default</button>\n\n    <span class=\"errors-status\">Form has {{ form.hasErrors ? '' : 'no ' }}errors</span>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Dirty.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\nconst form = useForm({ name: 'foo', foo: [] as string[] })\n\nconst submit = () => {\n  form.post('')\n}\n\nconst defaults = () => {\n  form.defaults()\n}\n\nconst dataAndDefaults = () => {\n  pushValue()\n  defaults()\n}\n\nconst pushValue = () => {\n  form.foo.push('bar')\n}\n\nconst submitAndSetDefaults = () => {\n  form.post('/form-helper/dirty/redirect-back', {\n    onSuccess: () => form.defaults(),\n  })\n}\n\nconst submitAndSetCustomDefaults = () => {\n  form.post('/form-helper/dirty/redirect-back', {\n    onSuccess: () => form.defaults({ name: 'Custom Default', foo: [] }),\n  })\n}\n</script>\n\n<template>\n  <div>\n    <div>Form is <span v-if=\"form.isDirty\">dirty</span><span v-else>clean</span></div>\n    <label>\n      Full Name\n      <input type=\"text\" id=\"name\" name=\"name\" v-model=\"form.name\" />\n    </label>\n\n    <button @click=\"submit\" class=\"submit\">Submit form</button>\n\n    <button @click=\"defaults\" class=\"defaults\">Defaults</button>\n\n    <button @click=\"dataAndDefaults\" class=\"data-and-defaults\">Data and Defaults</button>\n\n    <button @click=\"pushValue\" class=\"push\">Push value</button>\n\n    <button @click=\"submitAndSetDefaults\" class=\"submit-and-set-defaults\">Submit and setDefaults</button>\n\n    <button @click=\"submitAndSetCustomDefaults\" class=\"submit-and-set-custom-defaults\">\n      Submit and setDefaults custom\n    </button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/EmptyForm.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\ninterface FormData {\n  name: string\n  email: string\n}\n\nconst form = useForm<FormData>()\n\nconst submit = () => {\n  form.transform(() => ({\n    name: 'John Doe',\n    email: 'john@example.com',\n  }))\n  form.post('/dump/post')\n}\n</script>\n\n<template>\n  <div>\n    <button @click=\"submit\">Submit</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Errors.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\nconst form = useForm({\n  name: 'foo',\n  handle: 'example',\n  remember: false,\n})\n\nconst submit = () => {\n  form.post('/form-helper/errors')\n}\n\nconst clearErrors = () => {\n  form.clearErrors()\n}\n\nconst clearError = () => {\n  form.clearErrors('handle')\n}\n\nconst setErrors = () => {\n  form.setError({\n    name: 'Manually set Name error',\n    handle: 'Manually set Handle error',\n  })\n}\n\nconst setError = () => {\n  form.setError('handle', 'Manually set Handle error')\n}\n\nconst resetAndClearErrors = () => {\n  form.resetAndClearErrors()\n}\n\nconst resetHandle = () => {\n  form.resetAndClearErrors('handle')\n}\n</script>\n\n<template>\n  <div>\n    <label>\n      Full Name\n      <input type=\"text\" id=\"name\" name=\"name\" v-model=\"form.name\" />\n    </label>\n    <span class=\"name_error\" v-if=\"form.errors.name\">{{ form.errors.name }}</span>\n    <label>\n      Handle\n      <input type=\"text\" id=\"handle\" name=\"handle\" v-model=\"form.handle\" />\n    </label>\n    <span class=\"handle_error\" v-if=\"form.errors.handle\">{{ form.errors.handle }}</span>\n    <label>\n      Remember Me\n      <input type=\"checkbox\" id=\"remember\" name=\"remember\" v-model=\"form.remember\" />\n    </label>\n    <span class=\"remember_error\" v-if=\"form.errors.remember\">{{ form.errors.remember }}</span>\n\n    <button @click=\"submit\" class=\"submit\">Submit form</button>\n\n    <button @click=\"clearErrors\" class=\"clear\">Clear all errors</button>\n    <button @click=\"clearError\" class=\"clear-one\">Clear one error</button>\n    <button @click=\"setErrors\" class=\"set\">Set errors</button>\n    <button @click=\"setError\" class=\"set-one\">Set one error</button>\n    <button @click=\"resetAndClearErrors\" class=\"reset-all\">Reset all</button>\n    <button @click=\"resetHandle\" class=\"reset-handle\">Reset handle</button>\n\n    <span class=\"errors-status\">Form has {{ form.hasErrors ? '' : 'no ' }}errors</span>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/ErrorsClearOnResubmit.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\nconst form = useForm({\n  name: '',\n  handle: '',\n})\n\nconst submit = () => {\n  form.post('/form-helper/errors/clear-on-resubmit')\n}\n</script>\n\n<template>\n  <div>\n    <label>\n      Name\n      <input type=\"text\" id=\"name\" name=\"name\" v-model=\"form.name\" />\n    </label>\n    <span id=\"name-error\" v-if=\"form.errors.name\">{{ form.errors.name }}</span>\n\n    <label>\n      Handle\n      <input type=\"text\" id=\"handle\" name=\"handle\" v-model=\"form.handle\" />\n    </label>\n    <span id=\"handle-error\" v-if=\"form.errors.handle\">{{ form.errors.handle }}</span>\n\n    <button @click=\"submit\" id=\"submit\">Submit</button>\n\n    <span class=\"errors-status\">Form has {{ form.hasErrors ? '' : 'no ' }}errors</span>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Events.vue",
    "content": "<script setup lang=\"ts\">\nimport { Errors, Page, PendingVisit, Progress } from '@inertiajs/core'\nimport { useForm, usePage } from '@inertiajs/vue3'\nimport type { CancelTokenSource } from 'axios'\n\ndeclare global {\n  interface Window {\n    events: string[]\n    data: {\n      type: string\n      data: unknown\n      event: string | null\n    }[]\n  }\n}\n\nwindow.events = []\nwindow.data = []\n\nconst form = useForm({\n  name: 'foo',\n  remember: false,\n})\n\nconst pushEvent = (message: string) => {\n  window.events.push(message)\n}\n\nconst pushData = (event: string | null, type: string, data: unknown) => {\n  window.data.push({\n    type,\n    data,\n    event,\n  })\n}\n\npushData(null, 'processing', form.processing)\npushData(null, 'progress', form.progress)\npushData(null, 'errors', form.errors)\n\nconst page = usePage()\n\nconst callbacks = (overrides = {}) => {\n  const defaults = {\n    onBefore: () => pushEvent('onBefore'),\n    onCancelToken: () => pushEvent('onCancelToken'),\n    onStart: () => pushEvent('onStart'),\n    onProgress: () => pushEvent('onProgress'),\n    onFinish: () => pushEvent('onFinish'),\n    onCancel: () => pushEvent('onCancel'),\n    onSuccess: () => pushEvent('onSuccess'),\n    onError: () => pushEvent('onError'),\n  }\n\n  return {\n    ...defaults,\n    ...overrides,\n  }\n}\n\nconst submit = () => {\n  form.post(page.url)\n}\n\nconst successfulRequest = () => {\n  form.post(page.url, {\n    ...callbacks(),\n  })\n}\n\nconst onSuccessResetErrors = () => {\n  form.post('/form-helper/events/errors', {\n    onError: () => {\n      pushEvent('onError')\n\n      form.post('/form-helper/events', {\n        ...callbacks({\n          onStart: () => {\n            pushEvent('onStart')\n            pushData('onStart', 'errors', form.errors)\n          },\n          onSuccess: () => {\n            pushEvent('onSuccess')\n            pushData('onSuccess', 'errors', form.errors)\n          },\n          onFinish: () => {\n            pushEvent('onFinish')\n            pushData('onFinish', 'errors', form.errors)\n          },\n        }),\n      })\n    },\n  })\n}\n\nconst errorsSetOnError = () => {\n  form.post('/form-helper/events/errors', {\n    ...callbacks({\n      onStart: () => {\n        pushEvent('onStart')\n        pushData('onStart', 'errors', form.errors)\n      },\n      onError: () => {\n        pushEvent('onError')\n        pushData('onError', 'errors', form.errors)\n      },\n      onFinish: () => {\n        pushEvent('onFinish')\n        pushData('onFinish', 'errors', form.errors)\n      },\n    }),\n  })\n}\n\nconst onBeforeVisit = () => {\n  form.post('/sleep', {\n    ...callbacks({\n      onBefore: (visit: PendingVisit) => {\n        pushEvent('onBefore')\n        pushData('onBefore', 'visit', visit)\n      },\n    }),\n  })\n}\n\nconst onBeforeVisitCancelled = () => {\n  form.post('/sleep', {\n    ...callbacks({\n      onBefore: () => {\n        pushEvent('onBefore')\n        return false\n      },\n    }),\n  })\n}\n\nconst onStartVisit = () => {\n  form.post('/form-helper/events', {\n    ...callbacks({\n      onStart: (visit: PendingVisit) => {\n        pushEvent('onStart')\n        pushData('onStart', 'visit', visit)\n      },\n    }),\n  })\n}\n\nconst onProgressVisit = () => {\n  form\n    .transform((data) => ({\n      ...data,\n      file: new File(['foobar'], 'example.bin'),\n    }))\n    .post('/dump/post', {\n      ...callbacks({\n        onProgress: (event: Progress) => {\n          pushEvent('onProgress')\n          pushData('onProgress', 'progressEvent', event)\n        },\n      }),\n    })\n}\n\nconst cancelledVisit = () => {\n  form.post('/sleep', {\n    ...callbacks({\n      onCancelToken: (token: CancelTokenSource) => {\n        pushEvent('onCancelToken')\n\n        setTimeout(() => {\n          pushEvent('CANCELLING!')\n          token.cancel()\n        }, 10)\n      },\n    }),\n  })\n}\n\nconst onSuccessVisit = () => {\n  form.post('/dump/post', {\n    ...callbacks({\n      onSuccess: (page: Page) => {\n        pushEvent('onSuccess')\n        pushData('onSuccess', 'page', page)\n      },\n    }),\n  })\n}\n\nconst onSuccessPromiseVisit = () => {\n  form.post('/dump/post', {\n    ...callbacks({\n      onSuccess: () => {\n        pushEvent('onSuccess')\n\n        setTimeout(() => pushEvent('onFinish should have been fired by now if Promise functionality did not work'), 5)\n        return new Promise((resolve) => setTimeout(resolve, 20))\n      },\n    }),\n  })\n}\n\nconst onSuccessResetValue = () => {\n  form.post(page.url, {\n    ...callbacks({\n      onSuccess: () => {\n        form.reset()\n      },\n    }),\n  })\n}\n\nconst onErrorVisit = () => {\n  form.post('/form-helper/events/errors', {\n    ...callbacks({\n      onError: (errors: Errors) => {\n        pushEvent('onError')\n        pushData('onError', 'errors', errors)\n      },\n    }),\n  })\n}\n\nconst onErrorPromiseVisit = () => {\n  form.post('/form-helper/events/errors', {\n    ...callbacks({\n      onError: () => {\n        pushEvent('onError')\n\n        setTimeout(() => pushEvent('onFinish should have been fired by now if Promise functionality did not work'), 5)\n        return new Promise((resolve) => setTimeout(resolve, 20))\n      },\n    }),\n  })\n}\n\nconst onSuccessProcessing = () => {\n  form.post(page.url, {\n    ...callbacks({\n      onBefore: () => {\n        pushEvent('onBefore')\n        pushData('onBefore', 'processing', form.processing)\n      },\n      onCancelToken: () => {\n        pushEvent('onCancelToken')\n        pushData('onCancelToken', 'processing', form.processing)\n      },\n      onStart: () => {\n        pushEvent('onStart')\n        pushData('onStart', 'processing', form.processing)\n      },\n      onSuccess: () => {\n        pushEvent('onSuccess')\n        pushData('onSuccess', 'processing', form.processing)\n      },\n      onFinish: () => {\n        pushEvent('onFinish')\n        pushData('onFinish', 'processing', form.processing)\n      },\n    }),\n  })\n}\n\nconst onErrorProcessing = () => {\n  form.post('/form-helper/events/errors', {\n    ...callbacks({\n      onBefore: () => {\n        pushEvent('onBefore')\n        pushData('onBefore', 'processing', form.processing)\n      },\n      onCancelToken: () => {\n        pushEvent('onCancelToken')\n        pushData('onCancelToken', 'processing', form.processing)\n      },\n      onStart: () => {\n        pushEvent('onStart')\n        pushData('onStart', 'processing', form.processing)\n      },\n      onError: () => {\n        pushEvent('onError')\n        pushData('onError', 'processing', form.processing)\n      },\n      onFinish: () => {\n        pushEvent('onFinish')\n        pushData('onFinish', 'processing', form.processing)\n      },\n    }),\n  })\n}\n\nconst onSuccessProgress = () => {\n  form\n    .transform((data) => ({\n      ...data,\n      file: new File(['foobar'], 'example.bin'),\n    }))\n    .post('/sleep', {\n      ...callbacks({\n        onBefore: () => {\n          pushEvent('onBefore')\n          pushData('onBefore', 'progress', form.progress)\n        },\n        onCancelToken: () => {\n          pushEvent('onCancelToken')\n          pushData('onCancelToken', 'progress', form.progress)\n        },\n        onStart: () => {\n          pushEvent('onStart')\n          pushData('onStart', 'progress', form.progress)\n        },\n        onProgress: () => {\n          pushEvent('onProgress')\n          pushData('onProgress', 'progress', form.progress)\n        },\n        onSuccess: () => {\n          pushEvent('onSuccess')\n          pushData('onSuccess', 'progress', form.progress)\n        },\n        onFinish: () => {\n          pushEvent('onFinish')\n          pushData('onFinish', 'progress', form.progress)\n        },\n      }),\n    })\n}\n\nconst onErrorProgress = () => {\n  form\n    .transform((data) => ({\n      ...data,\n      file: new File(['foobar'], 'example.bin'),\n    }))\n    .post('/form-helper/events/errors', {\n      ...callbacks({\n        onBefore: () => {\n          pushEvent('onBefore')\n          pushData('onBefore', 'progress', form.progress)\n        },\n        onCancelToken: () => {\n          pushEvent('onCancelToken')\n          pushData('onCancelToken', 'progress', form.progress)\n        },\n        onStart: () => {\n          pushEvent('onStart')\n          pushData('onStart', 'progress', form.progress)\n        },\n        onProgress: () => {\n          pushEvent('onProgress')\n          pushData('onProgress', 'progress', form.progress)\n        },\n        onError: () => {\n          pushEvent('onError')\n          pushData('onError', 'progress', form.progress)\n        },\n        onFinish: () => {\n          pushEvent('onFinish')\n          pushData('onFinish', 'progress', form.progress)\n        },\n      }),\n    })\n}\n\nconst progressNoFiles = () => {\n  form.post(page.url, {\n    ...callbacks({\n      onBefore: () => {\n        pushEvent('onBefore')\n        pushData('onBefore', 'progress', form.progress)\n      },\n      onCancelToken: () => {\n        pushEvent('onCancelToken')\n        pushData('onCancelToken', 'progress', form.progress)\n      },\n      onStart: () => {\n        pushEvent('onStart')\n        pushData('onStart', 'progress', form.progress)\n      },\n      onProgress: () => {\n        pushEvent('onProgress')\n        pushData('onProgress', 'progress', form.progress)\n      },\n      onSuccess: () => {\n        pushEvent('onSuccess')\n        pushData('onSuccess', 'progress', form.progress)\n      },\n      onFinish: () => {\n        pushEvent('onFinish')\n        pushData('onFinish', 'progress', form.progress)\n      },\n    }),\n  })\n}\n</script>\n\n<template>\n  <div>\n    <button @click.prevent=\"submit\" class=\"submit\">Submit form</button>\n\n    <button @click.prevent=\"successfulRequest\" class=\"successful-request\">Successful request</button>\n    <button @click.prevent=\"cancelledVisit\" class=\"cancel\">Cancellable Visit</button>\n\n    <button @click.prevent=\"onBeforeVisit\" class=\"before\">onBefore</button>\n    <button @click.prevent=\"onBeforeVisitCancelled\" class=\"before-cancel\">onBefore cancellation</button>\n    <button @click.prevent=\"onStartVisit\" class=\"start\">onStart</button>\n    <button @click.prevent=\"onProgressVisit\" class=\"progress\">onProgress</button>\n\n    <button @click.prevent=\"onSuccessVisit\" class=\"success\">onSuccess</button>\n    <button @click.prevent=\"onSuccessProgress\" class=\"success-progress\">onSuccess progress property</button>\n    <button @click.prevent=\"onSuccessProcessing\" class=\"success-processing\">onSuccess resets processing</button>\n    <button @click.prevent=\"onSuccessResetErrors\" class=\"success-reset-errors\">onSuccess resets errors</button>\n    <button @click.prevent=\"onSuccessPromiseVisit\" class=\"success-promise\">onSuccess promise</button>\n    <button @click.prevent=\"onSuccessResetValue\" class=\"success-reset-value\">onSuccess resets value</button>\n\n    <button @click.prevent=\"onErrorVisit\" class=\"error\">onError</button>\n    <button @click.prevent=\"onErrorProgress\" class=\"error-progress\">onError progress property</button>\n    <button @click.prevent=\"onErrorProcessing\" class=\"error-processing\">onError resets processing</button>\n    <button @click.prevent=\"errorsSetOnError\" class=\"errors-set-on-error\">Errors set on error</button>\n    <button @click.prevent=\"onErrorPromiseVisit\" class=\"error-promise\">onError promise</button>\n\n    <button @click.prevent=\"progressNoFiles\" class=\"no-progress\">progress no files</button>\n\n    <span class=\"success-status\">Form was {{ form.wasSuccessful ? '' : 'not ' }}successful</span>\n    <span class=\"recently-status\">Form was {{ form.recentlySuccessful ? '' : 'not ' }}recently successful</span>\n\n    <input type=\"text\" class=\"name-input\" v-model=\"form.name\" />\n    <input type=\"checkbox\" class=\"remember-input\" v-model=\"form.remember\" />\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Methods.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\nconst form = useForm({\n  name: 'foo',\n  remember: false,\n})\n\nconst postForm = () => {\n  form.post('/dump/post')\n}\n\nconst putForm = () => {\n  form.put('/dump/put')\n}\n\nconst patchForm = () => {\n  form.patch('/dump/patch')\n}\n\nconst deleteForm = () => {\n  form.delete('/dump/delete')\n}\n\nconst submitForm = () => {\n  form.submit('post', '/dump/post')\n}\n\nconst submitFormObject = () => {\n  form.submit({\n    method: 'post',\n    url: '/dump/post',\n  })\n}\n</script>\n\n<template>\n  <div>\n    <label>\n      Full Name\n      <input type=\"text\" id=\"name\" name=\"name\" v-model=\"form.name\" />\n    </label>\n    <label>\n      Remember Me\n      <input type=\"checkbox\" id=\"remember\" name=\"remember\" v-model=\"form.remember\" />\n    </label>\n\n    <button @click=\"postForm\" class=\"post\">POST form</button>\n    <button @click=\"putForm\" class=\"put\">PUT form</button>\n    <button @click=\"patchForm\" class=\"patch\">PATCH form</button>\n    <button @click=\"deleteForm\" class=\"delete\">DELETE form</button>\n    <button @click=\"submitForm\" class=\"delete\">SUBMIT form</button>\n    <button @click=\"submitFormObject\" class=\"delete\">SUBMIT OBJECT form</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Nested.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\nconst form = useForm({\n  name: 'foo',\n  address: {\n    street: '123 Main St',\n    city: 'New York',\n  },\n  organization: {\n    name: 'Inertia',\n    repo: {\n      name: 'inertiajs/inertia',\n      tags: ['v0.1', 'v0.2'],\n    },\n  },\n  checked: ['foo', 'bar'],\n})\n\nconst submit = () => {\n  form.submit('post', '/dump/post')\n}\n</script>\n\n<template>\n  <div>\n    <label>\n      Full Name\n      <input type=\"text\" id=\"name\" v-model=\"form.name\" />\n    </label>\n    <label>\n      Street\n      <input type=\"text\" id=\"street\" v-model=\"form.address.street\" />\n    </label>\n    <label>\n      City\n      <input type=\"text\" id=\"city\" v-model=\"form.address.city\" />\n    </label>\n    <label>\n      Foo\n      <input type=\"checkbox\" id=\"foo\" value=\"foo\" v-model=\"form.checked\" />\n    </label>\n    <label>\n      Bar\n      <input type=\"checkbox\" id=\"bar\" value=\"bar\" v-model=\"form.checked\" />\n    </label>\n    <label>\n      Baz\n      <input type=\"checkbox\" id=\"baz\" value=\"baz\" v-model=\"form.checked\" />\n    </label>\n    <label>\n      Organization Name\n      <input type=\"text\" id=\"organization-name\" v-model=\"form.organization.name\" />\n    </label>\n    <label>\n      Repository Name\n      <input type=\"text\" id=\"repo-name\" v-model=\"form.organization.repo.name\" />\n    </label>\n    Repository Tags\n    <label>\n      v0.1\n      <input type=\"checkbox\" id=\"tag-0\" value=\"v0.1\" v-model=\"form.organization.repo.tags\" />\n    </label>\n    <label>\n      v0.2\n      <input type=\"checkbox\" id=\"tag-1\" value=\"v0.2\" v-model=\"form.organization.repo.tags\" />\n    </label>\n    <label>\n      v0.3\n      <input type=\"checkbox\" id=\"tag-2\" value=\"v0.3\" v-model=\"form.organization.repo.tags\" />\n    </label>\n    <button @click=\"submit\" class=\"submit\">Submit form</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/NestedError.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\nconst form = useForm({\n  foo: {\n    bar: '',\n  },\n  baz: '',\n})\n</script>\n\n<template>\n  <p v-if=\"form.errors['baz']\">{{ form.errors['baz'] }}</p>\n  <p v-if=\"form.errors['foo.bar']\">{{ form.errors['foo.bar'] }}</p>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/OptionsApi.vue",
    "content": "<script lang=\"ts\">\nexport default {\n  data() {\n    return {\n      form: this.$inertia.form({\n        email: 'test@test.com',\n        password: '',\n        remember: false,\n      }),\n    }\n  },\n  methods: {\n    submit() {\n      this.form.post('/dump/post')\n    },\n    resetAll() {\n      this.form.reset()\n    },\n    clearEmail() {\n      this.form.email = ''\n    },\n    setEmail() {\n      this.form.email = 'changed@test.com'\n    },\n  },\n}\n</script>\n\n<template>\n  <div>\n    <label>\n      Email\n      <input type=\"text\" id=\"email\" name=\"email\" v-model=\"form.email\" />\n    </label>\n    <span class=\"email-value\">{{ form.email }}</span>\n    <label>\n      Password\n      <input type=\"password\" id=\"password\" name=\"password\" v-model=\"form.password\" />\n    </label>\n    <span class=\"password-value\">{{ form.password }}</span>\n    <label>\n      Remember Me\n      <input type=\"checkbox\" id=\"remember\" name=\"remember\" v-model=\"form.remember\" />\n    </label>\n    <span class=\"remember-value\">{{ form.remember }}</span>\n\n    <button @click=\"submit\" class=\"submit\">Submit form</button>\n    <button @click=\"resetAll\" class=\"reset\">Reset all data</button>\n    <button @click=\"clearEmail\" class=\"clear-email\">Clear email</button>\n    <button @click=\"setEmail\" class=\"set-email\">Set email programmatically</button>\n\n    <span class=\"dirty-status\">Form is {{ form.isDirty ? '' : 'not ' }}dirty</span>\n    <span class=\"processing-status\">Form is {{ form.processing ? '' : 'not ' }}processing</span>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Precognition/BeforeValidation.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\nimport { isEqual } from 'lodash-es'\n\nconst form = useForm({\n  name: '',\n  email: '',\n})\n  .withPrecognition('post', '/precognition/default')\n  .setValidationTimeout(100)\n\nconst handleBeforeValidation = (\n  newRequest: { data: Record<string, unknown> | null; touched: string[] },\n  oldRequest: { data: Record<string, unknown> | null; touched: string[] },\n) => {\n  const payloadIsCorrect =\n    isEqual(newRequest, { data: { name: 'block' }, touched: ['name'] }) &&\n    isEqual(oldRequest, { data: {}, touched: [] })\n\n  if (payloadIsCorrect && newRequest.data?.name === 'block') {\n    return false\n  }\n\n  return true\n}\n</script>\n\n<template>\n  <div>\n    <div>\n      <input\n        v-model=\"form.name\"\n        name=\"name\"\n        placeholder=\"Name\"\n        @blur=\"\n          form.validate('name', {\n            onBeforeValidation: handleBeforeValidation,\n          })\n        \"\n      />\n      <p v-if=\"form.invalid('name')\">\n        {{ form.errors.name }}\n      </p>\n      <p v-if=\"form.valid('name')\">Name is valid!</p>\n    </div>\n\n    <div>\n      <input v-model=\"form.email\" name=\"email\" placeholder=\"Email\" @blur=\"form.validate('email')\" />\n      <p v-if=\"form.invalid('email')\">\n        {{ form.errors.email }}\n      </p>\n      <p v-if=\"form.valid('email')\">Email is valid!</p>\n    </div>\n\n    <p v-if=\"form.validating\">Validating...</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Precognition/Callbacks.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst form = useForm({\n  name: '',\n  email: '',\n})\n  .withPrecognition('post', '/precognition/default')\n  .setValidationTimeout(100)\n\nconst successCalled = ref(false)\nconst errorCalled = ref(false)\nconst finishCalled = ref(false)\n</script>\n\n<template>\n  <div>\n    <div>\n      <input v-model=\"form.name\" name=\"name\" placeholder=\"Name\" @blur=\"form.touch('name')\" />\n      <p v-if=\"form.invalid('name')\">\n        {{ form.errors.name }}\n      </p>\n      <p v-if=\"form.valid('name')\">Name is valid!</p>\n    </div>\n\n    <p v-if=\"form.validating\">Validating...</p>\n    <p v-if=\"successCalled\">onPrecognitionSuccess called!</p>\n    <p v-if=\"errorCalled\">onValidationError called!</p>\n    <p v-if=\"finishCalled\">onFinish called!</p>\n\n    <button\n      type=\"button\"\n      @click=\"\n        () => {\n          successCalled = false\n          errorCalled = false\n          finishCalled = false\n          form.validate({\n            onPrecognitionSuccess: () => {\n              successCalled = true\n            },\n            onValidationError: () => {\n              errorCalled = true\n            },\n            onFinish: () => {\n              finishCalled = true\n            },\n          })\n        }\n      \"\n    >\n      Validate\n    </button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Precognition/Cancel.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\nconst form = useForm({\n  name: '',\n})\n  .withPrecognition('post', '/precognition/default?slow=1')\n  .setValidationTimeout(100)\n</script>\n\n<template>\n  <div>\n    <div>\n      <input\n        id=\"auto-cancel-name-input\"\n        v-model=\"form.name\"\n        name=\"name\"\n        placeholder=\"Name\"\n        @blur=\"form.validate('name')\"\n      />\n      <p v-if=\"form.invalid('name')\">\n        {{ form.errors.name }}\n      </p>\n      <p v-if=\"form.valid('name')\">Name is valid!</p>\n    </div>\n\n    <p v-if=\"form.validating\">Validating...</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Precognition/Compatibility.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\nimport { NamedInputEvent } from 'laravel-precognition'\n\nconst form = useForm({\n  name: '',\n  email: '',\n  company: '',\n})\n  .withPrecognition('post', '/precognition/default')\n  .setValidationTimeout(100)\n</script>\n\n<template>\n  <div>\n    <h1>Compatibility Test Page</h1>\n\n    <div>\n      <input v-model=\"form.name\" name=\"name\" placeholder=\"Name\" @blur=\"form.validate('name')\" />\n      <p v-if=\"form.invalid('name')\" id=\"name-error\">{{ form.errors.name }}</p>\n      <p v-if=\"form.valid('name')\" id=\"name-valid\">Name is valid!</p>\n    </div>\n\n    <div>\n      <input v-model=\"form.email\" name=\"email\" placeholder=\"Email\" @blur=\"form.validate('email')\" />\n      <p v-if=\"form.invalid('email')\" id=\"email-error\">{{ form.errors.email }}</p>\n      <p v-if=\"form.valid('email')\" id=\"email-valid\">Email is valid!</p>\n    </div>\n\n    <div>\n      <input\n        v-model=\"form.company\"\n        name=\"company\"\n        placeholder=\"Company\"\n        @focus=\"\n          (e) => {\n            const event = e as any as NamedInputEvent // eslint-disable-line @typescript-eslint/no-explicit-any\n            form.forgetError(event)\n            form.touch(event)\n          }\n        \"\n        @blur=\"form.validate('company')\"\n      />\n      <p v-if=\"form.invalid('company')\" id=\"company-error\">{{ form.errors.company }}</p>\n      <p v-if=\"form.valid('company')\" id=\"company-valid\">company is valid!</p>\n    </div>\n\n    <p v-if=\"form.validating\" id=\"validating\">Validating...</p>\n\n    <!-- Test compatibility methods -->\n    <div style=\"margin-top: 20px\">\n      <button\n        type=\"button\"\n        id=\"test-setErrors\"\n        @click=\"\n          form.setErrors({ name: 'setErrors test', email: 'setErrors email test', company: 'setErrors company test' })\n        \"\n      >\n        Test setErrors()\n      </button>\n\n      <button type=\"button\" id=\"test-forgetError\" @click=\"form.forgetError('name')\">Test forgetError()</button>\n\n      <button type=\"button\" id=\"test-touch-array\" @click=\"form.touch(['name', 'email'])\">Test touch([])</button>\n\n      <button type=\"button\" id=\"test-touch-spread\" @click=\"form.touch('name', 'email')\">Test touch(...args)</button>\n    </div>\n\n    <div style=\"margin-top: 20px\">\n      <p id=\"touched-name\">Name touched: {{ form.touched('name') ? 'yes' : 'no' }}</p>\n      <p id=\"touched-email\">Email touched: {{ form.touched('email') ? 'yes' : 'no' }}</p>\n      <p id=\"touched-company\">Company touched: {{ form.touched('company') ? 'yes' : 'no' }}</p>\n      <p id=\"touched-any\">Any touched: {{ form.touched() ? 'yes' : 'no' }}</p>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Precognition/Default.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\nconst form = useForm({\n  name: '',\n  email: '',\n})\n  .withPrecognition('post', '/precognition/default')\n  .setValidationTimeout(100)\n</script>\n\n<template>\n  <div>\n    <div>\n      <input v-model=\"form.name\" name=\"name\" placeholder=\"Name\" @blur=\"form.validate('name')\" />\n      <p v-if=\"form.invalid('name')\">\n        {{ form.errors.name }}\n      </p>\n      <p v-if=\"form.valid('name')\">Name is valid!</p>\n    </div>\n\n    <div>\n      <input v-model=\"form.email\" name=\"email\" placeholder=\"Email\" @blur=\"form.validate('email')\" />\n      <p v-if=\"form.invalid('email')\">\n        {{ form.errors.email }}\n      </p>\n      <p v-if=\"form.valid('email')\">Email is valid!</p>\n    </div>\n\n    <p v-if=\"form.validating\">Validating...</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Precognition/DynamicArrayInputs.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\nconst form = useForm({\n  items: [] as Array<{ name: string }>,\n})\n  .withPrecognition('post', '/precognition/dynamic-array-inputs')\n  .setValidationTimeout(100)\n\nfunction addItem() {\n  form.items.push({ name: '' })\n}\n</script>\n\n<template>\n  <div>\n    <button id=\"add-item\" @click=\"addItem\">Add Item</button>\n\n    <div v-for=\"(item, idx) in form.items\" :key=\"idx\">\n      <input v-model=\"item.name\" :name=\"`items.${idx}.name`\" @blur=\"form.validate(`items.${idx}.name`)\" />\n      <p v-if=\"form.invalid(`items.${idx}.name`)\" :id=\"`items.${idx}.name-error`\">\n        {{ form.errors[`items.${idx}.name`] }}\n      </p>\n      <p v-if=\"form.valid(`items.${idx}.name`)\">Valid!</p>\n    </div>\n\n    <p v-if=\"form.validating\">Validating...</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Precognition/ErrorSync.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\nconst form = useForm({\n  name: '',\n  email: '',\n})\n  .withPrecognition('post', '/precognition/error-sync')\n  .setValidationTimeout(100)\n\nconst handleSubmit = () => {\n  form.submit()\n}\n</script>\n\n<template>\n  <div>\n    <h1>Precognition Error Sync Test (Form Helper)</h1>\n\n    <form @submit.prevent=\"handleSubmit\">\n      <div>\n        <input v-model=\"form.name\" name=\"name\" placeholder=\"Name\" @blur=\"form.validate('name')\" />\n        <p v-if=\"form.invalid('name')\" id=\"name-error\">\n          {{ form.errors.name }}\n        </p>\n      </div>\n\n      <div>\n        <input v-model=\"form.email\" name=\"email\" placeholder=\"Email\" @blur=\"form.validate('email')\" />\n        <p v-if=\"form.invalid('email')\" id=\"email-error\">\n          {{ form.errors.email }}\n        </p>\n      </div>\n\n      <p v-if=\"form.validating\" id=\"validating\">Validating...</p>\n\n      <button type=\"submit\" id=\"submit-btn\">Submit</button>\n    </form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Precognition/Files.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\nimport { ref, watch } from 'vue'\n\nconst form = useForm<{\n  name: string\n  avatar: File | null\n}>({\n  name: '',\n  avatar: null,\n})\n  .withPrecognition('post', '/precognition/files')\n  .setValidationTimeout(100)\n\nconst validateFiles = ref(false)\n\nwatch(validateFiles, (enabled) => (enabled ? form.validateFiles() : form.withoutFileValidation()))\n</script>\n\n<template>\n  <div>\n    <div>\n      <input v-model=\"form.name\" name=\"name\" placeholder=\"Name\" @blur=\"form.validate('name')\" />\n      <p v-if=\"form.invalid('name')\">\n        {{ form.errors.name }}\n      </p>\n      <p v-if=\"form.valid('name')\">Name is valid!</p>\n    </div>\n\n    <div>\n      <input\n        type=\"file\"\n        name=\"avatar\"\n        id=\"avatar\"\n        @change=\"(e) => (form.avatar = (e.target as HTMLInputElement).files?.[0] || null)\"\n      />\n      <p v-if=\"form.invalid('avatar')\">\n        {{ form.errors.avatar }}\n      </p>\n      <p v-if=\"form.valid('avatar')\">Avatar is valid!</p>\n    </div>\n\n    <p v-if=\"form.validating\">Validating...</p>\n\n    <button type=\"button\" @click=\"validateFiles = !validateFiles\">\n      Toggle Validate Files ({{ validateFiles ? 'enabled' : 'disabled' }})\n    </button>\n\n    <button type=\"button\" @click=\"form.validate({ only: ['name', 'avatar'] })\">Validate Both</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Precognition/Headers.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\nconst form = useForm({\n  name: '',\n})\n  .withPrecognition('post', '/precognition/headers')\n  .setValidationTimeout(100)\n</script>\n\n<template>\n  <div>\n    <div>\n      <input\n        v-model=\"form.name\"\n        name=\"name\"\n        placeholder=\"Name\"\n        @blur=\"\n          form.validate('name', {\n            headers: { 'X-Custom-Header': 'custom-value' },\n          })\n        \"\n      />\n      <p v-if=\"form.invalid('name')\">\n        {{ form.errors.name }}\n      </p>\n      <p v-if=\"form.valid('name')\">Name is valid!</p>\n    </div>\n\n    <p v-if=\"form.validating\">Validating...</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Precognition/Instantiate.vue",
    "content": "<script setup lang=\"ts\">\nimport { Method, UrlMethodPair } from '@inertiajs/core'\nimport { useForm } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst wayfinderUrl = (): UrlMethodPair => ({\n  url: '/precognition/default',\n  method: 'post',\n})\n\nconst form = ref<keyof typeof forms>('default')\nconst data = () => ({ name: 'a' })\n\nconst forms = {\n  // Forms that use the new withPrecognition() method\n  default: useForm(data()).withPrecognition('post', '/precognition/default'),\n  dynamic: useForm(data()).withPrecognition(\n    () => 'post',\n    () => '/precognition/default',\n  ),\n  wayfinder: useForm(data()).withPrecognition(wayfinderUrl()),\n  dynamicWayfinder: useForm(data()).withPrecognition(() => wayfinderUrl()),\n\n  // Forms that use the original useForm() parameters from the 0.x Precognition implementation\n  legacy: useForm('post', '/precognition/default', data()),\n  legacyDynamic: useForm(\n    () => 'post' as Method,\n    () => '/precognition/default',\n    data(),\n  ),\n  legacyWayfinder: useForm(wayfinderUrl(), data()),\n  legacyDynamicWayfinder: useForm(() => wayfinderUrl(), data()),\n}\n\nconst validateForm = (formName: keyof typeof forms) => {\n  forms[formName].touch('name')\n  forms[formName].validate()\n}\n\nconst submitWithoutArgs = (formName: keyof typeof forms) => {\n  forms[formName].submit()\n}\n\nconst submitWithArgs = (formName: keyof typeof forms) => {\n  forms[formName].submit('patch', '/dump/patch')\n}\n\nconst submitWithMethod = (formName: keyof typeof forms) => {\n  forms[formName].put('/dump/put')\n}\n\nconst submitWithWayfinder = (formName: keyof typeof forms) => {\n  forms[formName].submit({ url: '/dump/post', method: 'post' })\n}\n</script>\n\n<template>\n  <select v-model=\"form\">\n    <option value=\"default\">withPrecognition()</option>\n    <option value=\"dynamic\">withPrecognition() dynamic</option>\n    <option value=\"wayfinder\">withPrecognition() Wayfinder</option>\n    <option value=\"dynamicWayfinder\">withPrecognition() dynamic Wayfinder</option>\n    <option value=\"legacy\">useForm() legacy</option>\n    <option value=\"legacyDynamic\">useForm() legacy dynamic</option>\n    <option value=\"legacyWayfinder\">useForm() legacy Wayfinder</option>\n    <option value=\"legacyDynamicWayfinder\">useForm() legacy dynamic Wayfinder</option>\n  </select>\n\n  <button @click=\"validateForm(form)\">Validate</button>\n  <button @click=\"submitWithoutArgs(form)\">Submit without args</button>\n  <button @click=\"submitWithArgs(form)\">Submit with args</button>\n  <button @click=\"submitWithMethod(form)\">Submit with method</button>\n  <button @click=\"submitWithWayfinder(form)\">Submit with Wayfinder</button>\n\n  <p v-if=\"forms[form].validating\">Validating...</p>\n  <p v-if=\"forms[form].errors.name\">{{ forms[form].errors.name }}</p>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Precognition/Methods.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\nconst form = useForm({\n  name: '',\n  email: '',\n})\n  .withPrecognition('post', '/precognition/default')\n  .setValidationTimeout(100)\n</script>\n\n<template>\n  <div>\n    <div>\n      <input name=\"name\" v-model=\"form.name\" placeholder=\"Name\" @blur=\"form.touch('name')\" />\n      <p v-if=\"form.invalid('name')\">\n        {{ form.errors.name }}\n      </p>\n    </div>\n\n    <div>\n      <input name=\"email\" v-model=\"form.email\" placeholder=\"Email\" @blur=\"form.touch('email')\" />\n      <p v-if=\"form.invalid('email')\">\n        {{ form.errors.email }}\n      </p>\n    </div>\n\n    <p v-if=\"form.validating\">Validating...</p>\n\n    <p id=\"name-touched\">{{ form.touched('name') ? 'Name is touched' : 'Name is not touched' }}</p>\n    <p id=\"email-touched\">{{ form.touched('email') ? 'Email is touched' : 'Email is not touched' }}</p>\n    <p id=\"any-touched\">{{ form.touched() ? 'Form has touched fields' : 'Form has no touched fields' }}</p>\n\n    <button type=\"button\" @click=\"form.validate()\">Validate All Touched</button>\n    <button type=\"button\" @click=\"form.validate('name')\">Validate Name</button>\n    <button type=\"button\" @click=\"form.validate({ only: ['name', 'email'] })\">Validate Name and Email</button>\n    <button type=\"button\" @click=\"form.touch('name', 'email')\">Touch Name and Email</button>\n    <button\n      type=\"button\"\n      @click=\"\n        () => {\n          form.touch('name')\n          form.touch('name')\n        }\n      \"\n    >\n      Touch Name Twice\n    </button>\n    <button type=\"button\" @click=\"form.reset()\">Reset All</button>\n    <button type=\"button\" @click=\"form.reset('name')\">Reset Name</button>\n    <button type=\"button\" @click=\"form.reset('name', 'email')\">Reset Name and Email</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Precognition/Transform.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\nconst form = useForm({\n  name: '',\n})\n  .withPrecognition('post', '/precognition/default')\n  .setValidationTimeout(100)\n  .transform((data) => ({ name: String(data.name || '').repeat(2) }))\n</script>\n\n<template>\n  <div>\n    <div>\n      <input v-model=\"form.name\" name=\"name\" placeholder=\"Name\" @blur=\"form.validate('name')\" />\n      <p v-if=\"form.invalid('name')\">\n        {{ form.errors.name }}\n      </p>\n      <p v-if=\"form.valid('name')\">Name is valid!</p>\n    </div>\n\n    <p v-if=\"form.validating\">Validating...</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Precognition/TransformKeys.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\nconst form = useForm({\n  document: {\n    customer: { email: '' },\n  },\n})\n  .withPrecognition('post', '/precognition/transform-keys')\n  .setValidationTimeout(100)\n  .transform((data) => ({ ...data.document }))\n</script>\n\n<template>\n  <div>\n    <div>\n      <input\n        id=\"email-input\"\n        v-model=\"form.document.customer.email\"\n        name=\"customer.email\"\n        placeholder=\"Email\"\n        @blur=\"(form as any).validate('customer.email')\"\n      />\n      <p v-if=\"(form as any).invalid('customer.email')\">\n        {{ (form.errors as any)['customer.email'] }}\n      </p>\n      <p v-if=\"(form as any).valid('customer.email')\">Email is valid!</p>\n    </div>\n\n    <p v-if=\"form.validating\">Validating...</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Precognition/WithAllErrors.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\nconst form = useForm({\n  name: '',\n  email: '',\n})\n  .withPrecognition('post', '/precognition/with-all-errors')\n  .setValidationTimeout(100)\n  .withAllErrors()\n</script>\n\n<template>\n  <div>\n    <div>\n      <input v-model=\"form.name\" name=\"name\" placeholder=\"Name\" @blur=\"form.validate('name')\" />\n      <div v-if=\"form.invalid('name')\">\n        <template v-if=\"Array.isArray(form.errors.name)\">\n          <p v-for=\"(error, index) in form.errors.name\" :key=\"index\" :id=\"`name-error-${index}`\">\n            {{ error }}\n          </p>\n        </template>\n        <p v-else id=\"name-error-0\">{{ form.errors.name }}</p>\n      </div>\n      <p v-if=\"form.valid('name')\">Name is valid!</p>\n    </div>\n\n    <div>\n      <input v-model=\"form.email\" name=\"email\" placeholder=\"Email\" @blur=\"form.validate('email')\" />\n      <div v-if=\"form.invalid('email')\">\n        <template v-if=\"Array.isArray(form.errors.email)\">\n          <p v-for=\"(error, index) in form.errors.email\" :key=\"index\" :id=\"`email-error-${index}`\">\n            {{ error }}\n          </p>\n        </template>\n        <p v-else id=\"email-error-0\">{{ form.errors.email }}</p>\n      </div>\n      <p v-if=\"form.valid('email')\">Email is valid!</p>\n    </div>\n\n    <p v-if=\"form.validating\">Validating...</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Precognition/WithAllErrorsConfig.vue",
    "content": "<script setup lang=\"ts\">\nimport { config, useForm } from '@inertiajs/vue3'\n\n// Set global config for withAllErrors (no .withAllErrors() call on the form)\nconfig.set('form.withAllErrors', true)\n\nconst form = useForm({\n  name: '',\n  email: '',\n})\n  .withPrecognition('post', '/precognition/with-all-errors')\n  .setValidationTimeout(100)\n</script>\n\n<template>\n  <div>\n    <div>\n      <input v-model=\"form.name\" name=\"name\" placeholder=\"Name\" @blur=\"form.validate('name')\" />\n      <div v-if=\"form.invalid('name')\">\n        <template v-if=\"Array.isArray(form.errors.name)\">\n          <p v-for=\"(error, index) in form.errors.name\" :key=\"index\" :id=\"`name-error-${index}`\">\n            {{ error }}\n          </p>\n        </template>\n        <p v-else id=\"name-error-0\">{{ form.errors.name }}</p>\n      </div>\n      <p v-if=\"form.valid('name')\">Name is valid!</p>\n    </div>\n\n    <div>\n      <input v-model=\"form.email\" name=\"email\" placeholder=\"Email\" @blur=\"form.validate('email')\" />\n      <div v-if=\"form.invalid('email')\">\n        <template v-if=\"Array.isArray(form.errors.email)\">\n          <p v-for=\"(error, index) in form.errors.email\" :key=\"index\" :id=\"`email-error-${index}`\">\n            {{ error }}\n          </p>\n        </template>\n        <p v-else id=\"email-error-0\">{{ form.errors.email }}</p>\n      </div>\n      <p v-if=\"form.valid('email')\">Email is valid!</p>\n    </div>\n\n    <p v-if=\"form.validating\">Validating...</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Precognition/WithoutAllErrors.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\nconst form = useForm({\n  name: '',\n  email: '',\n})\n  .withPrecognition('post', '/precognition/with-all-errors')\n  .setValidationTimeout(100)\n</script>\n\n<template>\n  <div>\n    <div>\n      <input v-model=\"form.name\" name=\"name\" placeholder=\"Name\" @blur=\"form.validate('name')\" />\n      <p v-if=\"form.invalid('name')\">\n        {{ form.errors.name }}\n      </p>\n      <p v-if=\"form.valid('name')\">Name is valid!</p>\n    </div>\n\n    <div>\n      <input v-model=\"form.email\" name=\"email\" placeholder=\"Email\" @blur=\"form.validate('email')\" />\n      <p v-if=\"form.invalid('email')\">\n        {{ form.errors.email }}\n      </p>\n      <p v-if=\"form.valid('email')\">Email is valid!</p>\n    </div>\n\n    <p v-if=\"form.validating\">Validating...</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/RememberEdit.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\nconst props = defineProps({\n  user: {\n    type: Object as () => { id: number; name: string; email: string },\n    required: true,\n  },\n})\n\nconst form = useForm('EditUserForm', {\n  name: props.user.name,\n  email: props.user.email,\n})\n</script>\n\n<template>\n  <div>\n    <h1>Edit User {{ user.id }}</h1>\n    <form>\n      <div>\n        <label>Name:</label>\n        <input v-model=\"form.name\" type=\"text\" />\n      </div>\n      <div>\n        <label>Email:</label>\n        <input v-model=\"form.email\" type=\"email\" />\n      </div>\n    </form>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/RememberIndex.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n\ndefineProps({\n  users: {\n    type: Array as () => { id: number; name: string; email: string }[],\n    required: true,\n  },\n})\n</script>\n\n<template>\n  <div>\n    <h1>Users Index</h1>\n    <ul>\n      <li v-for=\"user in users\" :key=\"user.id\">\n        <Link :href=\"`/remember/users/${user.id}/edit`\">Edit {{ user.name }}</Link>\n      </li>\n    </ul>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/ReservedKeys.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\n// @ts-expect-error - Intentionally using reserved key to test validation\nconst form = useForm({ progress: 0 })\n</script>\n\n<template>\n  <div>\n    <div id=\"form-created\">Form created with progress value: {{ form.progress }}</div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/Transform.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\nconst form = useForm({\n  name: 'foo',\n  remember: false,\n})\n\nconst postForm = () => {\n  form\n    .transform((data) => ({\n      ...data,\n      name: 'bar',\n    }))\n    .post('/dump/post')\n}\n\nconst putForm = () => {\n  form\n    .transform((data) => ({\n      ...data,\n      name: 'baz',\n    }))\n    .put('/dump/put')\n}\n\nconst patchForm = () => {\n  form\n    .transform((data) => ({\n      ...data,\n      name: 'foo',\n    }))\n    .patch('/dump/patch')\n}\n\nconst deleteForm = () => {\n  form\n    .transform((data) => ({\n      ...data,\n      name: 'bar',\n    }))\n    .delete('/dump/delete')\n}\n</script>\n\n<template>\n  <div>\n    <label>\n      Full Name\n      <input type=\"text\" id=\"name\" name=\"name\" v-model=\"form.name\" />\n    </label>\n    <label>\n      Remember Me\n      <input type=\"checkbox\" id=\"remember\" name=\"remember\" v-model=\"form.remember\" />\n    </label>\n\n    <button @click=\"postForm\" class=\"post\">POST form</button>\n    <button @click=\"putForm\" class=\"put\">PUT form</button>\n    <button @click=\"patchForm\" class=\"patch\">PATCH form</button>\n    <button @click=\"deleteForm\" class=\"delete\">DELETE form</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/TypeScript/Any.vue",
    "content": "<script setup lang=\"ts\">\n// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/vue3'\n\nconst form = useForm<{ name: any }>({ name: null }) // eslint-disable-line @typescript-eslint/no-explicit-any\n\nform.name = 0\nform.name = 'test'\nform.name = true\nform.name = null\nform.name = {\n  key: 'value',\n}\n</script>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/TypeScript/Child.vue",
    "content": "<script setup lang=\"ts\">\n// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport type { InertiaForm } from '@inertiajs/vue3'\nimport { toRef } from 'vue'\n\nconst props = defineProps<{\n  form: InertiaForm<{\n    name: string\n    email?: string\n  }>\n}>()\n\nconst form = toRef(props, 'form')\n</script>\n\n<template>\n  <p>Name: {{ form.name }}</p>\n  <p>Email: {{ form.email }}</p>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/TypeScript/CircularReferences.vue",
    "content": "<script setup lang=\"ts\">\n// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/vue3'\n\ntype SubData = {\n  foo: string\n  items?: SubData[]\n}\n\ntype Data = {\n  items: SubData[]\n}\n\nconst form = useForm<Data>({\n  items: [],\n})\n\nform.items = []\nform.items = [\n  {\n    foo: 'bar',\n    items: [\n      {\n        foo: 'baz',\n        items: [\n          {\n            foo: 'qux',\n          },\n        ],\n      },\n    ],\n  },\n]\n\n// @ts-expect-error - items should be an array of SubData\nform.items = {}\n// @ts-expect-error - foo should be a string\nform.items = [{ foo: 123 }]\n// @ts-expect-error - items should be an array of SubData\nform.items = [{ foo: 'bar', items: {} }]\n// @ts-expect-error - foo should be a string\nform.items = [{ foo: 'bar', items: [{ foo: 123 }] }]\n</script>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/TypeScript/Data.vue",
    "content": "<script setup lang=\"ts\">\n// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/vue3'\n\ntype FormData = {\n  name: string\n  company: { name: string }\n  users: { name: string }[]\n}\n\nconst defaultData = {\n  name: '',\n  company: { name: '' },\n  users: [],\n}\n\nconst form = useForm<FormData>(defaultData)\nform.name = 'John Doe'\nform.company.name = 'Acme Corp'\nform.users = [{ name: 'Jane Doe' }]\n// @ts-expect-error - A form has no email field\nform.email = 'john@example.com'\n// @ts-expect-error - A company has no street field\nform.company.street = '123 Main St'\n// @ts-expect-error - A company has no street field\nform.company = { name: 'Acme Corp', street: '123 Main St' }\n// @ts-expect-error - A form has no email field\nform.users = [{ name: 'Jane Doe', email: 'jane@example.com' }]\n</script>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/TypeScript/DynamicInputName.vue",
    "content": "<script setup lang=\"ts\">\n// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/vue3'\n\ninterface ClientForm {\n  name: string\n  [key: string]: any // eslint-disable-line @typescript-eslint/no-explicit-any\n}\n\nconst form = useForm<ClientForm>({\n  name: '',\n})\n\nconst handleChange = (e: Event) => {\n  const target = e.target as HTMLInputElement\n  const { name, value } = target\n  form[name] = value\n}\n</script>\n\n<template>\n  <input name=\"name\" type=\"text\" :value=\"form.name\" @input=\"handleChange\" />\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/TypeScript/Errors.vue",
    "content": "<script setup lang=\"ts\">\n// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/vue3'\n\ntype FormData = {\n  name: string\n  company: { name: string }\n  users: { name: string }[]\n}\n\nconst defaultData = {\n  name: '',\n  company: { name: '' },\n  users: [],\n}\n\nconst form = useForm<FormData>(defaultData)\n\n// Get Errors\nconsole.log(form.errors.name)\nconsole.log(form.errors['company.name'])\n\n// Clear Errors\nform.clearErrors('name')\nform.clearErrors('company')\nform.clearErrors('company.name')\nform.clearErrors('users')\nform.clearErrors('users.0')\nform.clearErrors('users.0.name')\n\n// Reset and Clear Errors\nform.resetAndClearErrors('name')\nform.resetAndClearErrors('company')\nform.resetAndClearErrors('company.name')\nform.resetAndClearErrors('users')\nform.resetAndClearErrors('users.0')\nform.resetAndClearErrors('users.0.name')\n\n// Set error by key\nform.setError('name', 'Validation error')\nform.setError('company', 'Validation error')\nform.setError('company.name', 'Validation error')\nform.setError('users', 'Validation error')\nform.setError('users.0', 'Validation error')\nform.setError('users.0.name', 'Validation error')\n\n// Set error by object\nform.setError({ name: 'Validation error' })\nform.setError({ company: 'Validation error' })\nform.setError({ 'company.name': 'Validation error' })\nform.setError({ users: 'Validation error' })\nform.setError({ 'users.0': 'Validation error' })\nform.setError({ 'users.0.name': 'Validation error' })\n\n// @ts-expect-error - Form has no email field\nconsole.log(form.errors.email)\n// @ts-expect-error - Company has no email field\nconsole.log(form.errors['company.email'])\n\n// @ts-expect-error - Form has no email field\nform.clearErrors('email')\n// @ts-expect-error - Form has no email field\nform.resetAndClearErrors('email')\n// @ts-expect-error - Form has no email field\nform.setError('email', 'Validation error')\n// @ts-expect-error - Form has no email field\nform.setError({ email: 'Validation error' })\n\n// @ts-expect-error - Company has no email field\nform.clearErrors('company.email')\n// @ts-expect-error - Company has no email field\nform.resetAndClearErrors('company.email')\n// @ts-expect-error - Company has no email field\nform.setError('company.email', 'Validation error')\n// @ts-expect-error - Company has no email field\nform.setError({ 'company.email': 'Validation error' })\n\n// @ts-expect-error - A user has no email field\nform.clearErrors('users.0.email')\n// @ts-expect-error - A user has no email field\nform.resetAndClearErrors('users.0.email')\n// @ts-expect-error - A user has no email field\nform.setError('users.0.email', 'Validation error')\n// @ts-expect-error - A user has no email field\nform.setError({ 'users.0.email': 'Validation error' })\n</script>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/TypeScript/FormDataCallback.vue",
    "content": "<script setup lang=\"ts\">\n// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/vue3'\n\ntype FormData = {\n  name: string\n  company: { name: string }\n  users: { name: string }[]\n}\n\nconst defaultData = {\n  name: '',\n  company: { name: '' },\n  users: [],\n}\n\nconst form = useForm<FormData>(() => defaultData)\nform.name = 'John Doe'\nform.company.name = 'Acme Corp'\nform.users = [{ name: 'Jane Doe' }]\n// @ts-expect-error - A form has no email field\nform.email = 'john@example.com'\n// @ts-expect-error - A company has no street field\nform.company.street = '123 Main St'\n// @ts-expect-error - A company has no street field\nform.company = { name: 'Acme Corp', street: '123 Main St' }\n// @ts-expect-error - A form has no email field\nform.users = [{ name: 'Jane Doe', email: 'jane@example.com' }]\n\nconst inferredData = {\n  name: '',\n  company: { name: '' },\n  users: [{ name: '' }],\n}\n\nconst inferred = useForm(() => inferredData)\ninferred.name = 'John Doe'\ninferred.company.name = 'Acme Corp'\ninferred.users = [{ name: 'Jane Doe' }]\n// @ts-expect-error - A form has no email field\ninferred.email = 'john@example.com'\n\nconst withRememberKey = useForm<FormData>('myKey', () => defaultData)\nwithRememberKey.name = 'John Doe'\n// @ts-expect-error - A form has no email field\nwithRememberKey.email = 'john@example.com'\n\n// @ts-expect-error - progress is a reserved form key\nuseForm(() => ({ progress: 1 }))\n</script>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/TypeScript/Generic.vue",
    "content": "<script setup lang=\"ts\" generic=\"TFormData extends Record<string, FormDataConvertible>\">\n// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport type { FormDataConvertible } from '@inertiajs/core'\nimport type { InertiaForm } from '@inertiajs/vue3'\n\ndefineProps<{\n  form: InertiaForm<TFormData>\n}>()\n</script>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/TypeScript/Nullable.vue",
    "content": "<script setup lang=\"ts\">\n// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/vue3'\n\nuseForm<{ object: { x: number } | null }>({\n  object: null,\n})\n\nuseForm<{ object: { x: number } | null }>({\n  object: { x: 1 },\n})\n</script>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/TypeScript/NullableNestedObject.vue",
    "content": "<script setup lang=\"ts\">\n// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/vue3'\n\ninterface FormData {\n  foo: null | {\n    bar: string\n  }\n}\n\nconst form = useForm<FormData>({\n  foo: null,\n})\n\nconsole.log(form.errors['foo.bar'])\n</script>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/TypeScript/OptionalProps.vue",
    "content": "<script setup lang=\"ts\">\n// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/vue3'\n\ninterface LoginData {\n  username: string\n  password: string\n  remember: boolean\n}\n\nconst props = defineProps({\n  user: {\n    type: Object,\n    required: false,\n    default: null,\n  },\n})\n\nuseForm<LoginData>({\n  username: props.user?.username ?? '',\n  password: '',\n  remember: true,\n})\n</script>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/TypeScript/Parent.vue",
    "content": "<script setup lang=\"ts\">\n// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/vue3'\nimport Child from './Child.vue'\n\nconst form = useForm({\n  name: 'foo',\n  remember: false,\n})\n</script>\n\n<template>\n  <Child :form />\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/TypeScript/Precognition.vue",
    "content": "<script setup lang=\"ts\">\n// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { useForm } from '@inertiajs/vue3'\n\nconst defaultForm = useForm({})\nconst rememberForm = useForm('id', {})\n\n// @ts-expect-error - No Precognition...\ndefaultForm.validate()\n// @ts-expect-error - No Precognition...\nrememberForm.validate()\n\nconst precognitionForm = useForm({ name: '', company: '' }).withPrecognition('post', '/precognition/default')\nconst originalPrecognitionForm = useForm('post', '/', {})\n\nprecognitionForm.validate()\noriginalPrecognitionForm.validate()\n\nprecognitionForm.validate('name')\nprecognitionForm.validate({ only: ['name'] })\nprecognitionForm.touch('name')\nprecognitionForm.touch('name', 'company')\nprecognitionForm.touched()\nprecognitionForm.touched('name')\nprecognitionForm.invalid('name')\nprecognitionForm.valid('name')\n\n// @ts-expect-error - Field does not exist\nprecognitionForm.validate('email')\n// @ts-expect-error - Field does not exist\nprecognitionForm.validate({ only: ['email'] })\n// @ts-expect-error - Field does not exist\nprecognitionForm.touch('email')\n// @ts-expect-error - Field does not exist\nprecognitionForm.touched('email')\n// @ts-expect-error - Field does not exist\nprecognitionForm.invalid('email')\n// @ts-expect-error - Field does not exist\nprecognitionForm.valid('email')\n\nconst nestedForm = useForm({ user: { name: '', company: '' } }).withPrecognition('post', '/precognition/nested')\n\nnestedForm.validate('user.name')\nnestedForm.validate({ only: ['user.name'] })\nnestedForm.valid('user.name')\nnestedForm.invalid('user.name')\n\n// @ts-expect-error - Field does not exist\nnestedForm.validate('user.email')\n// @ts-expect-error - Field does not exist\nnestedForm.validate({ only: ['user.email'] })\n// @ts-expect-error - Field does not exist\nnestedForm.valid('user.email')\n// @ts-expect-error - Field does not exist\nnestedForm.invalid('user.email')\n\n// Wildcard path support (PrecognitionPath)\nconst wildcardForm = useForm({\n  users: [] as Array<{ name: string; email: string }>,\n  profile: { age: 0, city: '' },\n  company: { name: '', addresses: [] as string[] },\n  nested: { companies: [] as Array<{ name: string; addresses: string[] }> },\n}).withPrecognition('post', '/precognition/wildcard')\n\n// Valid array field paths\nwildcardForm.validate('users')\nwildcardForm.validate('users.*')\nwildcardForm.validate('users.*.name')\nwildcardForm.validate('users.*.email')\nwildcardForm.validate('users.*.*')\n\n// Valid object field paths\nwildcardForm.validate('profile')\nwildcardForm.validate('profile.*')\nwildcardForm.validate('profile.age')\n\n// Valid nested paths\nwildcardForm.validate('company')\nwildcardForm.validate('company.addresses')\nwildcardForm.validate('nested')\nwildcardForm.validate('nested.companies')\nwildcardForm.validate('nested.companies.*')\nwildcardForm.validate('nested.companies.*.name')\nwildcardForm.validate('nested.companies.*.addresses')\nwildcardForm.validate('nested.companies.*.*')\n\n// @ts-expect-error - nonexistent property in array items\nwildcardForm.validate('users.*.unknown')\n// @ts-expect-error - missing wildcard for array access\nwildcardForm.validate('users.email')\n// @ts-expect-error - invalid deep nesting\nwildcardForm.validate('profile.age.foo')\n// @ts-expect-error - field does not exist\nwildcardForm.validate('nonexistent')\n// @ts-expect-error - no such field\nwildcardForm.validate('profile.country')\n</script>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/TypeScript/ValidationKey.vue",
    "content": "<script setup lang=\"ts\">\n// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport type { FormDataConvertible } from '@inertiajs/core'\nimport type { InertiaFormProps } from '@inertiajs/vue3'\n\nconst validation = <T extends Record<string, FormDataConvertible>>(errors: () => InertiaFormProps<T>['errors']) => {\n  type Key = keyof ReturnType<typeof errors>\n\n  const filterAndMap = (key: Key) => {\n    const err = errors()\n\n    return (Object.keys(err).filter((k) => k.startsWith(key)) as [keyof ReturnType<typeof errors>]).map((k) => err[k])\n  }\n\n  const unique = (key: Key) => {\n    return filterAndMap(key).filter((error, index, self) => self.indexOf(error) === index)\n  }\n\n  return { filterAndMap, unique }\n}\n</script>\n\n<template>\n  <button @click=\"validation(() => ({ name: 'Validation error' }))\">Handle</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/TypeScript/WrapperChild.vue",
    "content": "<!-- eslint-disable @typescript-eslint/no-explicit-any -->\n<script setup lang=\"ts\" generic=\"T extends Record<string, any>\">\nimport { useForm } from '@inertiajs/vue3'\n\nconst props = defineProps<{ data: T }>()\n\nconst form = useForm(props.data)\n</script>\n\n<template>\n  <form>\n    <slot :form=\"form\" />\n  </form>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/FormHelper/TypeScript/WrapperParent.vue",
    "content": "<script setup lang=\"ts\">\n// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport WrapperChild from './WrapperChild.vue'\n\nconst dummyForm = {\n  header: '',\n  children: [\n    {\n      title: '',\n      active: false,\n    },\n  ],\n}\n</script>\n\n<template>\n  <WrapperChild :data=\"dummyForm\" v-slot=\"{ form }\">\n    {{ form.children.map((child) => child.title) }}\n  </WrapperChild>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Head/Conditional.vue",
    "content": "<script setup lang=\"ts\">\nimport { Head } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst showDescription = ref(true)\nconst showKeywords = ref(false)\n\nfunction toggleDescription() {\n  showDescription.value = !showDescription.value\n}\n\nfunction toggleKeywords() {\n  showKeywords.value = !showKeywords.value\n}\n</script>\n\n<template>\n  <Head title=\"Conditional Rendering\">\n    <meta\n      v-if=\"showDescription\"\n      name=\"description\"\n      content=\"This description is conditionally rendered\"\n      head-key=\"description\"\n    />\n    <meta v-if=\"showKeywords\" name=\"keywords\" content=\"vue, test, conditional\" head-key=\"keywords\" />\n    <meta name=\"always-present\" content=\"This is always here\" />\n  </Head>\n\n  <div>\n    <h1>Conditional Head Rendering</h1>\n    <button id=\"toggle-description\" @click=\"toggleDescription\">\n      {{ showDescription ? 'Hide' : 'Show' }} Description\n    </button>\n    <button id=\"toggle-keywords\" @click=\"toggleKeywords\">{{ showKeywords ? 'Hide' : 'Show' }} Keywords</button>\n    <p>Description visible: {{ showDescription }}</p>\n    <p>Keywords visible: {{ showKeywords }}</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Head/Dataset.vue",
    "content": "<script setup lang=\"ts\">\nimport { config, Head } from '@inertiajs/vue3'\n\nconfig.set('future.useDataInertiaHeadAttribute', true)\n</script>\n\n<template>\n  <Head title=\"Test Head Component\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  </Head>\n\n  <h1 :style=\"{ fontSize: '40px' }\">Head Component</h1>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Head/Mixed.vue",
    "content": "<script setup lang=\"ts\">\nimport { Head, Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <Head title=\"Multiple Elements Test\">\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <meta name=\"description\" content=\"Testing multiple head elements\" />\n    <meta name=\"keywords\" content=\"test, vue, inertia\" />\n    <meta property=\"og:title\" content=\"Open Graph Title\" />\n    <meta property=\"og:description\" content=\"Open Graph Description\" />\n    <link rel=\"icon\" href=\"/favicon.ico\" />\n    <link rel=\"stylesheet\" href=\"/custom.css\" />\n    <link rel=\"canonical\" href=\"https://example.com/page\" />\n  </Head>\n\n  <div>\n    <h1>Multiple Head Elements</h1>\n    <p>Check the document head for multiple elements</p>\n    <Link id=\"navigate-away\" href=\"/\">Go Home</Link>\n    <Link id=\"navigate-back\" href=\"/head/mixed\">Back to Mixed</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Head/Reactive.vue",
    "content": "<script setup lang=\"ts\">\nimport { Head } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst title = ref('Initial Title')\nconst description = ref('Initial description')\n\nfunction updateMeta() {\n  title.value = 'Updated Title'\n  description.value = 'Updated description'\n}\n</script>\n\n<template>\n  <Head :title=\"title\">\n    <meta name=\"description\" :content=\"description\" head-key=\"description\" />\n    <meta name=\"author\" content=\"Test Author\" />\n  </Head>\n\n  <div>\n    <h1>Dynamic Head Updates</h1>\n    <button id=\"update-meta\" @click=\"updateMeta\">Update Meta</button>\n    <p>Current title: {{ title }}</p>\n    <p>Current description: {{ description }}</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Head/WithTitle.vue",
    "content": "<script setup lang=\"ts\">\nimport { Head } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <Head>\n    <!-- Title as a child element instead of prop -->\n    <title>Title from Children</title>\n    <meta name=\"description\" content=\"Title set via children, not prop\" />\n  </Head>\n\n  <div>\n    <h1>Title in Children</h1>\n    <p>Tests title element as a child instead of using title prop</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Head/WithoutTitle.vue",
    "content": "<script setup lang=\"ts\">\nimport { Head } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <Head>\n    <!-- Head with no title prop -->\n    <meta name=\"test\" content=\"no title provided\" />\n  </Head>\n\n  <div>\n    <h1>Head without Title Prop</h1>\n    <p>Tests that Head works without a title prop</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Head.vue",
    "content": "<script setup lang=\"ts\">\nimport { Head } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <Head title=\"Test Head Component\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <meta name=\"description\" content='This is an \"escape\" example' />\n    <meta name=\"undefined\" :content=\"undefined\" />\n    <!-- @vue-expect-error - The content attribute must be a string, we support passing other types for backwards compatibility -->\n    <meta name=\"number\" :content=\"0\" />\n    <!-- @vue-expect-error -->\n    <meta name=\"boolean\" :content=\"true\" />\n    <!-- @vue-expect-error -->\n    <meta name=\"false\" :content=\"false\" />\n    <!-- @vue-expect-error -->\n    <meta name=\"null\" :content=\"null\" />\n    <!-- @vue-expect-error -->\n    <meta name=\"float\" :content=\"3.14\" />\n    <meta name=\"xss\" content=\"<script>alert('xss')</script>\" />\n    <meta name=\"ampersand\" content=\"Laravel & Inertia\" />\n    <meta name=\"unicode\" content=\"Hélló! 🎉\" />\n  </Head>\n\n  <h1 :style=\"{ fontSize: '40px' }\">Head Component</h1>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/History/Page.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, router } from '@inertiajs/vue3'\n\ndefineProps<{ pageNumber: number; multiByte: string }>()\n</script>\n\n<template>\n  <Link href=\"/history/1\">Page 1</Link>\n  <Link href=\"/history/2\">Page 2</Link>\n  <Link href=\"/history/3\">Page 3</Link>\n  <Link href=\"/history/4\">Page 4</Link>\n  <Link href=\"/history/5\">Page 5</Link>\n\n  <button @click=\"router.clearHistory()\">Clear History</button>\n\n  <div>This is page {{ pageNumber }}.</div>\n  <div>Multi byte character: {{ multiByte }}</div>\n\n  <div style=\"height: 5000px\"></div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/History/Version.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n\ndefineProps<{ pageNumber: number }>()\n</script>\n\n<template>\n  <Link href=\"/history/version/1\">Page 1</Link>\n  <Link href=\"/history/version/2\">Page 2</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/HistoryQuota/Page.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n\ndefineProps<{\n  pageNumber: number\n  largeData: string\n}>()\n</script>\n\n<template>\n  <div>\n    <h1>History Quota Test - Page {{ pageNumber }}</h1>\n    <p>Data size: {{ largeData?.length?.toLocaleString() }} bytes</p>\n\n    <div style=\"margin-top: 20px\">\n      <Link v-for=\"n in 20\" :key=\"n\" :href=\"`/history-quota/${n}`\" style=\"margin-right: 10px\"> Page {{ n }} </Link>\n    </div>\n\n    <div style=\"height: 5000px\"></div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/HistoryThrottle.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, router } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst callCount = ref(0)\n\nconst triggerRapidStateUpdates = () => {\n  for (let i = 0; i < 120; i++) {\n    callCount.value = i + 1\n    router.remember({ value: i }, `key-${i}`)\n  }\n}\n</script>\n\n<template>\n  <div>\n    <h1>History Throttle Test</h1>\n    <p id=\"call-count\">State updates: {{ callCount }}</p>\n    <button id=\"trigger\" @click=\"triggerRapidStateUpdates\">Trigger Rapid State Updates</button>\n    <Link id=\"home-link\" href=\"/\">Go Home</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Home.vue",
    "content": "<script setup lang=\"ts\">\nimport { Head, Link, router } from '@inertiajs/vue3'\nimport { getCurrentInstance } from 'vue'\n\nconst props = defineProps({\n  example: String,\n})\n\nconst visitsMethod = () => {\n  router.visit('/visits/method')\n}\n\nconst visitsReplace = () => {\n  router.get('/visits/replace')\n}\n\nconst redirect = () => {\n  router.post('/redirect')\n}\n\nconst redirectExternal = () => {\n  router.post('/redirect-external')\n}\n\nwindow._inertia_page_key = getCurrentInstance()?.uid\nwindow._inertia_props = props\nwindow._plugin_global_props = getCurrentInstance()?.appContext.config.globalProperties || {}\n</script>\n\n<template>\n  <Head title=\"Home\" />\n\n  <div>\n    <span class=\"text\">This is the Test App Entrypoint page</span>\n\n    <Link href=\"/links/method\" class=\"links-method\">Basic Links</Link>\n    <Link href=\"/links/replace\" class=\"links-replace\">'Replace' Links</Link>\n    <Link href=\"/links/as-component\" class=\"links-as-component\">Custom Component</Link>\n\n    <a href=\"#\" @click.prevent=\"visitsMethod\" class=\"visits-method\">Manual basic visits</a>\n    <a href=\"#\" @click.prevent=\"visitsReplace\" class=\"visits-replace\">Manual 'Replace' visits</a>\n\n    <Link href=\"/redirect\" method=\"post\" class=\"links-redirect\">Internal Redirect Link</Link>\n    <a href=\"#\" @click.prevent=\"redirect\" class=\"visits-redirect\">Manual Redirect visit</a>\n\n    <Link href=\"/redirect-external\" method=\"post\" class=\"links-redirect-external\">External Redirect Link</Link>\n    <a href=\"#\" @click.prevent=\"redirectExternal\" class=\"visits-redirect-external\">Manual External Redirect visit</a>\n\n    <Link id=\"navigate-back\" href=\"/head/mixed\">Go to Mixed Head</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/CustomElement.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n</script>\n\n<template>\n  <InfiniteScroll data=\"users\" as=\"section\" data-testid=\"infinite-scroll-container\">\n    <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n    <template #loading>\n      <div style=\"text-align: center; padding: 20px\">Loading...</div>\n    </template>\n  </InfiniteScroll>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/CustomTriggersRef.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { ref } from 'vue'\nimport { User } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n\nconst tableHeader = ref<HTMLElement>()\nconst tableFooter = ref<HTMLElement>()\nconst tableBody = ref<HTMLElement>()\n</script>\n\n<template>\n  <div style=\"padding: 20px\">\n    <h1>Custom Triggers with Refs Test</h1>\n\n    <InfiniteScroll\n      data=\"users\"\n      :start-element=\"() => tableHeader\"\n      :end-element=\"() => tableFooter\"\n      :items-element=\"() => tableBody\"\n      #default=\"{ loadingPrevious, loadingNext }\"\n    >\n      <div style=\"height: 300px; width: 100%; text-align: center; line-height: 300px; border: 1px solid #ccc\">\n        Spacer\n      </div>\n\n      <table style=\"width: 100%; border-collapse: collapse\">\n        <thead ref=\"tableHeader\" style=\"padding: 10px\">\n          <tr>\n            <th style=\"padding: 12px; border: 1px solid #ccc\">ID</th>\n            <th style=\"padding: 12px; border: 1px solid #ccc\">Name</th>\n          </tr>\n        </thead>\n\n        <tbody ref=\"tableBody\">\n          <tr v-for=\"user in users.data\" :key=\"user.id\" :data-user-id=\"user.id\">\n            <td style=\"padding: 80px 12px; border: 1px solid #ccc\">{{ user.id }}</td>\n            <td style=\"padding: 80px 12px; border: 1px solid #ccc\">{{ user.name }}</td>\n          </tr>\n          <tr v-if=\"loadingPrevious || loadingNext\">\n            <td colspan=\"2\" style=\"padding: 12px; border: 1px solid #ccc; text-align: center\">Loading...</td>\n          </tr>\n        </tbody>\n\n        <tfoot ref=\"tableFooter\" style=\"background: #fdf2e8; padding: 10px\">\n          <tr>\n            <td colspan=\"2\" style=\"padding: 12px; border: 1px solid #ccc; text-align: center\">\n              Table Footer - Triggers when this comes into view\n            </td>\n          </tr>\n        </tfoot>\n      </table>\n\n      <div style=\"height: 300px; width: 100%; text-align: center; line-height: 300px; border: 1px solid #ccc\">\n        Spacer\n      </div>\n    </InfiniteScroll>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/CustomTriggersRefObject.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { ref } from 'vue'\nimport { User } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n\nconst tableHeader = ref<HTMLElement>()\nconst tableFooter = ref<HTMLElement>()\nconst tableBody = ref<HTMLElement>()\n</script>\n\n<template>\n  <div style=\"padding: 20px\">\n    <h1>Custom Triggers with React Ref Objects Test</h1>\n\n    <InfiniteScroll\n      data=\"users\"\n      :start-element=\"() => tableHeader\"\n      :end-element=\"() => tableFooter\"\n      :items-element=\"() => tableBody\"\n      #default=\"{ loadingPrevious, loadingNext }\"\n    >\n      <div style=\"height: 300px; width: 100%; text-align: center; line-height: 300px; border: 1px solid #ccc\">\n        Spacer\n      </div>\n\n      <table style=\"width: 100%; border-collapse: collapse\">\n        <thead ref=\"tableHeader\" style=\"padding: 10px\">\n          <tr>\n            <th style=\"padding: 12px; border: 1px solid #ccc\">ID</th>\n            <th style=\"padding: 12px; border: 1px solid #ccc\">Name</th>\n          </tr>\n        </thead>\n\n        <tbody ref=\"tableBody\">\n          <tr v-for=\"user in users.data\" :key=\"user.id\" :data-user-id=\"user.id\">\n            <td style=\"padding: 80px 12px; border: 1px solid #ccc\">{{ user.id }}</td>\n            <td style=\"padding: 80px 12px; border: 1px solid #ccc\">{{ user.name }}</td>\n          </tr>\n          <tr v-if=\"loadingPrevious || loadingNext\">\n            <td colspan=\"2\" style=\"padding: 12px; border: 1px solid #ccc; text-align: center\">Loading...</td>\n          </tr>\n        </tbody>\n\n        <tfoot ref=\"tableFooter\" style=\"background: #fdf2e8; padding: 10px\">\n          <tr>\n            <td colspan=\"2\" style=\"padding: 12px; border: 1px solid #ccc; text-align: center\">\n              Table Footer - Triggers when this comes into view\n            </td>\n          </tr>\n        </tfoot>\n      </table>\n\n      <div style=\"height: 300px; width: 100%; text-align: center; line-height: 300px; border: 1px solid #ccc\">\n        Spacer\n      </div>\n    </InfiniteScroll>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/CustomTriggersSelector.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n</script>\n\n<template>\n  <div style=\"padding: 20px\">\n    <h1>Custom Triggers with Selectors Test</h1>\n\n    <InfiniteScroll\n      data=\"users\"\n      items-element=\"#table-body\"\n      start-element=\"#table-header\"\n      end-element=\"#table-footer\"\n      #default=\"{ loadingPrevious, loadingNext }\"\n    >\n      <div style=\"height: 300px; width: 100%; text-align: center; line-height: 300px; border: 1px solid #ccc\">\n        Spacer\n      </div>\n\n      <table style=\"width: 100%; border-collapse: collapse\">\n        <thead id=\"table-header\" style=\"padding: 12px\">\n          <tr>\n            <th style=\"padding: 12px; border: 1px solid #ccc\">ID</th>\n            <th style=\"padding: 12px; border: 1px solid #ccc\">Name</th>\n          </tr>\n        </thead>\n\n        <tbody id=\"table-body\">\n          <tr v-for=\"user in users.data\" :key=\"user.id\" :data-user-id=\"user.id\">\n            <td style=\"padding: 80px 12px; border: 1px solid #ccc\">{{ user.id }}</td>\n            <td style=\"padding: 80px 12px; border: 1px solid #ccc\">{{ user.name }}</td>\n          </tr>\n\n          <tr v-if=\"loadingPrevious || loadingNext\">\n            <td colspan=\"2\" style=\"padding: 12px; border: 1px solid #ccc; text-align: center\">Loading...</td>\n          </tr>\n        </tbody>\n\n        <tfoot id=\"table-footer\" style=\"padding: 12px\">\n          <tr>\n            <td colspan=\"2\" style=\"padding: 12px; border: 1px solid #ccc; text-align: center\">\n              Table Footer - Triggers when this comes into view\n            </td>\n          </tr>\n        </tfoot>\n      </table>\n\n      <div style=\"height: 300px; width: 100%; text-align: center; line-height: 300px; border: 1px solid #ccc\">\n        Spacer\n      </div>\n    </InfiniteScroll>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/DataTable.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n</script>\n\n<template>\n  <InfiniteScroll data=\"users\" items-element=\"tbody\" #default=\"{ loadingPrevious, loadingNext }\">\n    <table style=\"width: 100%; border-collapse: collapse\">\n      <thead>\n        <tr>\n          <th style=\"padding: 8px; border: 1px solid #ccc\">ID</th>\n          <th style=\"padding: 8px; border: 1px solid #ccc\">Name</th>\n        </tr>\n      </thead>\n\n      <tbody>\n        <tr v-for=\"user in users.data\" :key=\"user.id\" :data-user-id=\"user.id\">\n          <td style=\"padding: 8px; border: 1px solid #ccc\">{{ user.id }}</td>\n          <td style=\"padding: 8px; border: 1px solid #ccc\">{{ user.name }}</td>\n        </tr>\n      </tbody>\n\n      <tfoot>\n        <tr v-if=\"loadingPrevious || loadingNext\">\n          <td :colspan=\"2\" style=\"padding: 8px; border: 1px solid #ccc; text-align: center\">Loading...</td>\n        </tr>\n      </tfoot>\n    </table>\n  </InfiniteScroll>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/Deferred.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, InfiniteScroll } from '@inertiajs/vue3'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users?: { data: User[] }\n}>()\n</script>\n\n<template>\n  <Deferred data=\"users\">\n    <template #fallback>\n      <div>Loading deferred scroll prop...</div>\n    </template>\n\n    <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\" manual>\n      <template #previous=\"{ loading, fetch, hasMore }\">\n        <p>Has more previous items: {{ hasMore }}</p>\n\n        <button @click=\"fetch\">\n          {{ loading ? 'Loading previous items...' : 'Load previous items' }}\n        </button>\n      </template>\n\n      <UserCard v-for=\"user in users!.data\" :key=\"user.id\" :user=\"user\" />\n\n      <template #next=\"{ loading, fetch, hasMore }\">\n        <p>Has more next items: {{ hasMore }}</p>\n\n        <button @click=\"fetch\">\n          {{ loading ? 'Loading next items...' : 'Load next items' }}\n        </button>\n      </template>\n    </InfiniteScroll>\n  </Deferred>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/DualContainers.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users1: { data: User[] }\n  users2: { data: User[] }\n}>()\n</script>\n\n<template>\n  <div style=\"padding: 20px\">\n    <div style=\"display: flex; gap: 20px\">\n      <!-- First scroll container -->\n      <div style=\"flex: 1\">\n        <h2>Users1 Container</h2>\n        <div\n          data-testid=\"scroll-container-1\"\n          style=\"\n            height: 400px;\n            width: 100%;\n            border: 2px solid #3b82f6;\n            overflow-y: auto;\n            background: #f0f9ff;\n            padding: 10px;\n          \"\n        >\n          <InfiniteScroll data=\"users1\" style=\"display: grid; gap: 10px\">\n            <UserCard v-for=\"user in users1.data\" :key=\"user.id\" :user=\"user\" />\n\n            <template #loading>\n              <div style=\"text-align: center; padding: 20px; color: #3b82f6\">Loading more users1...</div>\n            </template>\n          </InfiniteScroll>\n        </div>\n      </div>\n\n      <!-- Second scroll container -->\n      <div style=\"flex: 1\">\n        <h2>Users2 Container</h2>\n        <div\n          data-testid=\"scroll-container-2\"\n          style=\"\n            height: 400px;\n            width: 100%;\n            border: 2px solid #ef4444;\n            overflow-y: auto;\n            background: #fef2f2;\n            padding: 10px;\n          \"\n        >\n          <InfiniteScroll data=\"users2\" style=\"display: grid; gap: 10px\">\n            <UserCard v-for=\"user in users2.data\" :key=\"user.id\" :user=\"user\" />\n\n            <template #loading>\n              <div style=\"text-align: center; padding: 20px; color: #ef4444\">Loading more users2...</div>\n            </template>\n          </InfiniteScroll>\n        </div>\n      </div>\n    </div>\n\n    <p style=\"margin-top: 20px\">Content below the scroll containers to verify page doesn't scroll.</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/DualSibling.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users1: { data: User[] }\n  users2: { data: User[] }\n}>()\n</script>\n\n<template>\n  <div style=\"padding: 20px\">\n    <h1>Dual Sibling InfiniteScroll</h1>\n    <p style=\"margin-bottom: 20px\">Two InfiniteScroll components side by side, sharing the window scroll</p>\n\n    <div style=\"display: grid; grid-template-columns: 1fr 1fr; gap: 40px\">\n      <div>\n        <h2>Users 1</h2>\n        <InfiniteScroll data=\"users1\" style=\"display: grid; gap: 20px\" manual>\n          <UserCard v-for=\"user in users1.data\" :key=\"user.id\" :user=\"user\" />\n\n          <template #next=\"{ loading, fetch }\">\n            <div style=\"text-align: center; padding: 20px\">\n              <button @click=\"fetch\" :disabled=\"loading\">\n                {{ loading ? 'Loading...' : 'Load More Users 1' }}\n              </button>\n            </div>\n          </template>\n        </InfiniteScroll>\n      </div>\n\n      <div>\n        <h2>Users 2</h2>\n        <InfiniteScroll data=\"users2\" style=\"display: grid; gap: 20px\" manual>\n          <UserCard v-for=\"user in users2.data\" :key=\"user.id\" :user=\"user\" />\n\n          <template #next=\"{ loading, fetch }\">\n            <div style=\"text-align: center; padding: 20px\">\n              <button @click=\"fetch\" :disabled=\"loading\">\n                {{ loading ? 'Loading...' : 'Load More Users 2' }}\n              </button>\n            </div>\n          </template>\n        </InfiniteScroll>\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/Empty.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n</script>\n\n<template>\n  <div>\n    <h1>Empty Dataset Test</h1>\n    <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\">\n      <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n      <div v-if=\"users.data.length === 0\" style=\"text-align: center; padding: 40px; color: #666\">No users found.</div>\n\n      <template #loading>\n        <div style=\"text-align: center; padding: 20px\">Loading...</div>\n      </template>\n    </InfiniteScroll>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/Filtering.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll, Link, useForm } from '@inertiajs/vue3'\nimport { debounce } from 'lodash-es'\nimport { watch } from 'vue'\nimport { User, default as UserCard } from './UserCard.vue'\n\nconst props = defineProps<{\n  users: { data: User[] }\n  preserveState: boolean\n  filter?: string\n  search?: string\n}>()\n\nconst form = useForm({\n  filter: undefined,\n  page: undefined,\n  search: props.search,\n})\n\nwatch(\n  () => form.search,\n  debounce(\n    () =>\n      form.get(\n        '',\n        props.preserveState\n          ? {\n              preserveState: true,\n              replace: true,\n              only: ['users', 'search', 'filter'],\n              reset: ['users'],\n            }\n          : {\n              replace: true,\n            },\n      ),\n    250,\n  ),\n)\n</script>\n\n<template>\n  <div>\n    <div style=\"margin-bottom: 20px; display: flex; gap: 10px\">\n      <Link href=\"\"> No Filter </Link>\n      <Link href=\"?filter=a-m\"> A-M </Link>\n      <Link href=\"?filter=n-z\"> N-Z </Link>\n      <div>Current filter: {{ filter || 'none' }}</div>\n      <div>Current search: {{ search || 'none' }}</div>\n      <input v-model=\"form.search\" placeholder=\"Search...\" />\n    </div>\n\n    <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\">\n      <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n      <template #loading>\n        <div style=\"text-align: center; padding: 20px\">Loading...</div>\n      </template>\n    </InfiniteScroll>\n\n    <div style=\"margin-top: 20px; display: flex; gap: 10px\">\n      <Link href=\"\"> No Filter </Link>\n      <Link href=\"?filter=a-m\"> A-M </Link>\n      <Link href=\"?filter=n-z\"> N-Z </Link>\n      <div>Current filter: {{ filter || 'none' }}</div>\n      <div>Current search: {{ search || 'none' }}</div>\n      <input v-model=\"form.search\" placeholder=\"Search...\" />\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/FilteringManual.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll, useForm } from '@inertiajs/vue3'\nimport { debounce } from 'lodash-es'\nimport { watch } from 'vue'\nimport { User, default as UserCard } from './UserCard.vue'\n\nconst props = defineProps<{\n  users: { data: User[] }\n  search?: string\n}>()\n\nconst form = useForm({\n  search: props.search,\n})\n\nwatch(\n  () => form.search,\n  debounce(\n    () =>\n      form.get('', {\n        preserveState: true,\n        replace: true,\n        only: ['users', 'search'],\n        reset: ['users'],\n      }),\n    250,\n  ),\n)\n</script>\n\n<template>\n  <div>\n    <div style=\"margin-bottom: 20px; display: flex; gap: 10px\">\n      <div>Current search: {{ search || 'none' }}</div>\n      <input v-model=\"form.search\" placeholder=\"Search...\" />\n    </div>\n\n    <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\" manual>\n      <template #previous=\"{ loading, fetch, hasMore }\">\n        <p>Has more previous items: {{ hasMore }}</p>\n\n        <button @click=\"fetch\">\n          {{ loading ? 'Loading previous items...' : 'Load previous items' }}\n        </button>\n      </template>\n\n      <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n      <template #next=\"{ loading, fetch, hasMore }\">\n        <p>Has more next items: {{ hasMore }}</p>\n\n        <button @click=\"fetch\">\n          {{ loading ? 'Loading next items...' : 'Load next items' }}\n        </button>\n      </template>\n    </InfiniteScroll>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/FilteringReset.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll, useForm } from '@inertiajs/vue3'\nimport { debounce } from 'lodash-es'\nimport { watch } from 'vue'\nimport { User, default as UserCard } from './UserCard.vue'\n\nconst props = defineProps<{\n  users: { data: User[] }\n  search?: string\n}>()\n\nconst form = useForm({\n  search: props.search,\n})\n\nwatch(\n  () => form.search,\n  debounce(\n    () =>\n      form.get('', {\n        preserveState: true,\n        replace: true,\n        only: ['users', 'search'],\n        reset: ['users'],\n      }),\n    250,\n  ),\n)\n</script>\n\n<template>\n  <div>\n    <div style=\"margin-bottom: 20px; display: flex; gap: 10px\">\n      <div>Current search: {{ search || 'none' }}</div>\n      <input v-model=\"form.search\" placeholder=\"Search...\" />\n    </div>\n\n    <InfiniteScroll data=\"users\" :buffer=\"2000\" style=\"display: grid; gap: 20px\">\n      <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n      <template #loading>\n        <div style=\"text-align: center; padding: 20px\">Loading...</div>\n      </template>\n    </InfiniteScroll>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/Grid.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n</script>\n\n<template>\n  <InfiniteScroll data=\"users\" style=\"display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px\">\n    <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n    <template #loading>\n      <div style=\"grid-column: 1 / -1; text-align: center; padding: 20px\">Loading more users...</div>\n    </template>\n  </InfiniteScroll>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/HorizontalScroll.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n</script>\n\n<template>\n  <div style=\"height: 120px; overflow-x: scroll; display: flex; width: 100vw\">\n    <InfiniteScroll data=\"users\" style=\"display: flex; gap: 20px; height: 120px\">\n      <div\n        v-for=\"user in users.data\"\n        :key=\"user.id\"\n        :data-user-id=\"user.id\"\n        style=\"\n          min-width: 200px;\n          height: 100px;\n          border: 1px solid #ccc;\n          background-color: #f5f5f5;\n          display: flex;\n          align-items: center;\n          justify-content: center;\n          flex: none;\n        \"\n      >\n        {{ user.name }}\n      </div>\n\n      <template #loading>\n        <div\n          style=\"\n            min-width: 150px;\n            height: 100px;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            border: 1px dashed #ccc;\n            margin-left: 20px;\n            margin-right: 20px;\n          \"\n        >\n          Loading...\n        </div>\n      </template>\n    </InfiniteScroll>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/InfiniteScrollWithLink.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll, Link } from '@inertiajs/vue3'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n</script>\n\n<template>\n  <div>\n    <Link href=\"/infinite-scroll\">Go back to Links</Link>\n    <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\">\n      <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n      <template #loading>\n        <div style=\"text-align: center; padding: 20px\">Loading...</div>\n      </template>\n    </InfiniteScroll>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/InvisibleFirstChild.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n</script>\n\n<template>\n  <div>\n    <h1>Infinite Scroll with Invisible First Child</h1>\n\n    <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\">\n      <div style=\"display: none\">Hidden first element</div>\n\n      <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n      <template #loading>\n        <div style=\"text-align: center; padding: 20px\">Loading...</div>\n      </template>\n    </InfiniteScroll>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/Links.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <Link href=\"/infinite-scroll-with-link\">Go to InfiniteScrollWithLink</Link>\n    <Link href=\"/infinite-scroll-with-link\" prefetch>Go to InfiniteScrollWithLink (Prefetch)</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/Manual.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n</script>\n\n<template>\n  <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\" manual>\n    <template #previous=\"{ loading, fetch, hasMore }\">\n      <p>Has more previous items: {{ hasMore }}</p>\n\n      <button @click=\"fetch\">\n        {{ loading ? 'Loading previous items...' : 'Load previous items' }}\n      </button>\n    </template>\n\n    <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n    <template #next=\"{ loading, fetch, hasMore }\">\n      <p>Has more next items: {{ hasMore }}</p>\n\n      <button @click=\"fetch\">\n        {{ loading ? 'Loading next items...' : 'Load next items' }}\n      </button>\n    </template>\n  </InfiniteScroll>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/ManualAfter.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n</script>\n\n<template>\n  <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\" :manual-after=\"2\">\n    <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n    <template #next=\"{ fetch, manualMode, loading }\">\n      <p v-if=\"loading\">Loading...</p>\n\n      <p>Manual mode: {{ manualMode }}</p>\n\n      <button v-if=\"manualMode\" @click=\"fetch\">Load next items...</button>\n    </template>\n  </InfiniteScroll>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/ManualReverse.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { computed } from 'vue'\nimport { User, default as UserCard } from './UserCard.vue'\n\nconst props = defineProps<{\n  users: { data: User[] }\n}>()\n\nconst reversedUsers = computed(() => [...props.users.data].reverse())\n</script>\n\n<template>\n  <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\" reverse only-next>\n    <template #previous=\"{ fetch, hasMore }\">\n      <button v-if=\"hasMore\" @click=\"fetch\" style=\"padding: 10px 20px; font-size: 16px; cursor: pointer\">\n        Load previous page (rendered at the end because of reverse mode)\n      </button>\n    </template>\n\n    <UserCard v-for=\"user in reversedUsers\" :key=\"user.id\" :user=\"user\" />\n\n    <template #next=\"{ fetch, hasMore }\">\n      <button @click=\"fetch\" style=\"padding: 10px 20px; font-size: 16px; cursor: pointer\" v-if=\"hasMore\">\n        Load next page (rendered at the start because of reverse mode)\n      </button>\n    </template>\n  </InfiniteScroll>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/ManualToggle.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { ref } from 'vue'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n\nconst manual = ref(false)\n</script>\n\n<template>\n  <div>\n    <p>\n      <label>\n        <input type=\"checkbox\" v-model=\"manual\" />\n        Manual mode: {{ manual }}\n      </label>\n    </p>\n\n    <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\" :manual=\"manual\">\n      <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n      <template #loading>\n        <div style=\"text-align: center; padding: 20px\">Loading...</div>\n      </template>\n    </InfiniteScroll>\n\n    <p>Total items on page: {{ users.data.length }}</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/OverflowX.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n</script>\n\n<template>\n  <div style=\"overflow-x: hidden\">\n    <InfiniteScroll data=\"users\">\n      <div v-for=\"user in users.data\" :key=\"user.id\" :data-user-id=\"user.id\">\n        <div>{{ user.name }}</div>\n      </div>\n    </InfiniteScroll>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/PreserveUrl.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n</script>\n\n<template>\n  <InfiniteScroll data=\"users\" :preserveUrl=\"true\" style=\"display: grid; gap: 20px\">\n    <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n    <template #loading>\n      <div style=\"text-align: center; padding: 20px\">Loading...</div>\n    </template>\n  </InfiniteScroll>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/ProgrammaticRef.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { onMounted, ref } from 'vue'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n\nconst infRef = ref()\nconst hasPrevious = ref(false)\nconst hasNext = ref(false)\n\nconst updateStates = () => {\n  hasPrevious.value = infRef.value.hasPrevious()\n  hasNext.value = infRef.value.hasNext()\n}\n\nconst fetchNext = async () => {\n  infRef.value.fetchNext({ onFinish: updateStates })\n}\n\nconst fetchPrevious = async () => {\n  infRef.value.fetchPrevious({ onFinish: updateStates })\n}\n\nonMounted(updateStates)\n</script>\n\n<template>\n  <div>\n    <h1>Programmatic Ref Test</h1>\n\n    <div style=\"margin-bottom: 20px\">\n      <p>Has more previous items: {{ hasPrevious }}</p>\n      <p>Has more next items: {{ hasNext }}</p>\n\n      <div style=\"display: flex; gap: 10px; margin: 10px 0\">\n        <button @click=\"fetchPrevious\">Load Previous (Ref)</button>\n        <button @click=\"fetchNext\">Load Next (Ref)</button>\n      </div>\n    </div>\n\n    <InfiniteScroll ref=\"infRef\" data=\"users\" style=\"display: grid; gap: 20px\" manual>\n      <template #loading>\n        <div style=\"text-align: center; padding: 20px\">Loading...</div>\n      </template>\n\n      <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n    </InfiniteScroll>\n\n    <p>Total items on page: {{ users.data.length }}</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/ReloadUnrelated.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll, router } from '@inertiajs/vue3'\nimport UserCard, { User } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n  time: number\n}>()\n\nconst reloadTime = () => {\n  router.reload({ only: ['time'] })\n}\n</script>\n\n<template>\n  <div>\n    <div>\n      <button @click=\"reloadTime\" id=\"reload-button\">Reload Time</button>\n      <span id=\"time-display\">Current time: {{ time }}</span>\n    </div>\n\n    <InfiniteScroll data=\"users\">\n      <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n    </InfiniteScroll>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/RememberState.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll, Link, router } from '@inertiajs/vue3'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n\nfunction prependUser(id: number) {\n  router.prependToProp('users.data', { id, name: `User ${id}` })\n}\n</script>\n\n<template>\n  <div style=\"margin-bottom: 40px; padding: 20px; border-top: 2px solid #ccc\">\n    <div style=\"margin-bottom: 20px\">\n      <button @click.prevent=\"prependUser(0)\" style=\"margin-right: 10px\">Prepend User '0'</button>\n      <button @click.prevent=\"prependUser(-1)\" style=\"margin-right: 10px\">Prepend User '-1'</button>\n    </div>\n    <Link href=\"/home\">Go Home</Link>\n  </div>\n\n  <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\" :manual-after=\"2\">\n    <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n    <template #next=\"{ fetch, manualMode, loading }\">\n      <p v-if=\"loading\">Loading...</p>\n\n      <p>Manual mode: {{ manualMode }}</p>\n\n      <button v-if=\"manualMode\" @click.prevent=\"fetch\">Load next items...</button>\n    </template>\n  </InfiniteScroll>\n\n  <div style=\"margin-top: 40px; padding: 20px; border-top: 2px solid #ccc\">\n    <Link href=\"/home\">Go to Home</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/Reverse.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { computed } from 'vue'\nimport { User, default as UserCard } from './UserCard.vue'\n\nconst props = defineProps<{\n  users: { data: User[] }\n}>()\n\nconst reversedUsers = computed(() => [...props.users.data].reverse())\n</script>\n\n<template>\n  <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\" reverse :auto-scroll=\"false\">\n    <UserCard v-for=\"user in reversedUsers\" :key=\"user.id\" :user=\"user\" />\n\n    <template #loading>\n      <div style=\"text-align: center; padding: 20px\">Loading...</div>\n    </template>\n  </InfiniteScroll>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/ReverseShortContent.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { computed } from 'vue'\n\nconst props = defineProps<{\n  users: { data: { id: number; name: string }[] }\n}>()\n\nconst reversedUsers = computed(() => [...props.users.data].reverse())\n</script>\n\n<template>\n  <div style=\"display: flex; flex-direction: column; height: 100vh\">\n    <div style=\"padding: 10px; border-bottom: 1px solid #ccc; flex-shrink: 0\">Header</div>\n\n    <div data-testid=\"scroll-container\" style=\"flex: 1; overflow-y: auto\">\n      <InfiniteScroll data=\"users\" style=\"display: grid; gap: 4px; padding: 20px\" reverse>\n        <div\n          v-for=\"user in reversedUsers\"\n          :key=\"user.id\"\n          :data-user-id=\"user.id\"\n          style=\"padding: 4px 8px; border: 1px solid #ddd; font-size: 13px\"\n        >\n          {{ user.name }}\n        </div>\n\n        <template #loading>\n          <div style=\"text-align: center; padding: 10px\">Loading...</div>\n        </template>\n      </InfiniteScroll>\n    </div>\n\n    <div style=\"padding: 10px; border-top: 1px solid #ccc; flex-shrink: 0\">Footer</div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/ScrollContainer.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n</script>\n\n<template>\n  <div style=\"padding: 20px\">\n    <h1>Infinite Scroll in Container</h1>\n    <p>This component scrolls within a fixed-height container, not the full page.</p>\n\n    <!-- Fixed height scrollable container -->\n    <div\n      data-testid=\"scroll-container\"\n      style=\"height: 400px; width: 100%; border: 2px solid #ccc; overflow-y: auto; background: #f9f9f9; padding: 10px\"\n    >\n      <InfiniteScroll data=\"users\" style=\"display: grid; gap: 10px\">\n        <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n        <template #loading>\n          <div style=\"text-align: center; padding: 20px; color: #666\">Loading more users...</div>\n        </template>\n      </InfiniteScroll>\n    </div>\n\n    <p style=\"margin-top: 20px\">Content below the scroll container to verify page doesn't scroll.</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/ShortContent.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n</script>\n\n<template>\n  <InfiniteScroll data=\"users\" items-element=\"tbody\">\n    <table style=\"width: 100%; border-collapse: collapse\">\n      <tbody>\n        <tr v-for=\"user in users.data\" :key=\"user.id\" :data-user-id=\"user.id\">\n          <td style=\"padding: 10px; border: 1px solid #ccc\">{{ user.id }}</td>\n          <td style=\"padding: 10px; border: 1px solid #ccc\">{{ user.name }}</td>\n        </tr>\n      </tbody>\n    </table>\n  </InfiniteScroll>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/Toggles.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { ref } from 'vue'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n\nconst manual = ref(false)\nconst preserveUrl = ref(false)\nconst triggerMode = ref<'onlyPrevious' | 'onlyNext' | 'both'>('onlyNext')\n</script>\n\n<template>\n  <div>\n    <div style=\"display: flex; gap: 10px\">\n      <p>\n        <label>\n          <input type=\"checkbox\" v-model=\"manual\" />\n          Manual mode: {{ manual }}\n        </label>\n      </p>\n\n      <p>\n        <label>\n          <input type=\"checkbox\" v-model=\"preserveUrl\" />\n          Preserve URL: {{ preserveUrl }}\n        </label>\n      </p>\n\n      <p>\n        <label>\n          Trigger mode: {{ triggerMode }}\n          <select v-model=\"triggerMode\">\n            <option value=\"onlyPrevious\">onlyPrevious</option>\n            <option value=\"onlyNext\">onlyNext</option>\n            <option value=\"both\">both</option>\n          </select>\n        </label>\n      </p>\n    </div>\n\n    <InfiniteScroll\n      data=\"users\"\n      style=\"display: grid; gap: 20px\"\n      :manual=\"manual\"\n      :preserve-url=\"preserveUrl\"\n      :only-next=\"triggerMode === 'onlyNext'\"\n      :only-previous=\"triggerMode === 'onlyPrevious'\"\n    >\n      <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n      <template #loading>\n        <div style=\"text-align: center; padding: 20px\">Loading...</div>\n      </template>\n    </InfiniteScroll>\n\n    <p>Total items on page: {{ users.data.length }}</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/TriggerBoth.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n</script>\n\n<template>\n  <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\">\n    <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n    <template #loading>\n      <div style=\"text-align: center; padding: 20px\">Loading...</div>\n    </template>\n  </InfiniteScroll>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/TriggerEndBuffer.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n</script>\n\n<template>\n  <InfiniteScroll data=\"users\" :buffer=\"200\" only-next style=\"display: grid; gap: 20px\">\n    <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n    <template #loading>\n      <div style=\"text-align: center; padding: 20px\">Loading...</div>\n    </template>\n  </InfiniteScroll>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/TriggerStartBuffer.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n</script>\n\n<template>\n  <InfiniteScroll data=\"users\" :buffer=\"200\" only-previous style=\"display: grid; gap: 20px\">\n    <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n    <template #loading>\n      <div style=\"text-align: center; padding: 20px\">Loading...</div>\n    </template>\n  </InfiniteScroll>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/TriggerToggle.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll } from '@inertiajs/vue3'\nimport { ref } from 'vue'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n\nconst triggerMode = ref<'onlyPrevious' | 'onlyNext' | 'both'>('onlyPrevious')\n</script>\n\n<template>\n  <div>\n    <p>\n      <label>\n        <select v-model=\"triggerMode\">\n          <option value=\"onlyPrevious\">onlyPrevious</option>\n          <option value=\"onlyNext\">onlyNext</option>\n          <option value=\"both\">both</option>\n        </select>\n        Trigger mode: {{ triggerMode }}\n      </label>\n    </p>\n\n    <InfiniteScroll\n      data=\"users\"\n      style=\"display: grid; gap: 20px\"\n      :only-next=\"triggerMode === 'onlyNext'\"\n      :only-previous=\"triggerMode === 'onlyPrevious'\"\n    >\n      <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n      <template #loading>\n        <div style=\"text-align: center; padding: 20px\">Loading...</div>\n      </template>\n    </InfiniteScroll>\n\n    <p>Total items on page: {{ users.data.length }}</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/UpdateQueryString.vue",
    "content": "<script setup lang=\"ts\">\nimport { InfiniteScroll, usePage } from '@inertiajs/vue3'\nimport { User, default as UserCard } from './UserCard.vue'\n\ndefineProps<{\n  users: { data: User[] }\n}>()\n\nconst page = usePage()\n\nwindow.testing = {\n  ...(window.testing || {}),\n  get pageUrl() {\n    return page.url\n  },\n}\n</script>\n\n<template>\n  <InfiniteScroll data=\"users\" style=\"display: grid; gap: 20px\">\n    <UserCard v-for=\"user in users.data\" :key=\"user.id\" :user=\"user\" />\n\n    <template #loading>\n      <div style=\"text-align: center; padding: 20px\">Loading...</div>\n    </template>\n  </InfiniteScroll>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/InfiniteScroll/UserCard.vue",
    "content": "<script setup lang=\"ts\">\nexport type User = {\n  id: number\n  name: string\n}\n\ndefineProps<{\n  user: User\n}>()\n</script>\n\n<template>\n  <div\n    v-text=\"user.name\"\n    :data-user-id=\"user.id\"\n    :style=\"{\n      height: '15vh',\n      border: '1px solid #ccc',\n      backgroundColor: `rgba(150,150,150,${user.id / 40})`,\n      color: 'green',\n      display: 'flex',\n      alignItems: 'center',\n      justifyContent: 'center',\n    }\"\n  />\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/AsComponent.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\nimport { defineComponent, h, ref } from 'vue'\n\nconst CustomButton = defineComponent({\n  name: 'CustomButton',\n  render() {\n    return h(\n      'button',\n      {\n        style: {\n          backgroundColor: 'blue',\n          color: 'white',\n          padding: '10px',\n        },\n      },\n      this.$slots.default?.(),\n    )\n  },\n})\n\ndefineProps({\n  page: Number,\n})\n\ndeclare global {\n  interface Window {\n    componentEvents: Array<{ eventName: string; data: unknown; timestamp: number }>\n  }\n}\n\nwindow.componentEvents = []\n\nconst trackEvent = (eventName: string, data: unknown = null) => {\n  window.componentEvents.push({ eventName, data, timestamp: Date.now() })\n}\n\nconst state = ref(crypto.randomUUID())\n</script>\n\n<template>\n  <div>\n    <h1>Link Custom Component - Page {{ page }}</h1>\n    <p id=\"state\">State: {{ state }}</p>\n    <Link :as=\"CustomButton\" href=\"/dump/get\" class=\"get\"> GET Custom Component </Link>\n    <Link :as=\"CustomButton\" method=\"post\" href=\"/dump/post\" class=\"post\"> POST Custom Component </Link>\n    <Link :as=\"CustomButton\" method=\"post\" href=\"/dump/post\" :data=\"{ test: 'data' }\" class=\"data\">\n      Custom Component with Data\n    </Link>\n    <Link :as=\"CustomButton\" href=\"/dump/get\" :headers=\"{ 'X-Test': 'header' }\" class=\"headers\">\n      Custom Component with Headers\n    </Link>\n    <Link :as=\"CustomButton\" href=\"/links/as-component/2\" :preserve-state=\"true\" class=\"preserve\">\n      Custom Component with Preserve State\n    </Link>\n    <Link :as=\"CustomButton\" href=\"/links/as-component/3\" :replace=\"true\" class=\"replace\"\n      >Custom Component with Replace</Link\n    >\n    <Link\n      :as=\"CustomButton\"\n      href=\"/dump/get\"\n      @start=\"(event) => trackEvent('onStart', event)\"\n      @finish=\"(event) => trackEvent('onFinish', event)\"\n      @success=\"(page) => trackEvent('onSuccess', page)\"\n      class=\"events\"\n    >\n      Custom Component with Events\n    </Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/AsElement.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\ndefineProps({\n  page: Number,\n})\n\ndeclare global {\n  interface Window {\n    componentEvents: Array<{ eventName: string; data: unknown; timestamp: number }>\n  }\n}\n\nwindow.componentEvents = []\n\nconst trackEvent = (eventName: string, data: unknown = null) => {\n  window.componentEvents.push({ eventName, data, timestamp: Date.now() })\n}\n\nconst state = ref(crypto.randomUUID())\n</script>\n\n<template>\n  <div>\n    <h1>Link Custom Element - Page {{ page }}</h1>\n    <p id=\"state\">State: {{ state }}</p>\n    <Link as=\"div\" href=\"/dump/get\" class=\"get\" style=\"background-color: blue; color: white; padding: 10px\">\n      GET Custom Element\n    </Link>\n    <Link as=\"div\" method=\"post\" href=\"/dump/post\" class=\"post\"> POST Custom Element </Link>\n    <Link as=\"div\" method=\"post\" href=\"/dump/post\" :data=\"{ test: 'data' }\" class=\"data\">\n      Custom Element with Data\n    </Link>\n    <Link as=\"div\" href=\"/dump/get\" :headers=\"{ 'X-Test': 'header' }\" class=\"headers\">\n      Custom Element with Headers\n    </Link>\n    <Link as=\"div\" href=\"/links/as-element/2\" :preserve-state=\"true\" class=\"preserve\">\n      Custom Element with Preserve State\n    </Link>\n    <Link as=\"div\" href=\"/links/as-element/3\" :replace=\"true\" class=\"replace\">Custom Element with Replace</Link>\n    <Link\n      as=\"div\"\n      href=\"/dump/get\"\n      @start=\"(event) => trackEvent('onStart', event)\"\n      @finish=\"(event) => trackEvent('onFinish', event)\"\n      @success=\"(page) => trackEvent('onSuccess', page)\"\n      class=\"events\"\n    >\n      Custom Element with Events\n    </Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/AsWarning.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Method } from '@inertiajs/core'\nimport { Link } from '@inertiajs/vue3'\n\ndefineProps<{\n  method: Method\n}>()\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the links page that demonstrates inertia-links with an 'as' warning</span>\n\n    <Link :method=\"method\" href=\"/example\" class=\"get\">{{ method }} Link</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/AsWarningFalse.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Method } from '@inertiajs/core'\nimport { Link } from '@inertiajs/vue3'\n\ndefineProps<{\n  method: Method\n}>()\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the links page that demonstrates inertia-links without the 'as' warning</span>\n\n    <Link :method=\"method\" href=\"/example\" class=\"get\" as=\"button\">{{ method }} button Link</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/AutomaticCancellation.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the links page that demonstrates that only one visit can be active at a time</span>\n    <Link href=\"/sleep\" class=\"visit\" @cancel=\"() => console.log('cancelled')\" @start=\"() => console.log('started')\"\n      >Link</Link\n    >\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/CancelSyncRequest.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n\ndefineProps({\n  page: Number,\n})\n</script>\n\n<template>\n  <div>\n    <h1 style=\"font-size: 40px\">Page {{ page }}</h1>\n\n    <Link href=\"/links/cancel-sync-request/1\"> Go to Page 1 </Link>\n    <Link href=\"/links/cancel-sync-request/2\"> Go to Page 2 </Link>\n    <Link href=\"/links/cancel-sync-request/3\"> Go to Page 3 </Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/Data/AutoConverted.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n\nconst linkData = {\n  file: new File([], 'example.jpg'),\n  foo: 'bar',\n}\n</script>\n\n<template>\n  <div>\n    <span class=\"text\"\n      >This is the links page that demonstrates the automatic conversion of plain objects to form-data</span\n    >\n\n    <Link method=\"get\" href=\"/dump/get\" :data=\"linkData\" class=\"get\">GET Link</Link>\n    <Link as=\"button\" method=\"post\" href=\"/dump/post\" :data=\"linkData\" class=\"post\">POST Link</Link>\n    <Link as=\"button\" method=\"put\" href=\"/dump/put\" :data=\"linkData\" class=\"put\">PUT Link</Link>\n    <Link as=\"button\" method=\"patch\" href=\"/dump/patch\" :data=\"linkData\" class=\"patch\">PATCH Link</Link>\n    <Link as=\"button\" method=\"delete\" href=\"/dump/delete\" :data=\"linkData\" class=\"delete\">DELETE Link</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/Data/FormData.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\nimport { onMounted, ref } from 'vue'\n\nconst linkData = ref(new FormData())\n\nonMounted(() => {\n  linkData.value.append('bar', 'baz')\n})\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the links page that demonstrates passing data through FormData objects</span>\n\n    <Link method=\"get\" href=\"/dump/get\" :data=\"linkData\" class=\"get\">GET Link</Link>\n    <Link as=\"button\" method=\"post\" href=\"/dump/post\" :data=\"linkData\" class=\"post\">POST Link</Link>\n    <Link as=\"button\" method=\"put\" href=\"/dump/put\" :data=\"linkData\" class=\"put\">PUT Link</Link>\n    <Link as=\"button\" method=\"patch\" href=\"/dump/patch\" :data=\"linkData\" class=\"patch\">PATCH Link</Link>\n    <Link as=\"button\" method=\"delete\" href=\"/dump/delete\" :data=\"linkData\" class=\"delete\">DELETE Link</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/Data/Object.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the links page that demonstrates passing data through plain objects</span>\n\n    <Link method=\"get\" href=\"/dump/get\" :data=\"{ foo: 'get' }\" class=\"get\">GET Link</Link>\n    <Link as=\"button\" method=\"post\" href=\"/dump/post\" :data=\"{ bar: 'post' }\" class=\"post\">POST Link</Link>\n    <Link as=\"button\" method=\"put\" href=\"/dump/put\" :data=\"{ baz: 'put' }\" class=\"put\">PUT Link</Link>\n    <Link as=\"button\" method=\"patch\" href=\"/dump/patch\" :data=\"{ foo: 'patch' }\" class=\"patch\">PATCH Link</Link>\n    <Link as=\"button\" method=\"delete\" href=\"/dump/delete\" :data=\"{ bar: 'delete' }\" class=\"delete\">DELETE Link</Link>\n\n    <Link href=\"/dump/get\" :data=\"{ a: ['b', 'c'] }\" class=\"qsaf-default\">QSAF Defaults</Link>\n    <Link href=\"/dump/get\" :data=\"{ a: ['b', 'c'] }\" queryStringArrayFormat=\"indices\" class=\"qsaf-indices\"\n      >QSAF Indices</Link\n    >\n    <Link href=\"/dump/get\" :data=\"{ a: ['b', 'c'] }\" queryStringArrayFormat=\"brackets\" class=\"qsaf-brackets\"\n      >QSAF Brackets</Link\n    >\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/DataLoading.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <Link href=\"/sleep\" class=\"get\">First</Link>\n    <Link href=\"/sleep\" class=\"get\">Second</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/Headers.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the links page that demonstrates passing custom headers</span>\n    <Link href=\"/dump/get\" class=\"default\">Standard visit Link</Link>\n\n    <Link method=\"get\" href=\"/dump/get\" :headers=\"{ foo: 'bar' }\" class=\"custom\">GET Link</Link>\n    <Link\n      as=\"button\"\n      method=\"post\"\n      href=\"/dump/post\"\n      :headers=\"{ bar: 'baz', 'X-Requested-With': 'custom' }\"\n      class=\"overridden\"\n      >POST Link</Link\n    >\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/Location.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the links page that demonstrates location visits inertia-links</span>\n\n    <Link href=\"/location\" replace class=\"example\">Location visit</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/Method.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the links page that demonstrates inertia-link methods</span>\n\n    <Link method=\"get\" href=\"/dump/get\" class=\"get\">GET Link</Link>\n    <Link as=\"button\" method=\"post\" href=\"/dump/post\" class=\"post\">POST Link</Link>\n    <Link as=\"button\" method=\"put\" href=\"/dump/put\" class=\"put\">PUT Link</Link>\n    <Link as=\"button\" method=\"patch\" href=\"/dump/patch\" class=\"patch\">PATCH Link</Link>\n    <Link as=\"button\" method=\"delete\" href=\"/dump/delete\" class=\"delete\">DELETE Link</Link>\n    <Link as=\"button\" :href=\"{ url: '/dump/post', method: 'post' }\">OBJECT Link</Link>\n    <Link as=\"button\" :href=\"{ url: '/dump/post', method: 'post' }\" method=\"put\">OBJECT METHOD OVERRIDE Link</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/PartialReloads.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n\ndefineProps({\n  foo: {\n    type: Number,\n    default: 0,\n  },\n  bar: Number,\n  baz: Number,\n  headers: Object,\n})\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the links page that demonstrates partial reloads</span>\n    <span class=\"foo-text\">Foo is now {{ foo }}</span>\n    <span class=\"bar-text\">Bar is now {{ bar }}</span>\n    <span class=\"baz-text\">Baz is now {{ baz }}</span>\n    <pre class=\"headers\">{{ headers }}</pre>\n\n    <Link href=\"/links/partial-reloads\" :data=\"{ foo }\" class=\"all\">Update All</Link>\n    <Link href=\"/links/partial-reloads\" :only=\"['headers', 'foo', 'bar']\" :data=\"{ foo }\" class=\"foo-bar\"\n      >Only foo + bar</Link\n    >\n    <Link href=\"/links/partial-reloads\" :only=\"['headers', 'baz']\" :data=\"{ foo }\" class=\"baz\">Only baz</Link>\n    <Link href=\"/links/partial-reloads\" :except=\"['foo', 'bar']\" :data=\"{ foo }\" class=\"except-foo-bar\"\n      >Except foo + bar</Link\n    >\n    <Link href=\"/links/partial-reloads\" :except=\"['baz']\" :data=\"{ foo }\" class=\"except-baz\">Except baz</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/PathTraversal.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <Link href=\"../\"> Up one level </Link>\n    <Link href=\"../../method\"> Up two levels and open method </Link>\n    <Link href=\"../../../\"> Up three levels </Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/PreserveScroll.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Page } from '@inertiajs/core'\nimport { Link } from '@inertiajs/vue3'\nimport WithScrollRegion from '../../Layouts/WithScrollRegion.vue'\n\ndefineOptions({\n  layout: WithScrollRegion,\n})\n\ndefineProps({\n  foo: {\n    type: String,\n    default: 'default',\n  },\n})\n\nconst preserveCallback = (page: Page) => {\n  console.log(JSON.stringify(page))\n\n  return true\n}\n\nconst preserveCallbackFalse = (page: Page) => {\n  console.log(JSON.stringify(page))\n\n  return false\n}\n</script>\n\n<template>\n  <div style=\"height: 800px; width: 600px\">\n    <span class=\"text\">This is the links page that demonstrates scroll preservation with scroll regions</span>\n    <span class=\"foo\">Foo is now {{ foo }}</span>\n\n    <Link\n      href=\"/links/preserve-scroll-page-two\"\n      preserve-scroll\n      :data=\"{ foo: 'baz' }\"\n      class=\"preserve\"\n      data-testid=\"preserve\"\n      >Preserve Scroll</Link\n    >\n    <Link href=\"/links/preserve-scroll-page-two\" :data=\"{ foo: 'bar' }\" class=\"reset\" data-testid=\"reset\"\n      >Reset Scroll</Link\n    >\n\n    <Link\n      href=\"/links/preserve-scroll-page-two\"\n      :preserve-scroll=\"preserveCallback\"\n      :data=\"{ foo: 'baz' }\"\n      class=\"preserve-callback\"\n      data-testid=\"preserve-callback\"\n      >Preserve Scroll (Callback)</Link\n    >\n    <Link\n      href=\"/links/preserve-scroll-page-two\"\n      :preserve-scroll=\"preserveCallbackFalse\"\n      :data=\"{ foo: 'foo' }\"\n      class=\"reset-callback\"\n      data-testid=\"reset-callback\"\n      >Reset Scroll (Callback)</Link\n    >\n\n    <a href=\"/non-inertia\" class=\"off-site\" style=\"display: block\">Off-site link</a>\n\n    <Link href=\"/article\" class=\"article\" data-testid=\"article\">Article</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/PreserveScrollFalse.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Page } from '@inertiajs/core'\nimport { Link } from '@inertiajs/vue3'\nimport WithoutScrollRegion from '../../Layouts/WithoutScrollRegion.vue'\n\ndefineOptions({\n  layout: WithoutScrollRegion,\n})\n\ndefineProps({\n  foo: {\n    type: String,\n    default: 'default',\n  },\n})\n\nconst preserveCallback = (page: Page) => {\n  console.log(JSON.stringify(page))\n\n  return true\n}\n\nconst preserveCallbackFalse = (page: Page) => {\n  console.log(JSON.stringify(page))\n\n  return false\n}\n</script>\n\n<template>\n  <div style=\"height: 800px; width: 600px\">\n    <span class=\"text\">This is the links page that demonstrates scroll preservation without scroll regions</span>\n    <span class=\"foo\">Foo is now {{ foo }}</span>\n\n    <Link\n      href=\"/links/preserve-scroll-false-page-two\"\n      preserve-scroll\n      :data=\"{ foo: 'baz' }\"\n      class=\"preserve\"\n      data-testid=\"preserve\"\n      >Preserve Scroll</Link\n    >\n    <Link href=\"/links/preserve-scroll-false-page-two\" :data=\"{ foo: 'bar' }\" class=\"reset\" data-testid=\"reset\"\n      >Reset Scroll</Link\n    >\n\n    <Link\n      href=\"/links/preserve-scroll-false-page-two\"\n      :preserve-scroll=\"preserveCallback\"\n      :data=\"{ foo: 'baz' }\"\n      class=\"preserve-callback\"\n      data-testid=\"preserve-callback\"\n      >Preserve Scroll (Callback)</Link\n    >\n    <Link\n      href=\"/links/preserve-scroll-false-page-two\"\n      :preserve-scroll=\"preserveCallbackFalse\"\n      :data=\"{ foo: 'foo' }\"\n      class=\"reset-callback\"\n      data-testid=\"reset-callback\"\n      >Reset Scroll (Callback)</Link\n    >\n\n    <a href=\"/non-inertia\" class=\"off-site\">Off-site link</a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/PreserveState.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Page } from '@inertiajs/core'\nimport { Link } from '@inertiajs/vue3'\nimport { getCurrentInstance, onMounted } from 'vue'\nimport WithoutScrollRegion from '../../Layouts/WithoutScrollRegion.vue'\n\ndefineOptions({\n  layout: WithoutScrollRegion,\n})\n\ndefineProps({\n  foo: {\n    type: String,\n    default: 'default',\n  },\n})\n\nconst preserveCallback = (page: Page) => {\n  alert(page)\n\n  return true\n}\n\nconst preserveCallbackFalse = (page: Page) => {\n  alert(page)\n\n  return false\n}\n\nonMounted(() => {\n  window._inertia_page_key = getCurrentInstance()?.uid\n})\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the links page that demonstrates preserve state on Links</span>\n    <span class=\"foo\">Foo is now {{ foo }}</span>\n    <label>\n      Example Field\n      <input type=\"text\" name=\"example-field\" class=\"field\" />\n    </label>\n\n    <Link href=\"/links/preserve-state-page-two\" preserve-state :data=\"{ foo: 'bar' }\" class=\"preserve\"\n      >[State] Preserve: true</Link\n    >\n    <Link href=\"/links/preserve-state-page-two\" :preserve-state=\"false\" :data=\"{ foo: 'baz' }\" class=\"preserve-false\"\n      >[State] Preserve: false</Link\n    >\n\n    <Link\n      href=\"/links/preserve-state-page-two\"\n      :preserve-state=\"preserveCallback\"\n      :data=\"{ foo: 'callback-bar' }\"\n      class=\"preserve-callback\"\n      >[State] Preserve Callback: true</Link\n    >\n    <Link\n      href=\"/links/preserve-state-page-two\"\n      :preserve-state=\"preserveCallbackFalse\"\n      :data=\"{ foo: 'callback-baz' }\"\n      class=\"preserve-callback-false\"\n      >[State] Preserve Callback: false</Link\n    >\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/PreserveUrl.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, router } from '@inertiajs/vue3'\n\nconst props = defineProps<{\n  foo?: string\n  items?: {\n    data: string[]\n    next_page_url?: string\n  }\n}>()\n\nconst loadMore = () => {\n  if (props.items?.next_page_url) {\n    router.visit(props.items.next_page_url, {\n      only: ['items'],\n      preserveState: true,\n      preserveScroll: true,\n      preserveUrl: true,\n    })\n  }\n}\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the links page that demonstrates preserve url on Links</span>\n    <span class=\"foo\">Foo is now {{ foo || 'default' }}</span>\n\n    <Link href=\"/links/preserve-url-page-two\" preserve-url :data=\"{ foo: 'bar' }\" class=\"preserve\"\n      >[URL] Preserve: true</Link\n    >\n    <Link href=\"/links/preserve-url-page-two\" :preserve-url=\"false\" :data=\"{ foo: 'baz' }\" class=\"preserve-false\"\n      >[URL] Preserve: false</Link\n    >\n\n    <div v-if=\"items\" class=\"items-section\">\n      <div class=\"items\">\n        <div v-for=\"item in items.data\" :key=\"item\" class=\"item\">{{ item }}</div>\n      </div>\n\n      <span class=\"items-loaded\">Items loaded: {{ items.data.length }}</span>\n      <span class=\"has-next-page\">{{ items.next_page_url ? 'true' : 'false' }}</span>\n\n      <Link\n        v-if=\"items.next_page_url\"\n        :href=\"items.next_page_url\"\n        :only=\"['items']\"\n        preserve-state\n        preserve-scroll\n        preserve-url\n        class=\"load-more\"\n      >\n        Load More\n      </Link>\n\n      <button v-if=\"items.next_page_url\" @click=\"loadMore\" class=\"load-more-router\">Load More Router</button>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/PropUpdate.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst href = ref('/sleep')\n</script>\n\n<template>\n  <div>\n    <button @click.prevent=\"href = '/something-else'\">Change URL</button>\n    <Link :href=\"href\">The Link</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/Reactivity.vue",
    "content": "<script setup lang=\"ts\">\nimport { CacheForOption, LinkPrefetchOption, Method } from '@inertiajs/core'\nimport { Link } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst method = ref<Method>('get')\nconst href = ref('/dump/get')\nconst data = ref({ foo: 'bar' })\nconst headers = ref({ 'X-Custom-Header': 'value' })\nconst prefetch = ref<boolean | LinkPrefetchOption>(false)\nconst cacheFor = ref<CacheForOption>(0)\n\nconst change = () => {\n  method.value = 'post'\n  href.value = '/dump/post'\n  data.value = { foo: 'baz' }\n  headers.value = { 'X-Custom-Header': 'new-value' }\n}\n\nconst enablePrefetch = () => {\n  prefetch.value = 'hover'\n  cacheFor.value = '1s'\n}\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">\n      This page demonstrates reactivity in Inertia links. Click the button to change the link properties.\n    </span>\n\n    <Link :method=\"method\" :href=\"href\" :data=\"data\" :headers=\"headers\">Submit</Link>\n    <button @click=\"change\">Change Link props</button>\n\n    <Link href=\"/dump/get\" :prefetch=\"prefetch\" :cache-for=\"cacheFor\"> Prefetch Link </Link>\n\n    <button @click=\"enablePrefetch\">Enable Prefetch (1s cache)</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/Replace.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the links page that demonstrates replace on Links</span>\n\n    <Link href=\"/dump/get\" replace class=\"replace\">[State] Replace: true</Link>\n    <Link href=\"/dump/get\" :replace=\"false\" class=\"replace-false\">[State] Replace: false</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/ScrollRegionList.vue",
    "content": "<script setup lang=\"ts\">\nimport WithScrollRegion from '@/Layouts/WithScrollRegion.vue'\nimport { VisitHelperOptions } from '@inertiajs/core'\nimport { router } from '@inertiajs/vue3'\n\ndefineProps({\n  user_id: Number,\n})\n\nconst navigate = (id: number, options: VisitHelperOptions = {}) => {\n  router.get(`/links/scroll-region-list/user/${id}`, {}, options)\n}\n\nconst users = Array.from({ length: 10 }, (_, i) => ({ id: i + 1, name: `User ${i + 1}` }))\n</script>\n\n<template>\n  <WithScrollRegion>\n    <div>\n      <span class=\"text\">Scrollable list with scroll region</span>\n      <div class=\"user-text\">Clicked user: {{ user_id || 'none' }}</div>\n\n      <div v-for=\"user in users\" :key=\"user.id\" style=\"padding: 20px; border-bottom: 1px solid #ccc\">\n        <div style=\"margin-bottom: 10px; width: 500px\">{{ user.name }}</div>\n        <button @click=\"navigate(user.id)\">Default</button>\n        <button @click=\"navigate(user.id, { preserveScroll: true })\">Preserve True</button>\n        <button @click=\"navigate(user.id, { preserveScroll: false })\">Preserve False</button>\n      </div>\n    </div>\n  </WithScrollRegion>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Links/UrlFragments.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\nimport { onMounted, ref } from 'vue'\n\nconst documentScrollTop = ref(0)\nconst documentScrollLeft = ref(0)\n\nonMounted(() => {\n  document.addEventListener('scroll', handleScrollEvent)\n})\n\nconst handleScrollEvent = () => {\n  documentScrollTop.value = document.documentElement.scrollTop\n  documentScrollLeft.value = document.documentElement.scrollLeft\n}\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the links page that demonstrates url fragment behaviour</span>\n    <div style=\"width: 200vw; height: 200vh; margin-top: 50vh\">\n      <button @click=\"handleScrollEvent\">Update scroll positions</button>\n      <!-- prettier-ignore -->\n      <div class=\"document-position\">Document scroll position is {{ documentScrollLeft }} & {{ documentScrollTop }}</div>\n      <Link href=\"/links/url-fragments#target\" class=\"basic\">Basic link</Link>\n      <Link href=\"#target\" class=\"fragment\">Fragment link</Link>\n      <Link href=\"/links/url-fragments#non-existent-fragment\" class=\"non-existent-fragment\"\n        >Non-existent fragment link</Link\n      >\n\n      <div id=\"target\">This is the element with id 'target'</div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/MatchPropsOnKey.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Page } from '@inertiajs/core'\nimport { router } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\ninterface ComponentProps {\n  foo: {\n    data: { id: number; name: string }[]\n    companies: { id: number; name: string }[]\n    teams: { id: number; name: string }[]\n    page: number\n    per_page: number\n    meta: { label: string }\n  }\n  bar: number[]\n  baz: number[]\n}\n\nconst props = defineProps<ComponentProps>()\n\nconst page = ref(props.foo.page)\n\nconst reloadIt = () => {\n  router.visit('/match-props-on-key', {\n    data: {\n      page: page.value,\n    },\n    only: ['foo', 'baz'],\n    onSuccess(visit: Page) {\n      // TODO: Refactor 'unknown' and make Page<ComponentProps> work\n      const visitProps = visit.props as unknown as Pick<ComponentProps, 'foo' | 'baz'>\n      page.value = visitProps.foo.page\n    },\n  })\n}\n\nconst getFresh = () => {\n  page.value = 0\n  router.visit('/match-props-on-key', {\n    reset: ['foo', 'baz'],\n  })\n}\n</script>\n\n<template>\n  <div>bar count is {{ bar.length }}</div>\n  <div>baz count is {{ baz.length }}</div>\n  <div>foo.data count is {{ foo.data.length }}</div>\n  <div>first foo.data name is {{ foo.data[0].name }}</div>\n  <div>last foo.data name is {{ foo.data[foo.data.length - 1].name }}</div>\n  <div>foo.companies count is {{ foo.companies.length }}</div>\n  <div>first foo.companies name is {{ foo.companies[0].name }}</div>\n  <div>last foo.companies name is {{ foo.companies[foo.companies.length - 1].name }}</div>\n  <div>foo.teams count is {{ foo.teams.length }}</div>\n  <div>first foo.teams name is {{ foo.teams[0].name }}</div>\n  <div>last foo.teams name is {{ foo.teams[foo.teams.length - 1].name }}</div>\n  <div>foo.page is {{ foo.page }}</div>\n  <div>foo.per_page is {{ foo.per_page }}</div>\n  <div>foo.meta.label is {{ foo.meta.label }}</div>\n  <button @click=\"reloadIt\">Reload</button>\n  <button @click=\"getFresh\">Get Fresh</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/MergeNestedProps.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\nconst props = defineProps<{\n  users: { data: { id: number; name: string }[]; meta: { page: number; perPage: number } }\n}>()\n\nconst loadMore = () => {\n  router.reload({\n    only: ['users'],\n    data: { page: props.users.meta.page + 1 },\n  })\n}\n</script>\n\n<template>\n  <div>\n    <p id=\"users\">{{ users.data.map((user) => user.name).join(', ') }}</p>\n    <p id=\"meta\">Page: {{ users.meta.page }}, Per Page: {{ users.meta.perPage }}</p>\n    <button @click=\"loadMore\">Load More</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/MergeProps.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\ndefineProps<{\n  foo: number[]\n  bar: number[]\n}>()\n\nconst reloadIt = () => {\n  router.reload({\n    only: ['foo'],\n  })\n}\n\nconst getFresh = () => {\n  router.reload({\n    reset: ['foo'],\n  })\n}\n</script>\n\n<template>\n  <div>bar count is {{ bar.length }}</div>\n  <div>foo count is {{ foo.length }}</div>\n  <button @click=\"reloadIt\">Reload</button>\n  <button @click=\"getFresh\">Get Fresh</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/NavigateNonInertia.vue",
    "content": "<script setup lang=\"ts\">\nfunction navigate() {\n  window.history.replaceState({ foo: {} }, '')\n  window.location.href = '/non-inertia'\n}\n</script>\n\n<template>\n  <div>\n    <h1>Navigate Non-Inertia</h1>\n    <p>\n      <a href=\"/non-inertia\" @click.prevent=\"navigate\">Go to non-Inertia page</a>\n    </p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/NetworkError.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\nimport { onMounted, onUnmounted, ref } from 'vue'\n\nconst error = ref(false)\n\nlet removeListener: () => void\n\nonMounted(() => {\n  removeListener = router.on('exception', () => {\n    error.value = true\n    return false\n  })\n})\n\nonUnmounted(() => removeListener?.())\n\nfunction makeRequest() {\n  error.value = false\n  router.get('/network-error')\n}\n</script>\n\n<template>\n  <div>\n    <h1>Network Error</h1>\n    <div v-if=\"error\" id=\"network-error\">Network error occurred</div>\n    <button id=\"make-request\" @click=\"makeRequest\">Make Request</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/ClientSideVisit.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\ndefineProps<{ foo: string; bar: string }>()\n\nconst pushWithoutPreserving = () => {\n  router.push({\n    url: '/once-props/client-side-visit',\n    component: 'OnceProps/ClientSideVisit',\n    props: { bar: 'bar-updated' },\n  })\n}\n\nconst pushWithOnceProps = () => {\n  router.push({\n    url: '/once-props/client-side-visit',\n    component: 'OnceProps/ClientSideVisit',\n    props: (currentProps, onceProps) => ({ ...onceProps, bar: 'bar-updated' }),\n  })\n}\n</script>\n\n<template>\n  <p id=\"foo\">Foo: {{ foo }}</p>\n  <p id=\"bar\">Bar: {{ bar }}</p>\n  <button @click=\"pushWithoutPreserving\">Push without preserving</button>\n  <button @click=\"pushWithOnceProps\">Push with once props</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/CustomKeyPageA.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n\ndefineProps<{ userPermissions: string; bar: string }>()\n</script>\n\n<template>\n  <p id=\"permissions\">Permissions: {{ userPermissions }}</p>\n  <p id=\"bar\">Bar: {{ bar }}</p>\n  <Link href=\"/once-props/custom-key/b\">Go to Custom Key Page B</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/CustomKeyPageB.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n\ndefineProps<{ permissions: string; bar: string }>()\n</script>\n\n<template>\n  <p id=\"permissions\">Permissions: {{ permissions }}</p>\n  <p id=\"bar\">Bar: {{ bar }}</p>\n  <Link href=\"/once-props/custom-key/a\">Go to Custom Key Page A</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/DeferredPageA.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, Link } from '@inertiajs/vue3'\n\ndefineProps<{\n  foo?: { text: string }\n  bar: string\n}>()\n</script>\n\n<template>\n  <Deferred data=\"foo\">\n    <template #fallback>\n      <div>Loading foo...</div>\n    </template>\n\n    <p id=\"foo\">Foo: {{ foo?.text }}</p>\n  </Deferred>\n\n  <p id=\"bar\">Bar: {{ bar }}</p>\n\n  <Link href=\"/once-props/deferred/b\">Go to Deferred Page B</Link>\n  <Link href=\"/once-props/deferred/c\" prefetch=\"mount\">Go to Deferred Page C</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/DeferredPageB.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, Link } from '@inertiajs/vue3'\n\ndefineProps<{\n  foo?: { text: string }\n  bar: string\n}>()\n</script>\n\n<template>\n  <Deferred data=\"foo\">\n    <template #fallback>\n      <div>Loading foo...</div>\n    </template>\n\n    <p id=\"foo\">Foo: {{ foo?.text }}</p>\n  </Deferred>\n\n  <p id=\"bar\">Bar: {{ bar }}</p>\n\n  <Link href=\"/once-props/deferred/a\">Go to Deferred Page A</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/DeferredPageC.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, Link } from '@inertiajs/vue3'\n\ndefineProps<{\n  foo?: { text: string }\n  bar: string\n}>()\n</script>\n\n<template>\n  <Deferred data=\"foo\">\n    <template #fallback>\n      <div>Loading foo...</div>\n    </template>\n\n    <p id=\"foo\">Foo: {{ foo?.text }}</p>\n  </Deferred>\n\n  <p id=\"bar\">Bar: {{ bar }}</p>\n\n  <Link href=\"/once-props/deferred/a\">Go to Deferred Page A</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/MergePageA.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, router } from '@inertiajs/vue3'\n\ndefineProps<{ items: string[]; bar: string }>()\n</script>\n\n<template>\n  <p id=\"items\">Items count: {{ items.length }}</p>\n  <p id=\"bar\">Bar: {{ bar }}</p>\n  <Link href=\"/once-props/merge/b\">Go to Merge Page B</Link>\n  <button @click=\"router.reload({ only: ['items'] })\">Load more items</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/MergePageB.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, router } from '@inertiajs/vue3'\n\ndefineProps<{ items: string[]; bar: string }>()\n</script>\n\n<template>\n  <p id=\"items\">Items count: {{ items.length }}</p>\n  <p id=\"bar\">Bar: {{ bar }}</p>\n  <Link href=\"/once-props/merge/a\">Go to Merge Page A</Link>\n  <button @click=\"router.reload({ only: ['items'] })\">Load more items</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/OptionalPageA.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, router } from '@inertiajs/vue3'\n\ndefineProps<{ foo?: string; bar: string }>()\n</script>\n\n<template>\n  <p id=\"foo\">Foo: {{ foo ?? 'not loaded' }}</p>\n  <p id=\"bar\">Bar: {{ bar }}</p>\n  <Link href=\"/once-props/optional/b\">Go to Optional Page B</Link>\n  <button @click=\"router.reload({ only: ['foo'] })\">Load foo</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/OptionalPageB.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, router } from '@inertiajs/vue3'\n\ndefineProps<{ foo?: string; bar: string }>()\n</script>\n\n<template>\n  <p id=\"foo\">Foo: {{ foo ?? 'not loaded' }}</p>\n  <p id=\"bar\">Bar: {{ bar }}</p>\n  <Link href=\"/once-props/optional/a\">Go to Optional Page A</Link>\n  <button @click=\"router.reload({ only: ['foo'] })\">Load foo</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/PageA.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, router } from '@inertiajs/vue3'\n\ndefineProps<{ foo: string; bar: string }>()\n</script>\n\n<template>\n  <p id=\"foo\">Foo: {{ foo }}</p>\n  <p id=\"bar\">Bar: {{ bar }}</p>\n  <Link href=\"/once-props/page-b\">Go to Page B</Link>\n  <Link href=\"/once-props/page-c\">Go to Page C</Link>\n  <Link href=\"/once-props/page-d\" prefetch=\"mount\">Go to Page D</Link>\n  <Link href=\"/once-props/page-e\" prefetch=\"mount\" :cacheFor=\"1000\">Go to Page E (short cache)</Link>\n  <button @click=\"router.reload({ only: ['foo'] })\">Reload (only foo)</button>\n  <button @click=\"router.replaceProp('foo', 'replaced-foo')\">Replace foo</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/PageB.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, router } from '@inertiajs/vue3'\n\ndefineProps<{ foo: string; bar: string }>()\n</script>\n\n<template>\n  <p id=\"foo\">Foo: {{ foo }}</p>\n  <p id=\"bar\">Bar: {{ bar }}</p>\n  <Link href=\"/once-props/page-a\">Go to Page A</Link>\n  <button @click=\"router.reload({ only: ['foo'] })\">Reload (only foo)</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/PageC.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <Link href=\"/once-props/page-a\">Go to Page A</Link>\n  <Link href=\"/once-props/page-b\">Go to Page B</Link>\n  <Link href=\"/once-props/page-d\" prefetch=\"mount\">Go to Page D</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/PageD.vue",
    "content": "<script setup lang=\"ts\">\ndefineProps<{ foo: string; bar: string }>()\n</script>\n\n<template>\n  <p id=\"foo\">Foo: {{ foo }}</p>\n  <p id=\"bar\">Bar: {{ bar }}</p>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/PageE.vue",
    "content": "<script setup lang=\"ts\">\ndefineProps<{ foo: string; bar: string }>()\n</script>\n\n<template>\n  <p id=\"foo\">Foo: {{ foo }}</p>\n  <p id=\"bar\">Bar: {{ bar }}</p>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/PartialReloadA.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, router } from '@inertiajs/vue3'\n\ndefineProps<{ foo: string; bar: string }>()\n</script>\n\n<template>\n  <p id=\"foo\">Foo: {{ foo }}</p>\n  <p id=\"bar\">Bar: {{ bar }}</p>\n  <Link href=\"/once-props/partial-reload/b\">Go to Partial Reload B</Link>\n  <button @click=\"router.reload({ only: ['foo'] })\">Reload (only foo)</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/PartialReloadB.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n\ndefineProps<{ foo: string; bar: string }>()\n</script>\n\n<template>\n  <p id=\"foo\">Foo: {{ foo }}</p>\n  <p id=\"bar\">Bar: {{ bar }}</p>\n  <Link href=\"/once-props/partial-reload/a\">Go to Partial Reload A</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/SlowDeferredPageA.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, Link } from '@inertiajs/vue3'\n\ndefineProps<{\n  foo?: string\n  bar: string\n}>()\n</script>\n\n<template>\n  <Deferred data=\"foo\">\n    <template #fallback>\n      <div id=\"foo-loading\">Loading foo...</div>\n    </template>\n\n    <p id=\"foo\">Foo: {{ foo }}</p>\n  </Deferred>\n\n  <p id=\"bar\">Bar: {{ bar }}</p>\n\n  <Link href=\"/once-props/slow-deferred/b\">Go to Page B</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/SlowDeferredPageB.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, Link } from '@inertiajs/vue3'\n\ndefineProps<{\n  foo?: string\n  bar: string\n}>()\n</script>\n\n<template>\n  <Deferred data=\"foo\">\n    <template #fallback>\n      <div id=\"foo-loading\">Loading foo...</div>\n    </template>\n\n    <p id=\"foo\">Foo: {{ foo }}</p>\n  </Deferred>\n\n  <p id=\"bar\">Bar: {{ bar }}</p>\n\n  <Link href=\"/once-props/slow-deferred/a\">Go to Page A</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/TtlPageA.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, router } from '@inertiajs/vue3'\n\ndefineProps<{ foo: string; bar: string }>()\n</script>\n\n<template>\n  <p id=\"foo\">Foo: {{ foo }}</p>\n  <p id=\"bar\">Bar: {{ bar }}</p>\n  <Link href=\"/once-props/ttl/b\">Go to TTL Page B</Link>\n  <Link href=\"/once-props/ttl/c\" prefetch=\"mount\">Go to TTL Page C</Link>\n  <button @click=\"router.reload({ only: ['foo'] })\">Reload foo</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/TtlPageB.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n\ndefineProps<{ foo: string; bar: string }>()\n</script>\n\n<template>\n  <p id=\"foo\">Foo: {{ foo }}</p>\n  <p id=\"bar\">Bar: {{ bar }}</p>\n  <Link href=\"/once-props/ttl/a\">Go to TTL Page A</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/OnceProps/TtlPageC.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n\ndefineProps<{ foo: string; bar: string }>()\n</script>\n\n<template>\n  <p id=\"foo\">Foo: {{ foo }}</p>\n  <p id=\"bar\">Bar: {{ bar }}</p>\n  <Link href=\"/once-props/ttl/a\">Go to TTL Page A</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageA.vue",
    "content": "<script lang=\"ts\">\nimport type { Component, VNode } from 'vue'\nimport NestedLayout from '@/Layouts/NestedLayout.vue'\nimport SiteLayout from '@/Layouts/SiteLayout.vue'\n\ntype RenderFunction = (component: Component, children: Component[]) => VNode\n\nexport default {\n  layout: (h: RenderFunction, page: Component) => {\n    return h(SiteLayout, [h(NestedLayout, [page])])\n  },\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">Nested Persistent Layout - Page A</span>\n    <Link href=\"/persistent-layouts/render-function/nested/page-b\">Page B</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageB.vue",
    "content": "<script lang=\"ts\">\nimport type { Component, VNode } from 'vue'\nimport NestedLayout from '@/Layouts/NestedLayout.vue'\nimport SiteLayout from '@/Layouts/SiteLayout.vue'\n\ntype RenderFunction = (component: Component, children: Component[]) => VNode\n\nexport default {\n  layout: (h: RenderFunction, page: Component) => {\n    return h(SiteLayout, [h(NestedLayout, [page])])\n  },\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">Nested Persistent Layout - Page B</span>\n    <Link href=\"/persistent-layouts/render-function/nested/page-a\">Page A</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageA.vue",
    "content": "<script lang=\"ts\">\nimport type { Component, VNode } from 'vue'\nimport Layout from '@/Layouts/SiteLayout.vue'\n\ntype RenderFunction = (component: Component, children: Component[]) => VNode\n\nexport default {\n  layout: (h: RenderFunction, page: Component) => h(Layout, [page]),\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">Simple Persistent Layout - Page A</span>\n    <Link href=\"/persistent-layouts/render-function/simple/page-b\">Page B</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageB.vue",
    "content": "<script lang=\"ts\">\nimport type { Component, VNode } from 'vue'\nimport Layout from '@/Layouts/SiteLayout.vue'\n\ntype RenderFunction = (component: Component, children: Component[]) => VNode\n\nexport default {\n  layout: (h: RenderFunction, page: Component) => h(Layout, [page]),\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">Simple Persistent Layout - Page B</span>\n    <Link href=\"/persistent-layouts/render-function/simple/page-a\">Page A</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.vue",
    "content": "<script lang=\"ts\">\nimport NestedLayout from '@/Layouts/NestedLayout.vue'\nimport SiteLayout from '@/Layouts/SiteLayout.vue'\n\nexport default {\n  layout: [SiteLayout, NestedLayout],\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { Link, usePage } from '@inertiajs/vue3'\nwindow._inertia_page_props = usePage().props\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">Nested Persistent Layout - Page A</span>\n    <Link href=\"/persistent-layouts/shorthand/nested/page-b\">Page B</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.vue",
    "content": "<script lang=\"ts\">\nimport NestedLayout from '@/Layouts/NestedLayout.vue'\nimport SiteLayout from '@/Layouts/SiteLayout.vue'\n\nexport default {\n  layout: [SiteLayout, NestedLayout],\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">Nested Persistent Layout - Page B</span>\n    <Link href=\"/persistent-layouts/shorthand/nested/page-a\">Page A</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '@/Layouts/SiteLayout.vue'\n\nexport default {\n  layout: Layout,\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { Link, usePage } from '@inertiajs/vue3'\n\nwindow._inertia_page_props = usePage().props\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">Simple Persistent Layout - Page A</span>\n    <Link href=\"/persistent-layouts/shorthand/simple/page-b\">Page B</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '@/Layouts/SiteLayout.vue'\n\nexport default {\n  layout: Layout,\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">Simple Persistent Layout - Page B</span>\n    <Link href=\"/persistent-layouts/shorthand/simple/page-a\">Page A</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Poll/Hook.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, usePoll } from '@inertiajs/vue3'\n\nusePoll(500, {\n  only: ['custom_prop'],\n  onFinish() {\n    console.log('hook poll finished')\n  },\n})\n</script>\n\n<template>\n  <Link href=\"/\">Home</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Poll/HookManual.vue",
    "content": "<script setup lang=\"ts\">\nimport { usePoll } from '@inertiajs/vue3'\n\nconst { start, stop } = usePoll(\n  500,\n  {\n    only: ['custom_prop'],\n    onFinish() {\n      console.log('hook poll finished')\n    },\n  },\n  {\n    autoStart: false,\n  },\n)\n</script>\n\n<template>\n  <button @click=\"start\">Start</button>\n  <button @click=\"stop\">Stop</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Poll/RouterManual.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\nconst { start, stop } = router.poll(\n  500,\n  {\n    only: ['custom_prop'],\n    onFinish() {\n      console.log('hook poll finished')\n    },\n  },\n  {\n    autoStart: false,\n  },\n)\n</script>\n\n<template>\n  <button @click=\"start\">Start</button>\n  <button @click=\"stop\">Stop</button>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Poll/UnchangedData.vue",
    "content": "<script setup lang=\"ts\">\nimport { usePoll } from '@inertiajs/vue3'\nimport { onMounted, ref } from 'vue'\n\nconst replaceStateCalls = ref(0)\nconst pollsFinished = ref(0)\n\nonMounted(() => {\n  const original = window.history.replaceState.bind(window.history)\n  window.history.replaceState = function (...args) {\n    replaceStateCalls.value++\n    return original(...args)\n  }\n})\n\nusePoll(500, {\n  only: ['custom_prop'],\n  onFinish: () => pollsFinished.value++,\n})\n</script>\n\n<template>\n  <div>\n    <p>\n      replaceState calls: <span class=\"replaceStateCalls\">{{ replaceStateCalls }}</span>\n    </p>\n    <p>\n      polls finished: <span class=\"pollsFinished\">{{ pollsFinished }}</span>\n    </p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Prefetch/AfterError.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\nconst prefetchPage = () => {\n  router.prefetch('/prefetch/swr/1', { method: 'get' }, { cacheFor: 5000 })\n}\n\nconst visitPage = () => {\n  router.visit('/prefetch/swr/1')\n}\n\nconst prefetchNonInertia = () => {\n  router.prefetch('/non-inertia', { method: 'get' }, { cacheFor: 5000 })\n}\n\nconst visitNonInertia = () => {\n  router.visit('/non-inertia')\n}\n</script>\n\n<template>\n  <div>\n    <button @click=\"prefetchPage\">Prefetch Page</button>\n    <button @click=\"visitPage\">Visit Page</button>\n    <button @click=\"prefetchNonInertia\">Prefetch Non-Inertia</button>\n    <button @click=\"visitNonInertia\">Visit Non-Inertia</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Prefetch/Form.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, useForm } from '@inertiajs/vue3'\n\ninterface Props {\n  randomValue: number\n}\n\ndefineProps<Props>()\n\nconst form = useForm({})\n\nconst submitToSame = () => {\n  form.post('/prefetch/form')\n}\n\nconst submitToOther = () => {\n  form.post('/prefetch/redirect-back')\n}\n</script>\n\n<template>\n  <div>\n    <p>\n      Random Value: <span class=\"random-value\">{{ randomValue }}</span>\n    </p>\n    <button @click=\"submitToSame\">Submit to Same URL</button>\n    <button @click=\"submitToOther\">Submit to Other URL</button>\n    <Link href=\"/prefetch/test-page\">Back to Test Page</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Prefetch/Page.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '@/Layouts/Prefetch.vue'\nimport type { Component, VNode } from 'vue'\n\ntype RenderFunction = (component: Component, children: Component[]) => VNode\n\nexport default {\n  layout: (h: RenderFunction, page: Component) => h(Layout, [page]),\n}\n</script>\n\n<script setup lang=\"ts\">\ndefineProps<{\n  pageNumber: string\n  lastLoaded: number\n}>()\n</script>\n\n<template>\n  <div>This is page {{ pageNumber }}</div>\n  <div>\n    Last loaded at <span id=\"last-loaded\">{{ lastLoaded }}</span>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Prefetch/PreserveState.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\ndefineProps<{\n  page: number\n  timestamp: number\n}>()\n\nconst prefetchPage2 = () => {\n  router.prefetch('/prefetch/preserve-state', { method: 'get', data: { page: 2 } }, { cacheFor: '30s' })\n}\n\nconst loadPage2WithoutPreserveState = () => {\n  router.get('/prefetch/preserve-state', { page: 2 }, { preserveState: false })\n}\n\nconst loadPage2WithPreserveState = () => {\n  router.get('/prefetch/preserve-state', { page: 2 }, { preserveState: true })\n}\n</script>\n\n<template>\n  <div>\n    <div>Current Page: {{ page }}</div>\n    <div>Timestamp: {{ timestamp }}</div>\n\n    <h3>Prefetch:</h3>\n    <button @click=\"prefetchPage2\">Prefetch Page 2</button>\n\n    <h3>Load (should use cache if prefetched):</h3>\n    <button @click=\"loadPage2WithoutPreserveState\">Load Page 2 (preserveState: false)</button>\n    <button @click=\"loadPage2WithPreserveState\">Load Page 2 (preserveState: true)</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Prefetch/SWR.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '@/Layouts/SWR.vue'\nimport type { Component, VNode } from 'vue'\n\ntype RenderFunction = (component: Component, children: Component[]) => VNode\n\nexport default {\n  layout: (h: RenderFunction, page: Component) => h(Layout, [page]),\n}\n</script>\n\n<script setup lang=\"ts\">\ndefineProps<{\n  pageNumber: string\n  lastLoaded: number\n}>()\n</script>\n\n<template>\n  <div>This is page {{ pageNumber }}</div>\n  <div>\n    Last loaded at <span id=\"last-loaded\">{{ lastLoaded }}</span>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Prefetch/Tags.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, router, useForm } from '@inertiajs/vue3'\n\nconst props = defineProps({\n  pageNumber: String,\n  lastLoaded: Number,\n  propType: String,\n})\n\nconst form = useForm({\n  name: '',\n})\n\nconst flushUserTags = () => {\n  router.flushByCacheTags(props.propType === 'string' ? 'user' : ['user'])\n}\n\nconst flushUserProductTags = () => {\n  router.flushByCacheTags(['user', 'product'])\n}\n\nconst programmaticPrefetch = () => {\n  router.prefetch('/prefetch/tags/2', { method: 'get' }, { cacheTags: props.propType === 'string' ? 'user' : ['user'] })\n  router.prefetch(\n    '/prefetch/tags/3',\n    { method: 'get' },\n    { cacheFor: '1m', cacheTags: props.propType === 'string' ? 'product' : ['product'] },\n  )\n  router.prefetch(\n    '/prefetch/tags/6',\n    { method: 'get' },\n    { cacheFor: '1m' }, // No tags (untagged)\n  )\n}\n\nconst submitWithUserInvalidation = () => {\n  form.post('/dump/post', {\n    invalidateCacheTags: props.propType === 'string' ? 'user' : ['user'],\n  })\n}\n</script>\n\n<template>\n  <div>\n    <div id=\"links\">\n      <Link href=\"/prefetch/tags/1\" prefetch=\"hover\" :cache-tags=\"['user', 'profile']\"> User Page 1 </Link>\n      <Link href=\"/prefetch/tags/2\" prefetch=\"hover\" :cache-tags=\"['user', 'settings']\"> User Page 2 </Link>\n      <Link href=\"/prefetch/tags/3\" prefetch=\"hover\" :cache-tags=\"['product', 'catalog']\"> Product Page 3 </Link>\n      <Link href=\"/prefetch/tags/4\" prefetch=\"hover\" :cache-tags=\"['product', 'details']\"> Product Page 4 </Link>\n      <Link href=\"/prefetch/tags/5\" prefetch=\"hover\" :cache-tags=\"props.propType === 'string' ? 'admin' : ['admin']\">\n        Admin Page 5\n      </Link>\n      <Link href=\"/prefetch/tags/6\" prefetch=\"hover\"> Untagged Page 6 </Link>\n    </div>\n    <div id=\"controls\">\n      <button id=\"flush-user\" @click=\"flushUserTags\">Flush User Tags</button>\n      <button id=\"flush-user-product\" @click=\"flushUserProductTags\">Flush User + Product Tags</button>\n      <button id=\"programmatic-prefetch\" @click=\"programmaticPrefetch\">Programmatic Prefetch</button>\n    </div>\n\n    <div id=\"form-section\">\n      <h3>Form Test</h3>\n      <form @submit.prevent>\n        <input id=\"form-name\" v-model=\"form.name\" type=\"text\" placeholder=\"Enter name\" />\n        <button id=\"submit-invalidate-user\" @click=\"submitWithUserInvalidation\">Submit (Invalidate User)</button>\n      </form>\n    </div>\n    <div>\n      <div>This is tags page {{ pageNumber }}</div>\n      <div>\n        Last loaded at <span id=\"last-loaded\">{{ lastLoaded }}</span>\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Prefetch/TestPage.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div>\n    <Link href=\"/prefetch/form\" prefetch>Go to Prefetch Form</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Prefetch/Wayfinder.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\nimport { onMounted, ref } from 'vue'\n\nconst isPrefetched = ref(false)\nconst isPrefetching = ref(false)\n\nconst wayfinderUrl = (): {\n  url: string\n  method: 'get'\n} => ({\n  url: '/prefetch/swr/4',\n  method: 'get',\n})\n\nconst checkStatus = () => {\n  isPrefetched.value = !!router.getCached(wayfinderUrl())\n  isPrefetching.value = !!router.getPrefetching(wayfinderUrl())\n}\n\nconst testPrefetch = () => {\n  router.prefetch(wayfinderUrl(), {\n    onPrefetching: () => {\n      isPrefetching.value = true\n    },\n    onPrefetched: () => {\n      isPrefetching.value = false\n      setTimeout(checkStatus)\n    },\n  })\n}\n\nconst testFlush = () => {\n  router.flush(wayfinderUrl())\n  checkStatus()\n}\n\nconst flushAll = () => {\n  router.flushAll()\n  checkStatus()\n}\n\nonMounted(checkStatus)\n</script>\n\n<template>\n  <div>\n    <p>\n      Is Prefetched: <span id=\"is-prefetched\">{{ isPrefetched }}</span>\n    </p>\n    <p>\n      Is Prefetching: <span id=\"is-prefetching\">{{ isPrefetching }}</span>\n    </p>\n\n    <button @click=\"testPrefetch\" id=\"test-prefetch\">Test prefetch</button>\n    <button @click=\"testFlush\" id=\"test-flush\">Test flush</button>\n    <button @click=\"flushAll\" id=\"flush-all\">Flush all</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/PreserveEqualProps.vue",
    "content": "<script setup lang=\"ts\">\nimport { config, Link } from '@inertiajs/vue3'\nimport { ref, watch } from 'vue'\n\nconst props = defineProps<{\n  nestedA: { count: number }\n  nestedB: { date: number }\n}>()\n\nconst effectACount = ref(1)\nconst effectBCount = ref(1)\n\nwatch(\n  () => props.nestedA,\n  () => {\n    effectACount.value++\n  },\n)\n\nwatch(\n  () => props.nestedB,\n  () => {\n    effectBCount.value++\n  },\n)\n\nfunction enable() {\n  config.set('future.preserveEqualProps', true)\n}\n</script>\n\n<template>\n  <div>\n    <h1>Preserve Equal Props</h1>\n    <p id=\"count-a\">Count A: {{ nestedA.count }}</p>\n    <p id=\"date-b\">Date B: {{ nestedB.date }}</p>\n    <p id=\"effect-a\">Effect A Count: {{ effectACount }}</p>\n    <p id=\"effect-b\">Effect B Count: {{ effectBCount }}</p>\n    <Link method=\"post\" preserve-state href=\"/preserve-equal-props/back\"> Submit and redirect back </Link>\n    <button @click=\"enable\">Enable</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/ProgressComponent.vue",
    "content": "<script setup lang=\"ts\">\nimport { progress } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\ndeclare global {\n  interface Window {\n    progressTests: unknown[]\n  }\n}\n\nwindow.progressTests = []\n\nconst logs = ref<string[]>([])\n\nconst log = (...args: unknown[]) => {\n  const message = args.join(' ')\n  window.progressTests.push(...args)\n  logs.value.push(message)\n}\n\nconst testStart = () => {\n  progress.start()\n  log('started')\n}\n\nconst testSet25 = () => {\n  progress.set(0.25)\n  log('set 25%')\n}\n\nconst testSet50 = () => {\n  progress.set(0.5)\n  log('set 50%')\n}\n\nconst testSet75 = () => {\n  progress.set(0.75)\n  log('set 75%')\n}\n\nconst testFinish = () => {\n  progress.finish()\n  log('finished')\n}\n\nconst testReset = () => {\n  progress.reset()\n  log('reset')\n}\n\nconst testRemove = () => {\n  progress.remove()\n  log('removed')\n}\n\nconst testHide = () => {\n  progress.hide()\n  log('hidden')\n}\n\nconst testReveal = () => {\n  progress.reveal()\n  log('revealed')\n}\n\nconst testIsStarted = () => {\n  log('isStarted:', progress.isStarted())\n}\n\nconst testGetStatus = () => {\n  log('getStatus:', progress.getStatus())\n}\n\nconst clearLogs = () => {\n  window.progressTests = []\n  logs.value = []\n}\n</script>\n\n<template>\n  <div>\n    <h1>Progress API Test</h1>\n\n    <div>\n      <button @click=\"testStart\">Start</button>\n      <button @click=\"testSet25\">Set 25%</button>\n      <button @click=\"testSet50\">Set 50%</button>\n      <button @click=\"testSet75\">Set 75%</button>\n      <button @click=\"testFinish\">Finish</button>\n    </div>\n\n    <div>\n      <button @click=\"testReset\">Reset</button>\n      <button @click=\"testRemove\">Remove</button>\n      <button @click=\"testHide\">Hide</button>\n      <button @click=\"testReveal\">Reveal</button>\n    </div>\n\n    <div>\n      <button @click=\"testIsStarted\">Is Started</button>\n      <button @click=\"testGetStatus\">Get Status</button>\n      <button @click=\"clearLogs\">Clear</button>\n    </div>\n\n    <div>\n      Logs: <span id=\"logs\">{{ logs.join(', ') }}</span>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Reload/Concurrent.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\ndefineProps<{\n  foo?: string\n  bar?: string\n}>()\n\nfunction reloadBothProps() {\n  router.reload({ only: ['foo'] })\n  setTimeout(() => router.reload({ only: ['bar'] }), 50)\n}\n</script>\n\n<template>\n  <div>\n    <div id=\"foo\">Foo: {{ foo }}</div>\n    <div id=\"bar\">Bar: {{ bar }}</div>\n\n    <button @click=\"reloadBothProps\">Reload both props</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Reload/ConcurrentWithData.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\ndefineProps<{\n  foo?: string\n  bar?: string\n  timeframe?: string\n}>()\n\nfunction reloadBothPropsWithData() {\n  router.reload({ only: ['foo'], data: { timeframe: 'week' } })\n  setTimeout(() => router.reload({ only: ['bar'], data: { timeframe: 'week' } }), 50)\n}\n</script>\n\n<template>\n  <div>\n    <div id=\"foo\">Foo: {{ foo }}</div>\n    <div id=\"bar\">Bar: {{ bar }}</div>\n    <div id=\"timeframe\">Timeframe: {{ timeframe }}</div>\n\n    <button @click=\"reloadBothPropsWithData\">Reload both props with data</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Remember/Components/ComponentA.vue",
    "content": "<script setup lang=\"ts\">\nimport { useRemember } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst untracked = ref('')\n\nconst data = useRemember(\n  {\n    name: '',\n    remember: false,\n  },\n  'Example/ComponentA',\n)\n</script>\n\n<template>\n  <div>\n    <span>This component uses a string 'key' for the remember functionality.</span>\n    <label>\n      Full Name\n      <input type=\"text\" class=\"a-name\" name=\"full_name\" v-model=\"data.name\" />\n    </label>\n    <label>\n      Remember Me\n      <input type=\"checkbox\" class=\"a-remember\" name=\"remember\" v-model=\"data.remember\" />\n    </label>\n    <label>\n      Remember Me\n      <input type=\"text\" class=\"a-untracked\" name=\"untracked\" v-model=\"untracked\" />\n    </label>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Remember/Components/ComponentB.vue",
    "content": "<script setup lang=\"ts\">\nimport { useRemember } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst untracked = ref('')\n\nconst data = useRemember(\n  {\n    name: '',\n    remember: false,\n  },\n  'Example/ComponentB',\n)\n</script>\n\n<template>\n  <div>\n    <span>This component uses a callback-style 'key' for the remember functionality.</span>\n    <label>\n      Full Name\n      <input type=\"text\" class=\"b-name\" name=\"full_name\" v-model=\"data.name\" />\n    </label>\n    <label>\n      Remember Me\n      <input type=\"checkbox\" class=\"b-remember\" name=\"remember\" v-model=\"data.remember\" />\n    </label>\n    <label>\n      Remember Me\n      <input type=\"text\" class=\"b-untracked\" name=\"untracked\" v-model=\"untracked\" />\n    </label>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Remember/Default.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst name = ref('')\nconst remember = ref(false)\nconst untracked = ref('')\n</script>\n\n<template>\n  <div>\n    <label>\n      Full Name\n      <input type=\"text\" id=\"name\" name=\"full_name\" v-model=\"name\" />\n    </label>\n    <label>\n      Remember Me\n      <input type=\"checkbox\" id=\"remember\" name=\"remember\" v-model=\"remember\" />\n    </label>\n    <label>\n      Untracked\n      <input type=\"text\" id=\"untracked\" name=\"untracked\" v-model=\"untracked\" />\n    </label>\n\n    <Link href=\"/dump/get\" class=\"link\">Navigate away</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Remember/FormHelper/Default.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, useForm } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst untracked = ref('')\n\nconst form = useForm({\n  name: 'foo',\n  handle: 'example',\n  remember: false,\n})\n\nconst submit = () => {\n  form.post('/remember/form-helper/default')\n}\n</script>\n\n<template>\n  <div>\n    <label>\n      Full Name\n      <input type=\"text\" id=\"name\" name=\"name\" v-model=\"form.name\" />\n    </label>\n    <span class=\"name_error\" v-if=\"form.errors.name\">{{ form.errors.name }}</span>\n    <label>\n      Handle\n      <input type=\"text\" id=\"handle\" name=\"handle\" v-model=\"form.handle\" />\n    </label>\n    <span class=\"handle_error\" v-if=\"form.errors.handle\">{{ form.errors.handle }}</span>\n    <label>\n      Remember Me\n      <input type=\"checkbox\" id=\"remember\" name=\"remember\" v-model=\"form.remember\" />\n    </label>\n    <span class=\"remember_error\" v-if=\"form.errors.remember\">{{ form.errors.remember }}</span>\n    <label>\n      Untracked\n      <input type=\"text\" id=\"untracked\" name=\"untracked\" v-model=\"untracked\" />\n    </label>\n\n    <button @click=\"submit\" class=\"submit\">Submit form</button>\n\n    <Link href=\"/dump/get\" class=\"link\">Navigate away</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Remember/FormHelper/Password.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, useForm } from '@inertiajs/vue3'\n\nconst form = useForm('password-form', {\n  username: '',\n  password: '',\n}).dontRemember('password')\n</script>\n\n<template>\n  <div>\n    <label>\n      Username\n      <input type=\"text\" id=\"username\" v-model=\"form.username\" />\n    </label>\n    <label>\n      Password\n      <input type=\"password\" id=\"password\" v-model=\"form.password\" />\n    </label>\n\n    <Link href=\"/dump/get\" class=\"link\">Navigate away</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Remember/FormHelper/Remember.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, useForm } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst form = useForm('form', {\n  name: 'foo',\n  handle: 'example',\n  remember: false,\n})\n\nconst untracked = ref('')\n\nconst submit = () => {\n  form.post('/remember/form-helper/remember')\n}\n\nconst reset = () => {\n  form.reset('handle').clearErrors('name')\n}\n</script>\n\n<template>\n  <div>\n    <label>\n      Full Name\n      <input type=\"text\" id=\"name\" name=\"name\" v-model=\"form.name\" />\n    </label>\n    <span class=\"name_error\" v-if=\"form.errors.name\">{{ form.errors.name }}</span>\n    <label>\n      Handle\n      <input type=\"text\" id=\"handle\" name=\"handle\" v-model=\"form.handle\" />\n    </label>\n    <span class=\"handle_error\" v-if=\"form.errors.handle\">{{ form.errors.handle }}</span>\n    <label>\n      Remember Me\n      <input type=\"checkbox\" id=\"remember\" name=\"remember\" v-model=\"form.remember\" />\n    </label>\n    <span class=\"remember_error\" v-if=\"form.errors.remember\">{{ form.errors.remember }}</span>\n    <label>\n      Untracked\n      <input type=\"text\" id=\"untracked\" name=\"untracked\" v-model=\"untracked\" />\n    </label>\n\n    <button @click=\"submit\" class=\"submit\">Submit form</button>\n    <button @click=\"reset\" class=\"reset-one\">Reset one field & error</button>\n\n    <Link href=\"/dump/get\" class=\"link\">Navigate away</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Remember/MultipleComponents.vue",
    "content": "<script setup lang=\"ts\">\nimport ComponentA from '@/Pages/Remember/Components/ComponentA.vue'\nimport ComponentB from '@/Pages/Remember/Components/ComponentB.vue'\nimport { Link, useRemember } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst untracked = ref('')\n\nconst form = useRemember({\n  name: '',\n  remember: false,\n})\n</script>\n\n<template>\n  <div>\n    <label>\n      Full Name\n      <input type=\"text\" id=\"name\" name=\"full_name\" v-model=\"form.name\" />\n    </label>\n    <label>\n      Remember Me\n      <input type=\"checkbox\" id=\"remember\" name=\"remember\" v-model=\"form.remember\" />\n    </label>\n    <label>\n      Untracked\n      <input type=\"text\" id=\"untracked\" name=\"untracked\" v-model=\"untracked\" />\n    </label>\n\n    <component-a class=\"component-a\" />\n    <component-b class=\"component-b\" />\n\n    <Link href=\"/dump/get\" class=\"link\">Navigate away</Link>\n    <a href=\"/non-inertia\" class=\"off-site\">Navigate off-site</a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Remember/Object.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, useRemember } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst untracked = ref('')\n\nconst form = useRemember({\n  name: '',\n  remember: false,\n})\n</script>\n\n<template>\n  <div>\n    <label>\n      Full Name\n      <input type=\"text\" id=\"name\" name=\"full_name\" v-model=\"form.name\" />\n    </label>\n    <label>\n      Remember Me\n      <input type=\"checkbox\" id=\"remember\" name=\"remember\" v-model=\"form.remember\" />\n    </label>\n    <label>\n      Untracked\n      <input type=\"text\" id=\"untracked\" name=\"untracked\" v-model=\"untracked\" />\n    </label>\n\n    <Link href=\"/dump/get\" class=\"link\">Navigate away</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Remember/Router.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst foo = ref('-')\nconst bar = ref(0)\n\nfunction remember() {\n  router.remember('foo')\n  router.remember(42, 'bar')\n}\n\nfunction restore() {\n  foo.value = router.restore() ?? '-'\n  bar.value = router.restore('bar') ?? 0\n}\n\nfunction restoreTyped() {\n  const fooValue = router.restore<string>()\n  const barValue = router.restore<number>('bar')\n\n  fooValue?.startsWith('f')\n  barValue?.toFixed(2)\n\n  foo.value = fooValue ?? '-'\n  bar.value = barValue ?? 0\n\n  // @ts-expect-error - Testing type safety\n  fooValue?.toFixed(2)\n  // @ts-expect-error - Testing type safety\n  barValue?.startsWith('b')\n}\n</script>\n\n<template>\n  <div>\n    <p>Foo: {{ foo }}</p>\n    <p>Bar: {{ bar }}</p>\n    <button @click=\"remember\">Remember</button>\n    <button @click=\"restore\">Restore</button>\n    <button @click=\"restoreTyped\">Restore Typed</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/SSR/Page1.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n\ndefineProps<{\n  user: {\n    name: string\n    email: string\n  }\n  items: string[]\n  count: number\n}>()\n</script>\n\n<template>\n  <div>\n    <h1 data-testid=\"ssr-title\">SSR Page 1</h1>\n\n    <div data-testid=\"user-info\">\n      <p data-testid=\"user-name\">Name: {{ user.name }}</p>\n      <p data-testid=\"user-email\">Email: {{ user.email }}</p>\n    </div>\n\n    <ul data-testid=\"items-list\">\n      <li v-for=\"item in items\" :key=\"item\" data-testid=\"item\">{{ item }}</li>\n    </ul>\n\n    <p data-testid=\"count\">Count: {{ count }}</p>\n\n    <Link href=\"/ssr/page2\" data-testid=\"navigate-link\">Navigate to another page</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/SSR/Page2.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n\ndefineProps<{\n  navigatedTo: boolean\n}>()\n</script>\n\n<template>\n  <div>\n    <h1 data-testid=\"ssr-title\">SSR Page 2</h1>\n    <p data-testid=\"navigated-status\">Navigated: {{ navigatedTo }}</p>\n\n    <Link href=\"/ssr/page1\" data-testid=\"back-link\">Go back</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/SSR/PageWithScriptElement.vue",
    "content": "<script setup lang=\"ts\">\ndefineProps<{\n  message: string\n}>()\n</script>\n\n<template>\n  <div>\n    <h1 data-testid=\"ssr-title\">SSR Page With Script Element</h1>\n    <p data-testid=\"message\">{{ message }}</p>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/ScrollAfterRender.vue",
    "content": "<script lang=\"ts\">\nlet originalScrollTo: typeof window.scrollTo | null = null\n</script>\n\n<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n\ndefineProps<{\n  page: number\n}>()\n\n// Patch scrollTo to log synchronously when it's called (not when the scroll event fires)\nif (!originalScrollTo) {\n  originalScrollTo = window.scrollTo.bind(window)\n\n  window.scrollTo = ((xOrOptions: number | ScrollToOptions, y?: number) => {\n    const firstArgIsNumber = typeof xOrOptions === 'number'\n    const scrollY = firstArgIsNumber ? y : (xOrOptions?.top ?? 0)\n\n    console.log('ScrollY', scrollY)\n\n    return firstArgIsNumber ? originalScrollTo!(xOrOptions, y!) : originalScrollTo!(xOrOptions)\n  }) as typeof window.scrollTo\n} else {\n  console.log('Render')\n}\n\nfunction beforeNavigate() {\n  window.scrollTo(0, 100)\n}\n</script>\n\n<template>\n  <h1 :style=\"{ fontSize: '40px' }\">Article Header</h1>\n  <h2 :style=\"{ fontSize: '40px' }\">Page {{ page }}</h2>\n  <article :style=\"{ fontSize: '20px', maxWidth: '500px' }\">\n    <p>\n      Sunt culpa sit sunt enim aliquip. Esse ea ea quis voluptate. Enim consectetur aliqua ex ex magna cupidatat id\n      minim sit elit.\n    </p>\n    <Link\n      :href=\"`/scroll-after-render/${page + 1}`\"\n      :style=\"{ display: 'block', marginTop: '20px' }\"\n      @before=\"beforeNavigate\"\n    >\n      Go to page {{ page + 1 }}\n    </Link>\n    <div v-for=\"i in [...Array(500).keys()]\" :key=\"i\">\n      <p>\n        Sunt culpa sit sunt enim aliquip. Esse ea ea quis voluptate. Enim consectetur aliqua ex ex magna cupidatat id\n        minim sit elit. Amet pariatur occaecat pariatur duis eiusmod dolore magna. Et commodo cupidatat in commodo elit\n        cupidatat minim qui id non enim ad. Culpa aliquip ad Lorem sit consectetur ullamco culpa duis nisi et fugiat\n        mollit eiusmod. Laboris voluptate veniam consequat proident in nulla irure velit.\n      </p>\n\n      <p>\n        Sit sint laboris sunt eiusmod ipsum laborum eiusmod amet commodo exercitation in duis magna. Proident sunt minim\n        in elit qui. Id pariatur commodo fugiat excepteur in deserunt Lorem ipsum occaecat est. Excepteur sit tempor\n        ipsum ex officia veniam enim amet velit fugiat mollit cillum. Incididunt aliqua nulla id occaecat nulla. Non ea\n        ad est occaecat deserunt officia qui commodo exercitation.\n      </p>\n\n      <p>\n        Voluptate laborum quis aliqua ullamco magna amet ullamco laborum qui cillum eu. Dolore dolore aliqua proident\n        proident sunt ipsum in. Enim velit dolore labore dolor quis incididunt duis culpa Lorem. Eu adipisicing non elit\n        fugiat voluptate labore ipsum dolore consectetur commodo. Et in et cillum duis consequat quis ex eu commodo.\n        Eiusmod aliqua excepteur consectetur eiusmod aute et consectetur sit pariatur dolore qui officia pariatur.\n      </p>\n\n      <p>\n        Non sunt eu mollit qui reprehenderit. Aute culpa anim voluptate do in esse duis laborum ad dolore. Ullamco nisi\n        in nostrud officia do. Duis pariatur officia id duis. Deserunt ad incididunt est sint consectetur reprehenderit\n        mollit est Lorem ea pariatur anim dolor adipisicing. Nostrud irure magna nostrud laboris aute sunt veniam\n        laboris veniam incididunt sit. Nulla proident ad aliqua fugiat culpa sunt est in dolor velit ad irure nulla.\n      </p>\n\n      <p>\n        Do aute laborum deserunt non laborum voluptate voluptate. Anim ut laborum magna sunt cupidatat irure. Cupidatat\n        fugiat minim sint cillum laborum excepteur irure id est irure ad occaecat adipisicing enim. Deserunt nulla anim\n        proident velit irure nostrud est est reprehenderit consequat pariatur qui. Fugiat Lorem sint eu laborum minim\n        pariatur cillum mollit nulla consequat ullamco ex. Ex consectetur ad ut irure fugiat occaecat aliqua\n        exercitation cillum ipsum anim dolore tempor.\n      </p>\n\n      <p>\n        Adipisicing consequat irure fugiat Lorem deserunt aliquip do cupidatat. Lorem labore elit ex qui nostrud qui\n        cillum sunt adipisicing occaecat. Sunt nostrud amet amet cupidatat fugiat Lorem quis nulla id cillum esse eu.\n        Ullamco aliqua dolore irure amet mollit anim velit dolore.\n      </p>\n\n      <p>\n        Veniam cupidatat ipsum ea officia ipsum nisi laborum culpa qui dolore. Aliqua Lorem nisi labore ea velit aliquip\n        irure excepteur eu. Laboris proident duis non labore sunt quis aute tempor laboris enim anim eiusmod.\n      </p>\n\n      <p>\n        Minim proident ut aliqua ea ut culpa fugiat ullamco nisi esse nostrud reprehenderit id. Id id ullamco velit anim\n        nisi magna Lorem tempor. Et veniam occaecat ut labore consequat fugiat duis.\n      </p>\n\n      <p>\n        Adipisicing ea consectetur adipisicing aute eu pariatur enim labore consequat occaecat consectetur minim nisi.\n        Cillum commodo sunt labore reprehenderit. Duis esse excepteur magna tempor eiusmod exercitation Lorem\n        reprehenderit excepteur pariatur. Esse cupidatat occaecat magna do aliquip Lorem. Consectetur adipisicing\n        consequat dolore nostrud esse eu cillum id commodo duis. Aliquip dolor cillum cupidatat fugiat.\n      </p>\n\n      <p>\n        Ex eiusmod id est laborum sunt ex ea aute adipisicing ad magna deserunt duis. Nostrud velit dolore id commodo\n        quis enim fugiat. Sint non quis consectetur voluptate aliqua dolore nulla. Irure sit reprehenderit sint laboris\n        non elit. Duis minim nisi esse dolor. Sit ex in consequat non occaecat commodo irure et. Commodo qui ipsum Lorem\n        magna consequat consequat et minim eiusmod Lorem eiusmod cupidatat voluptate.\n      </p>\n    </div>\n  </article>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/ScrollRegionPreserveUrl.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\nconst props = defineProps<{\n  page: number\n}>()\n\nlet scrollInterval: ReturnType<typeof setInterval> | null = null\n\nconst startScrollingAndNavigate = () => {\n  const container = document.getElementById('scroll-container')!\n  const nextPage = props.page === 1 ? 2 : 1\n\n  // Start continuous scrolling\n  scrollInterval = setInterval(() => {\n    container.scrollTop += 10\n  }, 10)\n\n  // After 150ms of scrolling, navigate to the other page\n  setTimeout(() => {\n    router.visit(`/scroll-region-preserve-url/${nextPage}`, {\n      preserveScroll: true,\n      preserveState: true,\n      preserveUrl: true,\n      onSuccess: () => {\n        // Stop scrolling after navigation\n        if (scrollInterval) {\n          clearInterval(scrollInterval)\n          scrollInterval = null\n        }\n      },\n    })\n  }, 150)\n}\n</script>\n\n<template>\n  <div scroll-region id=\"scroll-container\" style=\"height: 300px; overflow-y: auto; border: 1px solid #ccc\">\n    <div style=\"padding: 10px\">\n      <div class=\"page-number\">Page: {{ page }}</div>\n      <button id=\"scroll-and-navigate\" @click=\"startScrollingAndNavigate\">Start scrolling and navigate</button>\n      <div v-for=\"i in 50\" :key=\"i\" style=\"padding: 20px; border-bottom: 1px solid #eee\">Item {{ i }}</div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/ScrollSmooth.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link } from '@inertiajs/vue3'\n\ndefineProps<{\n  page: 'long' | 'short'\n}>()\n\ndocument.documentElement.style.scrollBehavior = 'smooth'\n</script>\n\n<template>\n  <div>\n    <h1>{{ page === 'long' ? 'Long Page' : 'Short Page' }}</h1>\n\n    <div :style=\"{ height: page === 'long' ? '2000px' : '100px' }\"></div>\n\n    <Link v-if=\"page === 'long'\" href=\"/scroll-smooth/short\">Go to Short Page</Link>\n    <Link v-else href=\"/scroll-smooth/long\">Go to Long Page</Link>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/ScrollableParent.vue",
    "content": "<script setup lang=\"ts\">\nimport { getScrollableParent } from '@inertiajs/core'\nimport { onMounted, ref } from 'vue'\n\nconst overflowXHidden = ref<HTMLElement | null>(null)\nconst overflowXScroll = ref<HTMLElement | null>(null)\nconst overflowYAuto = ref<HTMLElement | null>(null)\nconst overflowYAutoNoHeight = ref<HTMLElement | null>(null)\nconst overflowXScrollOverflowYHidden = ref<HTMLElement | null>(null)\nconst horizontalScrollCalc = ref<HTMLElement | null>(null)\nconst verticalScrollMaxHeight = ref<HTMLElement | null>(null)\nconst nestedScroll = ref<HTMLElement | null>(null)\nconst overflowAutoNoConstraints = ref<HTMLElement | null>(null)\nconst flexHorizontalCarousel = ref<HTMLElement | null>(null)\nconst coercedAutoNoConstraint = ref<HTMLElement | null>(null)\nconst displayContents = ref<HTMLElement | null>(null)\nconst overflowClip = ref<HTMLElement | null>(null)\nconst overflowOverlay = ref<HTMLElement | null>(null)\nconst inlineWidthStyle = ref<HTMLElement | null>(null)\nconst bothScrollDirections = ref<HTMLElement | null>(null)\nconst overflowYAutoOverflowXVisible = ref<HTMLElement | null>(null)\nconst overflowYAutoOverflowXClip = ref<HTMLElement | null>(null)\nconst overflowXAutoOverflowYVisible = ref<HTMLElement | null>(null)\nconst overflowXAutoOverflowYClip = ref<HTMLElement | null>(null)\nconst overflowYAutoOverflowXHidden = ref<HTMLElement | null>(null)\nconst overflowXAutoOverflowYHidden = ref<HTMLElement | null>(null)\n\nconst results = ref<Record<string, HTMLElement | null>>({})\n\nonMounted(() => {\n  Object.entries({\n    overflowXHidden,\n    overflowXScroll,\n    overflowYAuto,\n    overflowYAutoNoHeight,\n    overflowXScrollOverflowYHidden,\n    horizontalScrollCalc,\n    verticalScrollMaxHeight,\n    nestedScroll,\n    overflowAutoNoConstraints,\n    flexHorizontalCarousel,\n    coercedAutoNoConstraint,\n    displayContents,\n    overflowClip,\n    overflowOverlay,\n    inlineWidthStyle,\n    bothScrollDirections,\n    overflowYAutoOverflowXVisible,\n    overflowYAutoOverflowXClip,\n    overflowXAutoOverflowYVisible,\n    overflowXAutoOverflowYClip,\n    overflowYAutoOverflowXHidden,\n    overflowXAutoOverflowYHidden,\n  }).forEach(([key, elementRef]) => {\n    results.value[key] = getScrollableParent(elementRef.value)\n  })\n})\n</script>\n\n<template>\n  <div style=\"padding: 20px\">\n    <h1>ScrollableParent Tests</h1>\n\n    <div style=\"display: grid; gap: 20px; margin-top: 20px\">\n      <!-- overflow-x: hidden -->\n      <div>\n        <h3>overflow-x: hidden</h3>\n        <div style=\"overflow-x: hidden; border: 2px solid red; padding: 10px\">\n          <div ref=\"overflowXHidden\" data-testid=\"overflow-x-hidden\">Test</div>\n        </div>\n        <p data-testid=\"result-overflow-x-hidden\">{{ results.overflowXHidden?.tagName || 'null' }}</p>\n      </div>\n\n      <!-- overflow-x: scroll -->\n      <div>\n        <h3>overflow-x: scroll</h3>\n        <div\n          style=\"overflow-x: scroll; width: 300px; border: 2px solid red; padding: 10px\"\n          data-testid=\"scroll-container-x\"\n        >\n          <div ref=\"overflowXScroll\" data-testid=\"overflow-x-scroll\" style=\"width: 600px\">Wide content</div>\n        </div>\n        <p data-testid=\"result-overflow-x-scroll\">{{ results.overflowXScroll?.dataset?.testid || 'null' }}</p>\n      </div>\n\n      <!-- overflow-y: auto with height -->\n      <div>\n        <h3>overflow-y: auto + height</h3>\n        <div\n          style=\"overflow-y: auto; height: 100px; border: 2px solid red; padding: 10px\"\n          data-testid=\"scroll-container-y\"\n        >\n          <div ref=\"overflowYAuto\" data-testid=\"overflow-y-auto\">\n            <p>Content</p>\n            <p>Content</p>\n            <p>Content</p>\n          </div>\n        </div>\n        <p data-testid=\"result-overflow-y-auto\">{{ results.overflowYAuto?.dataset?.testid || 'null' }}</p>\n      </div>\n\n      <!-- overflow-y: auto no height -->\n      <div>\n        <h3>overflow-y: auto (no height)</h3>\n        <div style=\"overflow-y: auto; border: 2px solid red; padding: 10px\">\n          <div ref=\"overflowYAutoNoHeight\" data-testid=\"overflow-y-auto-no-height\">Content</div>\n        </div>\n        <p data-testid=\"result-overflow-y-auto-no-height\">{{ results.overflowYAutoNoHeight?.tagName || 'null' }}</p>\n      </div>\n\n      <!-- overflow-x: scroll, overflow-y: hidden -->\n      <div>\n        <h3>overflow-x: scroll, overflow-y: hidden</h3>\n        <div\n          style=\"overflow-x: scroll; overflow-y: hidden; width: 300px; border: 2px solid red; padding: 10px\"\n          data-testid=\"scroll-container-x-y-hidden\"\n        >\n          <div ref=\"overflowXScrollOverflowYHidden\" data-testid=\"overflow-x-scroll-y-hidden\" style=\"width: 600px\">\n            Wide content\n          </div>\n        </div>\n        <p data-testid=\"result-overflow-x-scroll-y-hidden\">\n          {{ results.overflowXScrollOverflowYHidden?.dataset?.testid || 'null' }}\n        </p>\n      </div>\n\n      <!-- overflow-x: scroll + max-width -->\n      <div>\n        <h3>overflow-x: scroll + max-width</h3>\n        <div\n          style=\"overflow-x: scroll; max-width: 300px; border: 2px solid red; padding: 10px\"\n          data-testid=\"scroll-container-max-width\"\n        >\n          <div ref=\"horizontalScrollCalc\" data-testid=\"horizontal-scroll-calc\" style=\"width: 600px\">Wide content</div>\n        </div>\n        <p data-testid=\"result-horizontal-scroll-calc\">{{ results.horizontalScrollCalc?.dataset?.testid || 'null' }}</p>\n      </div>\n\n      <!-- overflow-y: auto + max-height -->\n      <div>\n        <h3>overflow-y: auto + max-height</h3>\n        <div\n          style=\"overflow-y: auto; max-height: 100px; border: 2px solid red; padding: 10px\"\n          data-testid=\"scroll-container-max-height\"\n        >\n          <div ref=\"verticalScrollMaxHeight\" data-testid=\"vertical-scroll-max-height\">\n            <p>Content</p>\n            <p>Content</p>\n            <p>Content</p>\n          </div>\n        </div>\n        <p data-testid=\"result-vertical-scroll-max-height\">\n          {{ results.verticalScrollMaxHeight?.dataset?.testid || 'null' }}\n        </p>\n      </div>\n\n      <!-- Nested containers -->\n      <div>\n        <h3>Nested containers</h3>\n        <div style=\"overflow-y: auto; height: 200px; border: 2px solid red; padding: 10px\" data-testid=\"outer-scroll\">\n          <p>Outer</p>\n          <div\n            style=\"overflow-y: auto; height: 100px; border: 2px solid blue; padding: 10px\"\n            data-testid=\"inner-scroll\"\n          >\n            <div ref=\"nestedScroll\" data-testid=\"nested-scroll\">\n              <p>Content</p>\n              <p>Content</p>\n              <p>Content</p>\n              <p>Content</p>\n              <p>Content</p>\n            </div>\n          </div>\n        </div>\n        <p data-testid=\"result-nested-scroll\">{{ results.nestedScroll?.dataset?.testid || 'null' }}</p>\n      </div>\n\n      <!-- overflow: auto (no constraints) -->\n      <div>\n        <h3>overflow: auto (no constraints)</h3>\n        <div style=\"overflow: auto; border: 2px solid red; padding: 10px\">\n          <div ref=\"overflowAutoNoConstraints\" data-testid=\"overflow-auto-no-constraints\">Content</div>\n        </div>\n        <p data-testid=\"result-overflow-auto-no-constraints\">\n          {{ results.overflowAutoNoConstraints?.tagName || 'null' }}\n        </p>\n      </div>\n\n      <!-- Flex carousel -->\n      <div>\n        <h3>Flex horizontal carousel</h3>\n        <div\n          style=\"overflow-x: scroll; display: flex; gap: 10px; width: 300px; border: 2px solid red; padding: 10px\"\n          data-testid=\"flex-carousel\"\n        >\n          <div\n            ref=\"flexHorizontalCarousel\"\n            data-testid=\"flex-horizontal-carousel\"\n            style=\"min-width: 150px; height: 50px; background: lightblue\"\n          >\n            Item\n          </div>\n          <div style=\"min-width: 150px; height: 50px; background: lightgreen\">Item</div>\n          <div style=\"min-width: 150px; height: 50px; background: lightcoral\">Item</div>\n        </div>\n        <p data-testid=\"result-flex-horizontal-carousel\">\n          {{ results.flexHorizontalCarousel?.dataset?.testid || 'null' }}\n        </p>\n      </div>\n\n      <!-- Coerced auto -->\n      <div>\n        <h3>overflow-x: scroll (overflow-y coerced)</h3>\n        <div\n          style=\"overflow-x: scroll; display: flex; width: 300px; border: 2px solid red; padding: 10px\"\n          data-testid=\"coerced-auto\"\n        >\n          <div ref=\"coercedAutoNoConstraint\" data-testid=\"coerced-auto-no-constraint\" style=\"min-width: 600px\">\n            Wide\n          </div>\n        </div>\n        <p data-testid=\"result-coerced-auto-no-constraint\">\n          {{ results.coercedAutoNoConstraint?.dataset?.testid || 'null' }}\n        </p>\n      </div>\n\n      <!-- display: contents -->\n      <div>\n        <h3>display: contents (skip parent)</h3>\n        <div\n          style=\"overflow-y: auto; height: 100px; border: 2px solid red; padding: 10px\"\n          data-testid=\"scroll-container-skip-contents\"\n        >\n          <div style=\"display: contents\">\n            <div ref=\"displayContents\" data-testid=\"display-contents\">\n              <p>Content</p>\n              <p>Content</p>\n              <p>Content</p>\n              <p>Content</p>\n            </div>\n          </div>\n        </div>\n        <p data-testid=\"result-display-contents\">{{ results.displayContents?.dataset?.testid || 'null' }}</p>\n      </div>\n\n      <!-- overflow: clip -->\n      <div>\n        <h3>overflow: clip</h3>\n        <div style=\"overflow: clip; height: 100px; border: 2px solid red; padding: 10px\">\n          <div ref=\"overflowClip\" data-testid=\"overflow-clip\">\n            <p>Content</p>\n            <p>Content</p>\n          </div>\n        </div>\n        <p data-testid=\"result-overflow-clip\">{{ results.overflowClip?.tagName || 'null' }}</p>\n      </div>\n\n      <!-- overflow: overlay -->\n      <div>\n        <h3>overflow: overlay</h3>\n        <div\n          style=\"overflow: overlay; height: 100px; border: 2px solid red; padding: 10px\"\n          data-testid=\"scroll-container-overlay\"\n        >\n          <div ref=\"overflowOverlay\" data-testid=\"overflow-overlay\">\n            <p>Content</p>\n            <p>Content</p>\n            <p>Content</p>\n            <p>Content</p>\n          </div>\n        </div>\n        <p data-testid=\"result-overflow-overlay\">{{ results.overflowOverlay?.dataset?.testid || 'null' }}</p>\n      </div>\n\n      <!-- Inline width -->\n      <div>\n        <h3>overflow-x: auto + inline width</h3>\n        <div\n          style=\"overflow-x: auto; width: 300px; border: 2px solid red; padding: 10px\"\n          data-testid=\"inline-width-container\"\n        >\n          <div ref=\"inlineWidthStyle\" data-testid=\"inline-width-style\" style=\"width: 600px\">Wide</div>\n        </div>\n        <p data-testid=\"result-inline-width-style\">{{ results.inlineWidthStyle?.dataset?.testid || 'null' }}</p>\n      </div>\n\n      <!-- Both scroll -->\n      <div>\n        <h3>overflow: scroll (both)</h3>\n        <div\n          style=\"\n            overflow-x: scroll;\n            overflow-y: scroll;\n            width: 300px;\n            height: 100px;\n            border: 2px solid red;\n            padding: 10px;\n          \"\n          data-testid=\"both-scroll\"\n        >\n          <div ref=\"bothScrollDirections\" data-testid=\"both-scroll-directions\" style=\"width: 600px\">\n            <p>Wide and tall</p>\n            <p>Content</p>\n            <p>Content</p>\n          </div>\n        </div>\n        <p data-testid=\"result-both-scroll-directions\">{{ results.bothScrollDirections?.dataset?.testid || 'null' }}</p>\n      </div>\n\n      <!-- overflow-y: auto + overflow-x: visible -->\n      <div>\n        <h3>overflow-y: auto + overflow-x: visible</h3>\n        <div\n          style=\"overflow-y: auto; overflow-x: visible; height: 100px; border: 2px solid red; padding: 10px\"\n          data-testid=\"overflow-y-auto-x-visible\"\n        >\n          <div ref=\"overflowYAutoOverflowXVisible\" data-testid=\"overflow-y-auto-overflow-x-visible\">\n            <p>Content</p>\n            <p>Content</p>\n            <p>Content</p>\n          </div>\n        </div>\n        <p data-testid=\"result-overflow-y-auto-overflow-x-visible\">\n          {{ results.overflowYAutoOverflowXVisible?.dataset?.testid || 'null' }}\n        </p>\n      </div>\n\n      <!-- overflow-y: auto + overflow-x: clip -->\n      <div>\n        <h3>overflow-y: auto + overflow-x: clip</h3>\n        <div\n          style=\"overflow-y: auto; overflow-x: clip; height: 100px; border: 2px solid red; padding: 10px\"\n          data-testid=\"overflow-y-auto-x-clip\"\n        >\n          <div ref=\"overflowYAutoOverflowXClip\" data-testid=\"overflow-y-auto-overflow-x-clip\">\n            <p>Content</p>\n            <p>Content</p>\n            <p>Content</p>\n          </div>\n        </div>\n        <p data-testid=\"result-overflow-y-auto-overflow-x-clip\">\n          {{ results.overflowYAutoOverflowXClip?.dataset?.testid || 'null' }}\n        </p>\n      </div>\n\n      <!-- overflow-x: auto + overflow-y: visible -->\n      <div>\n        <h3>overflow-x: auto + overflow-y: visible</h3>\n        <div\n          style=\"overflow-x: auto; overflow-y: visible; width: 300px; border: 2px solid red; padding: 10px\"\n          data-testid=\"overflow-x-auto-y-visible\"\n        >\n          <div\n            ref=\"overflowXAutoOverflowYVisible\"\n            data-testid=\"overflow-x-auto-overflow-y-visible\"\n            style=\"width: 600px\"\n          >\n            Wide content\n          </div>\n        </div>\n        <p data-testid=\"result-overflow-x-auto-overflow-y-visible\">\n          {{ results.overflowXAutoOverflowYVisible?.dataset?.testid || 'null' }}\n        </p>\n      </div>\n\n      <!-- overflow-x: auto + overflow-y: clip -->\n      <div>\n        <h3>overflow-x: auto + overflow-y: clip</h3>\n        <div\n          style=\"overflow-x: auto; overflow-y: clip; width: 300px; border: 2px solid red; padding: 10px\"\n          data-testid=\"overflow-x-auto-y-clip\"\n        >\n          <div ref=\"overflowXAutoOverflowYClip\" data-testid=\"overflow-x-auto-overflow-y-clip\" style=\"width: 600px\">\n            Wide content\n          </div>\n        </div>\n        <p data-testid=\"result-overflow-x-auto-overflow-y-clip\">\n          {{ results.overflowXAutoOverflowYClip?.dataset?.testid || 'null' }}\n        </p>\n      </div>\n\n      <!-- overflow-y: auto + overflow-x: hidden (no height) -->\n      <div>\n        <h3>overflow-y: auto + overflow-x: hidden (no height)</h3>\n        <div style=\"overflow-y: auto; overflow-x: hidden; border: 2px solid red; padding: 10px\">\n          <div ref=\"overflowYAutoOverflowXHidden\" data-testid=\"overflow-y-auto-overflow-x-hidden\">Content</div>\n        </div>\n        <p data-testid=\"result-overflow-y-auto-overflow-x-hidden\">\n          {{ results.overflowYAutoOverflowXHidden?.tagName || 'null' }}\n        </p>\n      </div>\n\n      <!-- overflow-x: auto + overflow-y: hidden (no width) -->\n      <div>\n        <h3>overflow-x: auto + overflow-y: hidden (no width)</h3>\n        <div style=\"overflow-x: auto; overflow-y: hidden; border: 2px solid red; padding: 10px\">\n          <div ref=\"overflowXAutoOverflowYHidden\" data-testid=\"overflow-x-auto-overflow-y-hidden\">Content</div>\n        </div>\n        <p data-testid=\"result-overflow-x-auto-overflow-y-hidden\">\n          {{ results.overflowXAutoOverflowYHidden?.tagName || 'null' }}\n        </p>\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/TypeScriptCreateInertiaApp.ts",
    "content": "// This file is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { createInertiaApp } from '@inertiajs/vue3'\nimport type { DefineComponent } from 'vue'\nimport { createApp, h } from 'vue'\n\ndeclare module '@inertiajs/core' {\n  export interface InertiaConfig {\n    sharedPageProps: {\n      auth: { user: { name: string } | null }\n    }\n  }\n}\n\n// createInertiaApp setup should include shared props without explicit generic\ncreateInertiaApp({\n  resolve: (name) => {\n    const pages = import.meta.glob<DefineComponent>('./Pages/**/*.vue', { eager: true })\n    return pages[`./Pages/${name}.vue`]\n  },\n  setup({ el, App, props, plugin }) {\n    console.log(props.initialPage.props.auth.user?.name)\n    // @ts-expect-error - 'email' does not exist on user\n    console.log(props.initialPage.props.auth.user?.email)\n\n    createApp({ render: () => h(App, props) })\n      .use(plugin)\n      .mount(el)\n  },\n})\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/TypeScriptFlash.vue",
    "content": "<script setup lang=\"ts\">\n// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { router, usePage } from '@inertiajs/vue3'\n\ndeclare module '@inertiajs/core' {\n  export interface InertiaConfig {\n    flashDataType: {\n      toast?: { type: 'success' | 'error'; message: string }\n    }\n  }\n}\n\nconst page = usePage()\n\n// page.flash is always an object\nconst flash = page.flash\nconst toast = page.flash.toast\nconst toastMessage = page.flash.toast?.message\nconst toastType = page.flash.toast?.type\n\n// @ts-expect-error - 'message' does not exist on flash (it's on toast)\nconst flashMessage = page.flash.message\n\n// router.flash with object\nrouter.flash({ toast: { type: 'success', message: 'Hello' } })\n\n// router.flash with key-value\nrouter.flash('toast', { type: 'error', message: 'Oops' })\n\n// router.flash with callback\nrouter.flash((current) => ({\n  ...current,\n  toast: { type: 'success', message: 'Updated' },\n}))\n\n// Client-side visit with flash\nrouter.replace({\n  flash: { toast: { type: 'success', message: 'Replaced' } },\n  onFlash: (flash) => {\n    console.log(flash.toast?.message)\n  },\n})\n\n// Client-side visit with flash callback\nrouter.push({\n  flash: (current) => ({\n    ...current,\n    toast: { type: 'error', message: 'Error' },\n  }),\n})\n\n// Scoped flash typing with generic (for page/section-specific flash)\nrouter.flash<{ paymentError: string }>({ paymentError: 'Card declined' })\n\n// @ts-expect-error - 'paymentError' should be string, not number\nrouter.flash<{ paymentError: string }>({ paymentError: 123 })\n\nconsole.log({\n  flash,\n  toast,\n  toastMessage,\n  toastType,\n  flashMessage,\n})\n</script>\n\n<template>\n  <div v-if=\"page.flash.toast\">\n    {{ page.flash.toast.message }}\n  </div>\n\n  <!-- @vue-expect-error - 'message' does not exist on flash -->\n  {{ page.flash.message }}\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/TypeScriptProps.vue",
    "content": "<script setup lang=\"ts\">\n// This component is used for checking the TypeScript implementation; there is no Playwright test depending on it.\nimport { router, usePage } from '@inertiajs/vue3'\n\ndeclare module '@inertiajs/core' {\n  export interface InertiaConfig {\n    sharedPageProps: {\n      auth: { user: { name: string } | null }\n    }\n  }\n}\n\ntype PageProps = {\n  posts: { id: number; title: string }[]\n}\n\nconst page = usePage<PageProps>()\n\nconst userName = page.props.auth.user?.name\nconst postTitles = page.props.posts.map((post) => post.title)\n\n// @ts-expect-error - 'email' does not exist on user\nconst userEmail = page.props.auth.user?.email\n// @ts-expect-error - 'users' does not exist on page props\nconst userNames = page.props.users.map((user) => user.name)\n\n// Global event callbacks should include shared props\nrouter.on('success', (event) => {\n  console.log(event.detail.page.props.auth.user?.name)\n  // @ts-expect-error - 'email' does not exist on user\n  console.log(event.detail.page.props.auth.user?.email)\n})\n\nrouter.on('navigate', (event) => {\n  console.log(event.detail.page.props.auth.user?.name)\n  // @ts-expect-error - 'email' does not exist on user\n  console.log(event.detail.page.props.auth.user?.email)\n})\n\nrouter.on('beforeUpdate', (event) => {\n  console.log(event.detail.page.props.auth.user?.name)\n  // @ts-expect-error - 'email' does not exist on user\n  console.log(event.detail.page.props.auth.user?.email)\n})\n\n// Visit callback onSuccess should include shared props\nrouter.visit('/example', {\n  onSuccess: (page) => {\n    console.log(page.props.auth.user?.name)\n    // @ts-expect-error - 'email' does not exist on user\n    console.log(page.props.auth.user?.email)\n  },\n})\n\n// Client-side visit onSuccess should include shared props\nrouter.push({\n  onSuccess: (page) => {\n    console.log(page.props.auth.user?.name)\n    // @ts-expect-error - 'email' does not exist on user\n    console.log(page.props.auth.user?.email)\n  },\n})\n\nrouter.replace({\n  onSuccess: (page) => {\n    console.log(page.props.auth.user?.name)\n    // @ts-expect-error - 'email' does not exist on user\n    console.log(page.props.auth.user?.email)\n  },\n})\n\nconsole.log({\n  userName,\n  postTitles,\n  userEmail,\n  userNames,\n})\n</script>\n\n<template>\n  {{ $page.props.auth.user?.name }}\n\n  <!-- @vue-expect-error - 'email' does not exist on user -->\n  {{ $page.props.auth.user?.email }}\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/ViewTransition/FormErrors.vue",
    "content": "<script setup lang=\"ts\">\nimport { useForm } from '@inertiajs/vue3'\n\nconst form = useForm({ name: '' })\n\nconst submit = () => {\n  form.post('/view-transition/form-errors', {\n    viewTransition: (viewTransition) => {\n      viewTransition.ready.then(() => console.log('ready'))\n      viewTransition.updateCallbackDone.then(() => console.log('updateCallbackDone'))\n      viewTransition.finished.then(() => console.log('finished'))\n    },\n  })\n}\n</script>\n\n<template>\n  <div>\n    <h1>View Transition Form Errors Test</h1>\n\n    <label>\n      Name\n      <input id=\"name\" v-model=\"form.name\" type=\"text\" name=\"name\" />\n    </label>\n\n    <p v-if=\"form.errors.name\" class=\"name_error\">{{ form.errors.name }}</p>\n\n    <button class=\"submit\" @click=\"submit\">Submit with View Transition</button>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/ViewTransition/PageA.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, router } from '@inertiajs/vue3'\n\nconst transitionWithBoolean = () => {\n  router.visit('/view-transition/page-b', {\n    viewTransition: true,\n  })\n}\n\nconst transitionWithCallback = () => {\n  router.visit('/view-transition/page-b', {\n    viewTransition: (viewTransition) => {\n      viewTransition.ready.then(() => console.log('ready'))\n      viewTransition.updateCallbackDone.then(() => console.log('updateCallbackDone'))\n      viewTransition.finished.then(() => console.log('finished'))\n    },\n  })\n}\n\nconst clientSideReplace = () => {\n  router.replace({\n    url: '/view-transition/page-b',\n    component: 'ViewTransition/PageB',\n    props: {},\n    viewTransition: (viewTransition) => {\n      viewTransition.ready.then(() => console.log('ready'))\n      viewTransition.updateCallbackDone.then(() => console.log('updateCallbackDone'))\n      viewTransition.finished.then(() => console.log('finished'))\n    },\n  })\n}\n</script>\n\n<template>\n  <h1>Page A - View Transition Test</h1>\n\n  <button @click=\"transitionWithBoolean\">Transition with boolean</button>\n  <button @click=\"transitionWithCallback\">Transition with callback</button>\n  <button @click=\"clientSideReplace\">Client-side replace</button>\n  <Link\n    href=\"/view-transition/page-b\"\n    :view-transition=\"\n      (viewTransition: ViewTransition) => {\n        viewTransition.ready.then(() => console.log('ready'))\n        viewTransition.updateCallbackDone.then(() => console.log('updateCallbackDone'))\n        viewTransition.finished.then(() => console.log('finished'))\n      }\n    \"\n    >Link to Page B</Link\n  >\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/ViewTransition/PageB.vue",
    "content": "<template>\n  <h1>Page B - View Transition Test</h1>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/AfterError.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\nconst visitDump = (e: Event) => {\n  e.preventDefault()\n  router.visit('/dump/get')\n}\n\nconst throwErrorOnSuccess = (e: Event) => {\n  e.preventDefault()\n\n  router.visit('/visits/after-error/2', {\n    onSuccess: () => {\n      throw new Error('Error after visit')\n    },\n  })\n}\n</script>\n\n<template>\n  <div>\n    <a href=\"#\" @click.prevent=\"visitDump\"> Visit dump page </a>\n\n    <a href=\"#\" @click.prevent=\"throwErrorOnSuccess\"> Throw error on success </a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/AutomaticCancellation.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\nconst visit = () => {\n  router.get(\n    '/sleep',\n    {},\n    {\n      onStart: () => console.log('started'),\n      onCancel: () => console.log('cancelled'),\n    },\n  )\n}\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the page that demonstrates that only one visit can be active at a time</span>\n    <a href=\"#\" @click.prevent=\"visit\" class=\"visit\">Link</a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/Data/AutoConverted.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\nconst formData = {\n  file: new File([], 'example.jpg'),\n  foo: 'bar',\n}\n\nconst visitMethod = () => {\n  router.visit('/dump/post', {\n    method: 'post',\n    data: formData,\n  })\n}\n\nconst postMethod = () => {\n  router.post('/dump/post', formData)\n}\n\nconst putMethod = () => {\n  router.put('/dump/put', formData)\n}\n\nconst patchMethod = () => {\n  router.patch('/dump/patch', formData)\n}\n\nconst deleteMethod = () => {\n  router.delete('/dump/delete', {\n    data: formData,\n  })\n}\n</script>\n\n<template>\n  <div>\n    <span class=\"text\"\n      >This is the page that demonstrates automatic conversion of plain objects to form-data using manual visits</span\n    >\n\n    <a href=\"#\" @click.prevent=\"visitMethod\" class=\"visit\">Visit Link</a>\n    <a href=\"#\" @click.prevent=\"postMethod\" class=\"post\">POST Link</a>\n    <a href=\"#\" @click.prevent=\"putMethod\" class=\"put\">PUT Link</a>\n    <a href=\"#\" @click.prevent=\"patchMethod\" class=\"patch\">PATCH Link</a>\n    <a href=\"#\" @click.prevent=\"deleteMethod\" class=\"delete\">DELETE Link</a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/Data/FormData.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\nconst visitMethod = () => {\n  const formData = new FormData()\n  formData.append('foo', 'visit')\n\n  router.visit('/dump/post', {\n    method: 'post',\n    data: formData,\n  })\n}\n\nconst postMethod = () => {\n  const formData = new FormData()\n  formData.append('baz', 'post')\n\n  router.post('/dump/post', formData)\n}\n\nconst putMethod = () => {\n  const formData = new FormData()\n  formData.append('foo', 'put')\n\n  router.put('/dump/put', formData)\n}\n\nconst patchMethod = () => {\n  const formData = new FormData()\n  formData.append('bar', 'patch')\n\n  router.patch('/dump/patch', formData)\n}\n\nconst deleteMethod = () => {\n  const formData = new FormData()\n  formData.append('baz', 'delete')\n\n  router.delete('/dump/delete', {\n    data: formData,\n  })\n}\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the page that demonstrates manual visit data passing through FormData objects</span>\n\n    <a href=\"#\" @click.prevent=\"visitMethod\" class=\"visit\">Visit Link</a>\n    <a href=\"#\" @click.prevent=\"postMethod\" class=\"post\">POST Link</a>\n    <a href=\"#\" @click.prevent=\"putMethod\" class=\"put\">PUT Link</a>\n    <a href=\"#\" @click.prevent=\"patchMethod\" class=\"patch\">PATCH Link</a>\n    <a href=\"#\" @click.prevent=\"deleteMethod\" class=\"delete\">DELETE Link</a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/Data/Object.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\nconst visitMethod = () => {\n  router.visit('/dump/get', {\n    data: { foo: 'visit' },\n  })\n}\n\nconst getMethod = () => {\n  router.get('/dump/get', {\n    bar: 'get',\n  })\n}\n\nconst postMethod = () => {\n  router.post('/dump/post', {\n    baz: 'post',\n  })\n}\n\nconst putMethod = () => {\n  router.put('/dump/put', {\n    foo: 'put',\n  })\n}\n\nconst patchMethod = () => {\n  router.patch('/dump/patch', {\n    bar: 'patch',\n  })\n}\n\nconst deleteMethod = () => {\n  router.delete('/dump/delete', {\n    data: { baz: 'delete' },\n  })\n}\n\nconst qsafDefault = () => {\n  router.visit('/dump/get', {\n    data: { a: ['b', 'c'] },\n  })\n}\n\nconst qsafIndices = () => {\n  router.visit('/dump/get', {\n    data: { a: ['b', 'c'] },\n    queryStringArrayFormat: 'indices',\n  })\n}\n\nconst qsafBrackets = () => {\n  router.visit('/dump/get', {\n    data: { a: ['b', 'c'] },\n    queryStringArrayFormat: 'brackets',\n  })\n}\n\nconst deleteQueryParam = (e: Event) => {\n  e.preventDefault()\n  router.visit('/dump/get', {\n    data: { a: undefined },\n  })\n}\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the page that demonstrates manual visit data passing through plain objects</span>\n\n    <a href=\"#\" @click.prevent=\"visitMethod\" class=\"visit\">Visit Link</a>\n    <a href=\"#\" @click.prevent=\"getMethod\" class=\"get\">GET Link</a>\n    <a href=\"#\" @click.prevent=\"postMethod\" class=\"post\">POST Link</a>\n    <a href=\"#\" @click.prevent=\"putMethod\" class=\"put\">PUT Link</a>\n    <a href=\"#\" @click.prevent=\"patchMethod\" class=\"patch\">PATCH Link</a>\n    <a href=\"#\" @click.prevent=\"deleteMethod\" class=\"delete\">DELETE Link</a>\n\n    <a href=\"#\" @click.prevent=\"qsafDefault\" class=\"qsaf-default\">QSAF Defaults</a>\n    <a href=\"#\" @click.prevent=\"qsafIndices\" class=\"qsaf-indices\">QSAF Indices</a>\n    <a href=\"#\" @click.prevent=\"qsafBrackets\" class=\"qsaf-brackets\">QSAF Brackets</a>\n    <a href=\"#\" @click.prevent=\"deleteQueryParam\" className=\"delete-query-param\">Delete Query Param</a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/ErrorBags.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\nconst defaultVisit = () => {\n  router.post('/dump/post')\n}\n\nconst basicVisit = () => {\n  router.visit('/dump/post', {\n    method: 'post',\n    data: { foo: 'bar' },\n    errorBag: 'visitErrorBag',\n  })\n}\n\nconst postVisit = () => {\n  router.post(\n    '/dump/post',\n    {\n      foo: 'baz',\n    },\n    {\n      errorBag: 'postErrorBag',\n    },\n  )\n}\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the page that demonstrates error bags using manual visits</span>\n    <a href=\"#\" @click.prevent=\"defaultVisit\" class=\"default\">Default visit</a>\n    <a href=\"#\" @click.prevent=\"basicVisit\" class=\"visit\">Basic visit</a>\n    <a href=\"#\" @click.prevent=\"postVisit\" class=\"get\">POST visit</a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/Headers.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\nconst defaultHeadersMethod = () => {\n  router.visit('/dump/get')\n}\n\nconst visitWithCustomHeaders = () => {\n  router.visit('/dump/get', {\n    headers: {\n      foo: 'bar',\n    },\n  })\n}\n\nconst getMethod = () => {\n  router.get(\n    '/dump/get',\n    {},\n    {\n      headers: {\n        bar: 'baz',\n      },\n    },\n  )\n}\n\nconst postMethod = () => {\n  router.post(\n    '/dump/post',\n    {},\n    {\n      headers: {\n        baz: 'foo',\n      },\n    },\n  )\n}\n\nconst putMethod = () => {\n  router.put(\n    '/dump/put',\n    {},\n    {\n      headers: {\n        foo: 'bar',\n      },\n    },\n  )\n}\n\nconst patchMethod = () => {\n  router.patch(\n    '/dump/patch',\n    {},\n    {\n      headers: {\n        bar: 'baz',\n      },\n    },\n  )\n}\n\nconst deleteMethod = () => {\n  router.delete('/dump/delete', {\n    headers: {\n      baz: 'foo',\n    },\n  })\n}\n\nconst overridden = () => {\n  router.post(\n    '/dump/post',\n    {},\n    {\n      headers: {\n        bar: 'baz',\n        'X-Requested-With': 'custom',\n      },\n    },\n  )\n}\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the page that demonstrates passing custom headers through manual visits</span>\n\n    <a href=\"#\" @click.prevent=\"defaultHeadersMethod\" class=\"default\">Standard visit Link</a>\n\n    <a href=\"#\" @click.prevent=\"visitWithCustomHeaders\" class=\"visit\">Specific visit Link</a>\n    <a href=\"#\" @click.prevent=\"getMethod\" class=\"get\">GET Link</a>\n    <a href=\"#\" @click.prevent=\"postMethod\" class=\"post\">POST Link</a>\n    <a href=\"#\" @click.prevent=\"putMethod\" class=\"put\">PUT Link</a>\n    <a href=\"#\" @click.prevent=\"patchMethod\" class=\"patch\">PATCH Link</a>\n    <a href=\"#\" @click.prevent=\"deleteMethod\" class=\"delete\">DELETE Link</a>\n\n    <a href=\"#\" @click.prevent=\"overridden\" class=\"overridden\">Overriden Link</a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/Location.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\nconst locationVisit = (e: Event) => {\n  e.preventDefault()\n  router.visit('/location')\n}\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the page that demonstrates location visits</span>\n\n    <a href=\"#\" @click.prevent=\"locationVisit\" class=\"example\">Location visit</a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/Method.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\nconst standardVisitMethod = () => {\n  router.visit('/dump/get')\n}\n\nconst specificVisitMethod = () => {\n  router.visit('/dump/patch', {\n    method: 'patch',\n  })\n}\n\nconst getMethod = () => {\n  router.get('/dump/get')\n}\n\nconst postMethod = () => {\n  router.post('/dump/post')\n}\n\nconst putMethod = () => {\n  router.put('/dump/put')\n}\n\nconst patchMethod = () => {\n  router.patch('/dump/patch')\n}\n\nconst deleteMethod = () => {\n  router.delete('/dump/delete')\n}\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the page that demonstrates manual visit methods</span>\n\n    <a href=\"#\" @click.prevent=\"standardVisitMethod\" class=\"visit-get\">Standard visit Link</a>\n    <a href=\"#\" @click.prevent=\"specificVisitMethod\" class=\"visit-specific\">Specific visit Link</a>\n    <a href=\"#\" @click.prevent=\"getMethod\" class=\"get\">GET Link</a>\n    <a href=\"#\" @click.prevent=\"postMethod\" class=\"post\">POST Link</a>\n    <a href=\"#\" @click.prevent=\"putMethod\" class=\"put\">PUT Link</a>\n    <a href=\"#\" @click.prevent=\"patchMethod\" class=\"patch\">PATCH Link</a>\n    <a href=\"#\" @click.prevent=\"deleteMethod\" class=\"delete\">DELETE Link</a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/PartialReloads.vue",
    "content": "<script setup lang=\"ts\">\nimport { router, usePage } from '@inertiajs/vue3'\nimport { onMounted } from 'vue'\n\nconst props = defineProps({\n  foo: Number,\n  bar: Number,\n  baz: Number,\n  headers: Object,\n})\n\nconst page = usePage()\n\nonMounted(() => {\n  window._inertia_props = page.props\n})\n\nconst partialReloadVisit = () => {\n  router.visit('/visits/partial-reloads', {\n    data: { foo: props.foo },\n  })\n}\n\nconst partialReloadVisitFooBar = () => {\n  router.visit('/visits/partial-reloads', {\n    data: { foo: props.foo },\n    only: ['headers', 'foo', 'bar'],\n  })\n}\n\nconst partialReloadVisitBaz = () => {\n  router.visit('/visits/partial-reloads', {\n    data: { foo: props.foo },\n    only: ['headers', 'baz'],\n  })\n}\n\nconst partialReloadVisitExceptFooBar = () => {\n  router.visit('/visits/partial-reloads', {\n    data: { foo: props.foo },\n    except: ['foo', 'bar'],\n  })\n}\n\nconst partialReloadVisitExceptBaz = () => {\n  router.visit('/visits/partial-reloads', {\n    data: { foo: props.foo },\n    except: ['baz'],\n  })\n}\n\nconst partialReloadGet = () => {\n  router.get('/visits/partial-reloads', {\n    foo: props.foo,\n  })\n}\n\nconst partialReloadGetFooBar = () => {\n  router.get(\n    '/visits/partial-reloads',\n    {\n      foo: props.foo,\n    },\n    {\n      only: ['headers', 'foo', 'bar'],\n    },\n  )\n}\n\nconst partialReloadGetBaz = () => {\n  router.get(\n    '/visits/partial-reloads',\n    {\n      foo: props.foo,\n    },\n    {\n      only: ['headers', 'baz'],\n    },\n  )\n}\n\nconst partialReloadGetExceptFooBar = () => {\n  router.get(\n    '/visits/partial-reloads',\n    {\n      foo: props.foo,\n    },\n    {\n      except: ['foo', 'bar'],\n    },\n  )\n}\n\nconst partialReloadGetExceptBaz = () => {\n  router.get(\n    '/visits/partial-reloads',\n    {\n      foo: props.foo,\n    },\n    {\n      except: ['baz'],\n    },\n  )\n}\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the page that demonstrates partial reloads using manual visits</span>\n    <span class=\"foo-text\">Foo is now {{ foo }}</span>\n    <span class=\"bar-text\">Bar is now {{ bar }}</span>\n    <span class=\"baz-text\">Baz is now {{ baz }}</span>\n    <pre class=\"headers\">{{ headers }}</pre>\n\n    <a href=\"#\" @click.prevent=\"partialReloadVisit\" class=\"visit\">Update All (visit)</a>\n    <a href=\"#\" @click.prevent=\"partialReloadVisitFooBar\" class=\"visit-foo-bar\">'Only' foo + bar (visit)</a>\n    <a href=\"#\" @click.prevent=\"partialReloadVisitBaz\" class=\"visit-baz\">'Only' baz (visit)</a>\n    <a href=\"#\" @click.prevent=\"partialReloadVisitExceptFooBar\" class=\"visit-except-foo-bar\"\n      >'Except' foo + bar (visit)</a\n    >\n    <a href=\"#\" @click.prevent=\"partialReloadVisitExceptBaz\" class=\"visit-except-baz\">'Except' baz (visit)</a>\n\n    <a href=\"#\" @click.prevent=\"partialReloadGet\" class=\"get\">Update All (GET)</a>\n    <a href=\"#\" @click.prevent=\"partialReloadGetFooBar\" class=\"get-foo-bar\">'Only' foo + bar (GET)</a>\n    <a href=\"#\" @click.prevent=\"partialReloadGetBaz\" class=\"get-baz\">'Only' baz (GET)</a>\n    <a href=\"#\" @click.prevent=\"partialReloadGetExceptFooBar\" class=\"get-except-foo-bar\">'Except' foo + bar (GET)</a>\n    <a href=\"#\" @click.prevent=\"partialReloadGetExceptBaz\" class=\"get-except-baz\">'Except' baz (GET)</a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/PreserveScroll.vue",
    "content": "<script setup lang=\"ts\">\nimport WithScrollRegion from '@/Layouts/WithScrollRegion.vue'\nimport { router } from '@inertiajs/vue3'\n\ndefineOptions({\n  layout: WithScrollRegion,\n})\n\ndefineProps({\n  foo: {\n    type: String,\n    default: 'default',\n  },\n})\n\nconst preserve = () => {\n  router.visit('/visits/preserve-scroll-page-two', {\n    data: { foo: 'foo' },\n    preserveScroll: true,\n  })\n}\n\nconst preserveFalse = () => {\n  router.visit('/visits/preserve-scroll-page-two', {\n    data: { foo: 'bar' },\n  })\n}\n\nconst preserveCallback = () => {\n  router.visit('/visits/preserve-scroll-page-two', {\n    data: { foo: 'baz' },\n    preserveScroll: (page) => {\n      console.log(JSON.stringify(page))\n\n      return true\n    },\n  })\n}\n\nconst preserveCallbackFalse = () => {\n  router.visit('/visits/preserve-scroll-page-two', {\n    data: { foo: 'foo' },\n    preserveScroll: (page) => {\n      console.log(JSON.stringify(page))\n\n      return false\n    },\n  })\n}\n\nconst preserveGet = () => {\n  router.get(\n    '/visits/preserve-scroll-page-two',\n    {\n      foo: 'bar',\n    },\n    {\n      preserveScroll: true,\n    },\n  )\n}\n\nconst preserveGetFalse = () => {\n  router.get('/visits/preserve-scroll-page-two', {\n    foo: 'baz',\n  })\n}\n</script>\n\n<template>\n  <div style=\"height: 800px; width: 600px\">\n    <span class=\"text\"\n      >This is the page that demonstrates scroll preservation with scroll regions when using manual visits</span\n    >\n    <span class=\"foo\">Foo is now {{ foo }}</span>\n\n    <a href=\"#\" @click.prevent=\"preserve\" class=\"preserve\">Preserve Scroll</a>\n    <a href=\"#\" @click.prevent=\"preserveFalse\" class=\"reset\">Reset Scroll</a>\n    <a href=\"#\" @click.prevent=\"preserveCallback\" class=\"preserve-callback\">Preserve Scroll (Callback)</a>\n    <br />\n    <a href=\"#\" @click.prevent=\"preserveCallbackFalse\" class=\"reset-callback\">Reset Scroll (Callback)</a>\n    <a href=\"#\" @click.prevent=\"preserveGet\" class=\"preserve-get\">Preserve Scroll (GET)</a>\n    <a href=\"#\" @click.prevent=\"preserveGetFalse\" class=\"reset-get\">Reset Scroll (GET)</a>\n\n    <a href=\"/non-inertia\" class=\"off-site\">Off-site link</a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/PreserveScrollFalse.vue",
    "content": "<script setup lang=\"ts\">\nimport WithoutScrollRegion from '@/Layouts/WithoutScrollRegion.vue'\nimport { router } from '@inertiajs/vue3'\n\ndefineOptions({\n  layout: WithoutScrollRegion,\n})\n\ndefineProps({\n  foo: {\n    type: String,\n    default: 'default',\n  },\n})\n\nconst preserve = () => {\n  router.visit('/visits/preserve-scroll-false-page-two', {\n    data: { foo: 'foo' },\n    preserveScroll: true,\n  })\n}\n\nconst preserveFalse = () => {\n  router.visit('/visits/preserve-scroll-false-page-two', {\n    data: { foo: 'bar' },\n  })\n}\n\nconst preserveCallback = () => {\n  router.visit('/visits/preserve-scroll-false-page-two', {\n    data: { foo: 'baz' },\n    preserveScroll: (page) => {\n      console.log(JSON.stringify(page))\n\n      return true\n    },\n  })\n}\n\nconst preserveCallbackFalse = () => {\n  router.visit('/visits/preserve-scroll-false-page-two', {\n    data: { foo: 'foo' },\n    preserveScroll: (page) => {\n      console.log(JSON.stringify(page))\n\n      return false\n    },\n  })\n}\n\nconst preserveGet = () => {\n  router.get(\n    '/visits/preserve-scroll-false-page-two',\n    {\n      foo: 'bar',\n    },\n    {\n      preserveScroll: true,\n    },\n  )\n}\n\nconst preserveGetFalse = () => {\n  router.get('/visits/preserve-scroll-false-page-two', {\n    foo: 'baz',\n  })\n}\n</script>\n<template>\n  <div style=\"height: 800px; width: 600px\">\n    <span class=\"text\"\n      >This is the page that demonstrates scroll preservation without scroll regions when using manual visits</span\n    >\n    <span class=\"foo\">Foo is now {{ foo }}</span>\n\n    <a href=\"#\" @click.prevent=\"preserve\" class=\"preserve\">Preserve Scroll</a>\n    <a href=\"#\" @click.prevent=\"preserveFalse\" class=\"reset\">Reset Scroll</a>\n    <a href=\"#\" @click.prevent=\"preserveCallback\" class=\"preserve-callback\">Preserve Scroll (Callback)</a>\n    <br />\n    <a href=\"#\" @click.prevent=\"preserveCallbackFalse\" class=\"reset-callback\">Reset Scroll (Callback)</a>\n    <a href=\"#\" @click.prevent=\"preserveGet\" class=\"preserve-get\">Preserve Scroll (GET)</a>\n    <a href=\"#\" @click.prevent=\"preserveGetFalse\" class=\"reset-get\">Reset Scroll (GET)</a>\n\n    <a href=\"/non-inertia\" class=\"off-site\">Off-site link</a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/PreserveState.vue",
    "content": "<script setup lang=\"ts\">\nimport type { Page } from '@inertiajs/core'\nimport { router } from '@inertiajs/vue3'\nimport { getCurrentInstance, onMounted } from 'vue'\n\ndefineProps({\n  foo: {\n    type: String,\n    default: 'default',\n  },\n})\n\nonMounted(() => {\n  window._inertia_page_key = getCurrentInstance()?.uid\n})\n\nconst preserve = () => {\n  router.visit('/visits/preserve-state-page-two', {\n    data: { foo: 'bar' },\n    preserveState: true,\n  })\n}\n\nconst preserveFalse = () => {\n  router.visit('/visits/preserve-state-page-two', {\n    data: { foo: 'baz' },\n    preserveState: false,\n  })\n}\n\nconst preserveCallback = () => {\n  router.get(\n    '/visits/preserve-state-page-two',\n    {\n      foo: 'callback-bar',\n    },\n    {\n      preserveState: (page: Page) => {\n        alert(page)\n\n        return true\n      },\n    },\n  )\n}\n\nconst preserveCallbackFalse = () => {\n  router.get(\n    '/visits/preserve-state-page-two',\n    {\n      foo: 'callback-baz',\n    },\n    {\n      preserveState: (page: Page) => {\n        alert(page)\n\n        return false\n      },\n    },\n  )\n}\n\nconst preserveGet = () => {\n  router.get(\n    '/visits/preserve-state-page-two',\n    {\n      foo: 'get-bar',\n    },\n    {\n      preserveState: true,\n    },\n  )\n}\n\nconst preserveGetFalse = () => {\n  router.get(\n    '/visits/preserve-state-page-two',\n    {\n      foo: 'get-baz',\n    },\n    {\n      preserveState: false,\n    },\n  )\n}\n</script>\n<template>\n  <div>\n    <span class=\"text\">This is the page that demonstrates preserve state on manual visits</span>\n    <span class=\"foo\">Foo is now {{ foo }}</span>\n    <label>\n      Example Field\n      <input type=\"text\" name=\"example-field\" class=\"field\" />\n    </label>\n\n    <a href=\"#\" @click.prevent=\"preserve\" class=\"preserve\">[State] Preserve visit: true</a>\n    <a href=\"#\" @click.prevent=\"preserveFalse\" class=\"preserve-false\">[State] Preserve visit: false</a>\n    <a href=\"#\" @click.prevent=\"preserveCallback\" class=\"preserve-callback\">[State] Preserve Callback: true</a>\n    <a href=\"#\" @click.prevent=\"preserveCallbackFalse\" class=\"preserve-callback-false\"\n      >[State] Preserve Callback: false</a\n    >\n    <a href=\"#\" @click.prevent=\"preserveGet\" class=\"preserve-get\">[State] Preserve GET: true</a>\n    <a href=\"#\" @click.prevent=\"preserveGetFalse\" class=\"preserve-get-false\">[State] Preserve GET: false</a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/Proxy.vue",
    "content": "<script setup lang=\"ts\">\nimport { Deferred, Link, router } from '@inertiajs/vue3'\nimport { toRef } from 'vue'\n\nconst props = defineProps<{\n  foo: number\n  sites?: Array<{\n    id: number\n    latestDeployment: {\n      id: number\n      statuses: string[]\n    }\n  }>\n}>()\n\nconst sites = toRef(props, 'sites')\n\nconst updateFirstSite = () => {\n  if (sites.value && sites.value.length > 0) {\n    const incomingPartialData = { statuses: [`frontend-${Math.floor(Math.random() * 1_000_000)}`] }\n    sites.value[0].latestDeployment = { ...sites.value[0].latestDeployment, ...incomingPartialData }\n  }\n}\n\nfunction submit() {\n  router.post(\n    '/visits/proxy',\n    {},\n    {\n      preserveScroll: true,\n      preserveState: true,\n      only: ['foo'],\n    },\n  )\n}\n</script>\n\n<template>\n  <p id=\"foo\">Foo: {{ props.foo }}</p>\n\n  <Deferred data=\"sites\">\n    <template #fallback>Loading...</template>\n\n    <div v-for=\"site in sites\" :key=\"site.id\">\n      <p>Site ID: {{ site.id }}</p>\n      <p>Latest Deployment ID: {{ site.latestDeployment.id }}</p>\n      <p :id=\"`status-${site.id}`\">Statuses: {{ site.latestDeployment.statuses.join(', ') }}</p>\n    </div>\n  </Deferred>\n\n  <button @click=\"updateFirstSite\">Update First Site Ref</button>\n  <button @click=\"submit\">Reload</button>\n  <Link href=\"/\">Go Home</Link>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/ReloadOnMount.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\nimport { onMounted } from 'vue'\n\ndefineProps({\n  name: String,\n})\n\nonMounted(() => {\n  router.reload({ only: ['name'] })\n})\n</script>\n\n<template>\n  <div>Name is {{ name }}</div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/Replace.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\nconst replace = () => {\n  router.visit('/dump/get', {\n    replace: true,\n  })\n}\n\nconst replaceFalse = () => {\n  router.visit('/dump/get', {\n    replace: false,\n  })\n}\n\nconst replaceGet = () => {\n  router.get(\n    '/dump/get',\n    {},\n    {\n      replace: true,\n    },\n  )\n}\n\nconst replaceGetFalse = () => {\n  router.get(\n    '/dump/get',\n    {},\n    {\n      replace: false,\n    },\n  )\n}\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the links page that demonstrates manual replace</span>\n\n    <a href=\"#\" @click.prevent=\"replace\" class=\"replace\">[State] Replace visit: true</a>\n    <a href=\"#\" @click.prevent=\"replaceFalse\" class=\"replace-false\">[State] Replace visit: false</a>\n    <a href=\"#\" @click.prevent=\"replaceGet\" class=\"replace-get\">[State] Replace GET: true</a>\n    <a href=\"#\" @click.prevent=\"replaceGetFalse\" class=\"replace-get-false\">[State] Replace GET: false</a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/UrlFragments.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\nimport { onBeforeUnmount, onMounted, ref } from 'vue'\n\nconst documentScrollTop = ref(0)\nconst documentScrollLeft = ref(0)\n\nonMounted(() => {\n  document.addEventListener('scroll', handleScrollEvent)\n})\n\nonBeforeUnmount(() => {\n  document.removeEventListener('scroll', handleScrollEvent)\n})\n\nconst handleScrollEvent = () => {\n  documentScrollTop.value = document.documentElement.scrollTop\n  documentScrollLeft.value = document.documentElement.scrollLeft\n}\n\nconst basicVisit = () => {\n  router.visit('/visits/url-fragments#target')\n}\n\nconst fragmentVisit = () => {\n  router.visit('#target')\n}\n\nconst nonExistentFragmentVisit = () => {\n  router.visit('/visits/url-fragments#non-existent-fragment')\n}\n\nconst basicGetVisit = () => {\n  router.get('/visits/url-fragments#target')\n}\n\nconst fragmentGetVisit = () => {\n  router.get('#target')\n}\n\nconst nonExistentFragmentGetVisit = () => {\n  router.get('/visits/url-fragments#non-existent-fragment')\n}\n</script>\n\n<template>\n  <div>\n    <span class=\"text\">This is the page that demonstrates url fragment behaviour using manual visits</span>\n    <div style=\"width: 200vw; height: 200vh; margin-top: 50vh\">\n      <button @click=\"handleScrollEvent\">Update scroll positions</button>\n      <!-- prettier-ignore -->\n      <div class=\"document-position\">Document scroll position is {{ documentScrollLeft }} & {{ documentScrollTop }}</div>\n      <a href=\"#\" @click.prevent=\"basicVisit\" class=\"basic\">Basic visit</a>\n      <a href=\"#\" @click.prevent=\"fragmentVisit\" class=\"fragment\">Fragment visit</a>\n      <a href=\"#\" @click.prevent=\"nonExistentFragmentVisit\" class=\"non-existent-fragment\"\n        >Non-existent fragment visit</a\n      >\n\n      <a href=\"#\" @click.prevent=\"basicGetVisit\" class=\"basic-get\">Basic GET visit</a>\n      <a href=\"#\" @click.prevent=\"fragmentGetVisit\" class=\"fragment-get\">Fragment GET visit</a>\n      <a href=\"#\" @click.prevent=\"nonExistentFragmentGetVisit\" class=\"non-existent-fragment-get\"\n        >Non-existent fragment GET visit</a\n      >\n\n      <div id=\"target\">This is the element with id 'target'</div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/Visits/Wayfinder.vue",
    "content": "<script setup lang=\"ts\">\nimport { router } from '@inertiajs/vue3'\n\nconst wayfinderObjectVisit = () => {\n  router.visit({ url: '/dump/post', method: 'post' })\n}\n\nconst wayfinderObjectMethodOverride = () => {\n  router.visit({ url: '/dump/patch', method: 'get' }, { method: 'patch' })\n}\n</script>\n\n<template>\n  <div>\n    <a href=\"#\" @click.prevent=\"wayfinderObjectVisit\" class=\"wayfinder-visit\">Wayfinder object visit</a>\n    <a href=\"#\" @click.prevent=\"wayfinderObjectMethodOverride\" class=\"wayfinder-method-override\">\n      Wayfinder object method override\n    </a>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/WhenVisible.vue",
    "content": "<script setup lang=\"ts\">\nimport { WhenVisible } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst count = ref(0)\n</script>\n\n<template>\n  <div style=\"margin-top: 5000px\">\n    <WhenVisible data=\"foo\">\n      <template #fallback>\n        <div>Loading first one...</div>\n      </template>\n\n      <div>First one is visible!</div>\n    </WhenVisible>\n  </div>\n\n  <div style=\"margin-top: 5000px\">\n    <WhenVisible :buffer=\"1000\" data=\"foo\">\n      <template #fallback>\n        <div>Loading second one...</div>\n      </template>\n\n      <div>Second one is visible!</div>\n    </WhenVisible>\n  </div>\n\n  <div style=\"margin-top: 5000px\">\n    <WhenVisible data=\"foo\" always>\n      <template #fallback>\n        <div>Loading third one...</div>\n      </template>\n\n      <div>Third one is visible!</div>\n    </WhenVisible>\n  </div>\n\n  <div style=\"margin-top: 5000px\">\n    <WhenVisible data=\"foo\">\n      <template #fallback>\n        <div>Loading fourth one...</div>\n      </template>\n    </WhenVisible>\n  </div>\n\n  <div style=\"margin-top: 6000px\">\n    <WhenVisible\n      always\n      :params=\"{\n        data: {\n          count,\n        },\n        onSuccess: () => {\n          count += 1\n        },\n      }\"\n    >\n      <template #fallback>\n        <div>Loading fifth one...</div>\n      </template>\n\n      <div>Count is now {{ count }}</div>\n    </WhenVisible>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/WhenVisibleArrayReload.vue",
    "content": "<script setup lang=\"ts\">\nimport { router, WhenVisible } from '@inertiajs/vue3'\n\ndefineProps<{\n  firstData?: {\n    text: string\n  }\n  secondData?: {\n    text: string\n  }\n}>()\n</script>\n\n<template>\n  <div>\n    <h1>WhenVisible + Array Props + Reload</h1>\n\n    <button @click=\"router.reload()\">Reload Page</button>\n\n    <div style=\"margin-top: 2000px; padding: 20px; border: 1px solid #ccc\">\n      <WhenVisible :data=\"['firstData', 'secondData']\">\n        <template #fallback>\n          <p>Loading array data...</p>\n        </template>\n\n        <div>\n          <p>{{ firstData?.text }}</p>\n          <p>{{ secondData?.text }}</p>\n        </div>\n      </WhenVisible>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/WhenVisibleBackButton.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, WhenVisible } from '@inertiajs/vue3'\n\ndefineProps<{\n  lazyData?: {\n    text: string\n  }\n}>()\n</script>\n\n<template>\n  <div>\n    <h1>WhenVisible + Back Button</h1>\n\n    <Link href=\"/links/method\">Navigate Away</Link>\n\n    <div style=\"margin-top: 2000px; padding: 20px; border: 1px solid #ccc\">\n      <WhenVisible data=\"lazyData\">\n        <template #fallback>\n          <p>Loading lazy data...</p>\n        </template>\n\n        <p>{{ lazyData?.text }}</p>\n      </WhenVisible>\n    </div>\n\n    <div style=\"margin-top: 2000px; padding: 20px; border: 1px solid #ccc\">\n      <WhenVisible data=\"lazyData\" always>\n        <template #fallback>\n          <p>Loading always data...</p>\n        </template>\n\n        <p>Always: {{ lazyData?.text }}</p>\n      </WhenVisible>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/WhenVisibleFetching.vue",
    "content": "<script setup lang=\"ts\">\nimport { WhenVisible } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <div style=\"margin-top: 5000px\">\n    <WhenVisible data=\"lazyData\" always>\n      <template #default=\"{ fetching }\">\n        <div>Lazy data loaded!</div>\n        <div v-if=\"fetching\">Fetching in background...</div>\n      </template>\n\n      <template #fallback>\n        <div>Loading lazy data...</div>\n      </template>\n    </WhenVisible>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/WhenVisibleMergeParams.vue",
    "content": "<script setup lang=\"ts\">\nimport { WhenVisible } from '@inertiajs/vue3'\n\ndefineProps<{\n  dataOnlyProp?: { text: string }\n  mergedProp?: { text: string }\n  mergedWithCallbackProp?: { text: string }\n}>()\n</script>\n\n<template>\n  <div id=\"data-only\" style=\"margin-top: 3000px\">\n    <WhenVisible data=\"dataOnlyProp\">\n      <template #fallback>\n        <div>Loading data only...</div>\n      </template>\n      <div>Data only loaded: {{ dataOnlyProp?.text }}</div>\n    </WhenVisible>\n  </div>\n\n  <div id=\"merged\" style=\"margin-top: 5000px\">\n    <WhenVisible\n      data=\"mergedProp\"\n      :params=\"{\n        data: { extra: 'from-params' },\n      }\"\n    >\n      <template #fallback>\n        <div>Loading merged...</div>\n      </template>\n      <div>Merged loaded: {{ mergedProp?.text }}</div>\n    </WhenVisible>\n  </div>\n\n  <div id=\"merged-with-callback\" style=\"margin-top: 5000px\">\n    <WhenVisible\n      data=\"mergedWithCallbackProp\"\n      :params=\"{\n        data: { page: '2' },\n        preserveUrl: true,\n      }\"\n    >\n      <template #fallback>\n        <div>Loading merged with callback...</div>\n      </template>\n      <div>Merged with callback loaded: {{ mergedWithCallbackProp?.text }}</div>\n    </WhenVisible>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/WhenVisibleParamsUpdate.vue",
    "content": "<script setup lang=\"ts\">\nimport { WhenVisible } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\ndefineProps({\n  lazyData: Object,\n})\n\nconst paramValue = ref('initial')\n</script>\n\n<template>\n  <div>\n    <button @click=\"paramValue = 'updated'\">Update Param</button>\n    <p>Current param: {{ paramValue }}</p>\n\n    <div style=\"margin-top: 3000px\">\n      <WhenVisible data=\"lazyData\" :params=\"{ data: { paramValue } }\" always>\n        <div>\n          <p>Data loaded: {{ lazyData?.text }}</p>\n        </div>\n        <template #fallback>\n          <p>Loading lazy data...</p>\n        </template>\n      </WhenVisible>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/Pages/WhenVisibleReload.vue",
    "content": "<script setup lang=\"ts\">\nimport { router, WhenVisible } from '@inertiajs/vue3'\n\ndefineProps<{\n  lazyData?: {\n    text: string\n  }\n}>()\n</script>\n\n<template>\n  <div>\n    <h1>WhenVisible + Reload</h1>\n\n    <button @click=\"router.reload()\">Reload Page</button>\n\n    <div style=\"margin-top: 2000px; padding: 20px; border: 1px solid #ccc\">\n      <WhenVisible data=\"lazyData\">\n        <template #fallback>\n          <p>Loading lazy data...</p>\n        </template>\n\n        {{ lazyData?.text }}\n      </WhenVisible>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "packages/vue3/test-app/app.ts",
    "content": "import type { VisitOptions } from '@inertiajs/core'\nimport { createInertiaApp, router } from '@inertiajs/vue3'\nimport type { DefineComponent } from 'vue'\nimport { createApp, h } from 'vue'\n\nwindow.testing = { Inertia: router }\n\nconst withAppDefaults = new URLSearchParams(window.location.search).get('withAppDefaults')\n\ncreateInertiaApp({\n  page: window.initialPage,\n  resolve: async (name) => {\n    const pages = import.meta.glob<DefineComponent>('./Pages/**/*.vue', { eager: true })\n\n    if (name === 'DeferredProps/InstantReload') {\n      // Add small delay to ensure the component is loaded after the initial page load\n      // This is for projects that don't use { eager: true } in import.meta.glob\n      await new Promise((resolve) => setTimeout(resolve, 50))\n    }\n\n    return pages[`./Pages/${name}.vue`]\n  },\n  setup({ el, App, props, plugin }) {\n    const inst = createApp({ render: () => h(App, props) })\n\n    if (!window.location.pathname.startsWith('/plugin/without')) {\n      inst.use(plugin)\n    }\n\n    inst.mount(el)\n  },\n  ...(withAppDefaults && {\n    defaults: {\n      visitOptions: (href: string, options: VisitOptions) => {\n        return { headers: { ...options.headers, 'X-From-App-Defaults': 'test' } }\n      },\n    },\n  }),\n})\n"
  },
  {
    "path": "packages/vue3/test-app/eslint.config.js",
    "content": "import prettier from 'eslint-config-prettier/flat'\nimport vue from 'eslint-plugin-vue'\nimport globals from 'globals'\n\nimport { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript'\n\nexport default defineConfigWithVueTs(\n  {\n    files: ['**/*.vue', '**/*.js', '**/*.ts'],\n  },\n  {\n    ignores: ['node_modules', 'dist/**/*', '*.config.js', '**/*.d.ts', '*.timestamp-*'],\n  },\n  vue.configs['flat/essential'],\n  vueTsConfigs.recommended,\n  {\n    languageOptions: {\n      ecmaVersion: 2020,\n      sourceType: 'module',\n      globals: {\n        ...globals.browser,\n        ...globals.es2020,\n      },\n      parserOptions: {\n        projectService: true,\n        tsconfigRootDir: import.meta.dirname,\n      },\n    },\n  },\n  {\n    rules: {\n      'vue/multi-word-component-names': 'off',\n      '@typescript-eslint/unbound-method': 'error',\n    },\n  },\n  prettier,\n)\n"
  },
  {
    "path": "packages/vue3/test-app/index.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title {{ headAttribute }}>Inertia Vue - Testing Environment</title>\n    <script>\n      window.initialPage = '{{ placeholder }}'\n    </script>\n    <script type=\"module\" src=\"app.ts\"></script>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/vue3/test-app/package.json",
    "content": "{\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"vite build .\",\n    \"build:ssr\": \"vite build --ssr ssr.ts --outDir dist\",\n    \"dev\": \"nodemon --watch . --watch ../../core/dist --watch ../../vue3/dist --ext js,vue,html,json --ignore dist/ --exec 'vite build .'\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"vue-tsc --noEmit\"\n  },\n  \"devDependencies\": {\n    \"@vitejs/plugin-vue\": \"^6.0.4\",\n    \"@vue/eslint-config-typescript\": \"^14.7.0\",\n    \"eslint\": \"^9.39.3\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"eslint-plugin-vue\": \"^10.8.0\",\n    \"globals\": \"^17.3.0\",\n    \"nodemon\": \"^3.1.14\",\n    \"typescript\": \"^5.9.3\",\n    \"typescript-eslint\": \"^8.56.1\",\n    \"vite\": \"^7.3.1\",\n    \"vue\": \"^3.5.29\",\n    \"vue-tsc\": \"^3.2.5\"\n  },\n  \"dependencies\": {\n    \"@inertiajs/core\": \"workspace:*\",\n    \"@inertiajs/vue3\": \"workspace:*\"\n  }\n}\n"
  },
  {
    "path": "packages/vue3/test-app/ssr.ts",
    "content": "import { createInertiaApp } from '@inertiajs/vue3'\nimport createServer from '@inertiajs/vue3/server'\nimport { createSSRApp, h, type DefineComponent } from 'vue'\nimport { renderToString } from 'vue/server-renderer'\n\ncreateServer((page) =>\n  createInertiaApp({\n    page,\n    render: renderToString,\n    resolve: (name) => {\n      const pages = import.meta.glob<DefineComponent>('./Pages/SSR/**/*.vue', { eager: true })\n      return pages[`./Pages/${name}.vue`]\n    },\n    setup({ App, props, plugin }) {\n      return createSSRApp({\n        render: () => h(App, props),\n      }).use(plugin)\n    },\n    defaults: {\n      future: {\n        useScriptElementForInitialPage: page.component === 'SSR/PageWithScriptElement',\n      },\n    },\n  }),\n)\n"
  },
  {
    "path": "packages/vue3/test-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ESNext\", \"DOM\", \"DOM.Iterable\"],\n    \"jsx\": \"preserve\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"paths\": {\n      \"@/*\": [\"./*\"]\n    },\n    \"resolveJsonModule\": true,\n    \"allowJs\": true,\n    \"sourceMap\": true,\n    \"noEmit\": true,\n    \"isolatedModules\": true,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"strict\": true,\n    \"skipLibCheck\": true\n  },\n  \"include\": [\"**/*.ts\", \"**/*.d.ts\", \"**/*.vue\"]\n}\n"
  },
  {
    "path": "packages/vue3/test-app/types.d.ts",
    "content": "import type { Method, Page, PageProps, Router } from '@inertiajs/core'\n\ndeclare global {\n  interface Window {\n    testing: {\n      Inertia: Router\n    }\n    initialPage: Page\n    _inertia_request_dump: {\n      headers: Record<string, string>\n      method: Method\n      form: Record<string, unknown> | undefined\n      files: MulterFile[] | object\n      query: Record<string, unknown>\n      url: string\n      $page: Page\n    }\n    _inertia_page_key: number | undefined\n    _inertia_props: PageProps\n    _inertia_layout_id: number | undefined\n    _inertia_site_layout_props: PageProps\n    _inertia_nested_layout_id: number | undefined\n    _inertia_nested_layout_props: PageProps\n    _inertia_page_props: PageProps\n    _plugin_global_props: object\n  }\n\n  interface ImportMeta {\n    readonly glob: <T>(pattern: string, options: { eager: true }) => Record<string, T>\n  }\n}\n\nexport type MulterFile = Express.Multer.File\n"
  },
  {
    "path": "packages/vue3/test-app/vite.config.ts",
    "content": "import vue from '@vitejs/plugin-vue'\nimport { defineConfig } from 'vite'\n\nconst isSSR = process.argv.includes('--ssr')\n\nexport default defineConfig({\n  build: {\n    minify: false,\n    emptyOutDir: !isSSR,\n  },\n  resolve: {\n    alias: {\n      '@': __dirname,\n    },\n  },\n  plugins: [\n    vue({\n      features: { prodDevtools: true },\n    }),\n  ],\n})\n"
  },
  {
    "path": "packages/vue3/tsconfig.json",
    "content": "{\n  \"include\": [\"src/index.ts\", \"src/server.ts\"],\n  \"compilerOptions\": {\n    \"rootDir\": \"src\",\n    \"noEmitOnError\": true,\n\n    \"lib\": [\"DOM\", \"DOM.Iterable\", \"ES2020\"],\n    \"target\": \"ES2020\",\n\n    \"declaration\": true,\n    \"declarationDir\": \"types\",\n    \"emitDeclarationOnly\": true,\n\n    \"module\": \"ES2020\",\n    \"moduleResolution\": \"Node\",\n    \"resolveJsonModule\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"skipLibCheck\": true,\n\n    \"noImplicitThis\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"preserveConstEnums\": true,\n    \"removeComments\": true,\n    \"typeRoots\": [\"./node_modules/@types\"],\n    \"strict\": true\n  }\n}\n"
  },
  {
    "path": "playgrounds/react/.gitattributes",
    "content": "* text=auto\n\n*.blade.php diff=html\n*.css diff=css\n*.html diff=html\n*.md diff=markdown\n*.php diff=php\n\n/.github export-ignore\nCHANGELOG.md export-ignore\n.styleci.yml export-ignore\n"
  },
  {
    "path": "playgrounds/react/.gitignore",
    "content": "/node_modules\n/bootstrap/ssr\n/public/build\n/public/hot\n/public/storage\n/storage/*.key\n/vendor\n.env\n.env.backup\n.env.production\n.phpunit.result.cache\nHomestead.json\nHomestead.yaml\nauth.json\nnpm-debug.log\nyarn-error.log\n/.fleet\n/.idea\n/.vscode\n"
  },
  {
    "path": "playgrounds/react/README.md",
    "content": "<p align=\"center\"><a href=\"https://laravel.com\" target=\"_blank\"><img src=\"https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg\" width=\"400\" alt=\"Laravel Logo\"></a></p>\n\n<p align=\"center\">\n<a href=\"https://travis-ci.org/laravel/framework\"><img src=\"https://travis-ci.org/laravel/framework.svg\" alt=\"Build Status\"></a>\n<a href=\"https://packagist.org/packages/laravel/framework\"><img src=\"https://img.shields.io/packagist/dt/laravel/framework\" alt=\"Total Downloads\"></a>\n<a href=\"https://packagist.org/packages/laravel/framework\"><img src=\"https://img.shields.io/packagist/v/laravel/framework\" alt=\"Latest Stable Version\"></a>\n<a href=\"https://packagist.org/packages/laravel/framework\"><img src=\"https://img.shields.io/packagist/l/laravel/framework\" alt=\"License\"></a>\n</p>\n\n## About Laravel\n\nLaravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:\n\n- [Simple, fast routing engine](https://laravel.com/docs/routing).\n- [Powerful dependency injection container](https://laravel.com/docs/container).\n- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.\n- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).\n- Database agnostic [schema migrations](https://laravel.com/docs/migrations).\n- [Robust background job processing](https://laravel.com/docs/queues).\n- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).\n\nLaravel is accessible, powerful, and provides tools required for large, robust applications.\n\n## Learning Laravel\n\nLaravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.\n\nYou may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.\n\nIf you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 2000 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.\n\n## Laravel Sponsors\n\nWe would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell).\n\n### Premium Partners\n\n- **[Vehikl](https://vehikl.com/)**\n- **[Tighten Co.](https://tighten.co)**\n- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**\n- **[64 Robots](https://64robots.com)**\n- **[Cubet Techno Labs](https://cubettech.com)**\n- **[Cyber-Duck](https://cyber-duck.co.uk)**\n- **[Many](https://www.many.co.uk)**\n- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**\n- **[DevSquad](https://devsquad.com)**\n- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**\n- **[OP.GG](https://op.gg)**\n- **[WebReinvent](https://webreinvent.com/?utm_source=laravel&utm_medium=github&utm_campaign=patreon-sponsors)**\n- **[Lendio](https://lendio.com)**\n\n## Contributing\n\nThank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).\n\n## Code of Conduct\n\nIn order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).\n\n## Security Vulnerabilities\n\nIf you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.\n\n## License\n\nThe Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).\n"
  },
  {
    "path": "playgrounds/react/app/Console/Kernel.php",
    "content": "<?php\n\nnamespace App\\Console;\n\nuse Illuminate\\Console\\Scheduling\\Schedule;\nuse Illuminate\\Foundation\\Console\\Kernel as ConsoleKernel;\n\nclass Kernel extends ConsoleKernel\n{\n    /**\n     * Define the application's command schedule.\n     *\n     * @param  \\Illuminate\\Console\\Scheduling\\Schedule  $schedule\n     * @return void\n     */\n    protected function schedule(Schedule $schedule)\n    {\n        // $schedule->command('inspire')->hourly();\n    }\n\n    /**\n     * Register the commands for the application.\n     *\n     * @return void\n     */\n    protected function commands()\n    {\n        $this->load(__DIR__.'/Commands');\n\n        require base_path('routes/console.php');\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/app/Exceptions/Handler.php",
    "content": "<?php\n\nnamespace App\\Exceptions;\n\nuse Illuminate\\Foundation\\Exceptions\\Handler as ExceptionHandler;\nuse Throwable;\n\nclass Handler extends ExceptionHandler\n{\n    /**\n     * A list of exception types with their corresponding custom log levels.\n     *\n     * @var array<class-string<\\Throwable>, \\Psr\\Log\\LogLevel::*>\n     */\n    protected $levels = [\n        //\n    ];\n\n    /**\n     * A list of the exception types that are not reported.\n     *\n     * @var array<int, class-string<\\Throwable>>\n     */\n    protected $dontReport = [\n        //\n    ];\n\n    /**\n     * A list of the inputs that are never flashed to the session on validation exceptions.\n     *\n     * @var array<int, string>\n     */\n    protected $dontFlash = [\n        'current_password',\n        'password',\n        'password_confirmation',\n    ];\n\n    /**\n     * Register the exception handling callbacks for the application.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        $this->reportable(function (Throwable $e) {\n            //\n        });\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/app/Http/Controllers/Controller.php",
    "content": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Foundation\\Auth\\Access\\AuthorizesRequests;\nuse Illuminate\\Foundation\\Bus\\DispatchesJobs;\nuse Illuminate\\Foundation\\Validation\\ValidatesRequests;\nuse Illuminate\\Routing\\Controller as BaseController;\n\nclass Controller extends BaseController\n{\n    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;\n}\n"
  },
  {
    "path": "playgrounds/react/app/Http/Kernel.php",
    "content": "<?php\n\nnamespace App\\Http;\n\nuse Illuminate\\Foundation\\Http\\Kernel as HttpKernel;\n\nclass Kernel extends HttpKernel\n{\n    /**\n     * The application's global HTTP middleware stack.\n     *\n     * These middleware are run during every request to your application.\n     *\n     * @var array<int, class-string|string>\n     */\n    protected $middleware = [\n        // \\App\\Http\\Middleware\\TrustHosts::class,\n        \\App\\Http\\Middleware\\TrustProxies::class,\n        \\Illuminate\\Http\\Middleware\\HandleCors::class,\n        \\App\\Http\\Middleware\\PreventRequestsDuringMaintenance::class,\n        \\Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize::class,\n        \\App\\Http\\Middleware\\TrimStrings::class,\n        \\Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull::class,\n    ];\n\n    /**\n     * The application's route middleware groups.\n     *\n     * @var array<string, array<int, class-string|string>>\n     */\n    protected $middlewareGroups = [\n        'web' => [\n            \\App\\Http\\Middleware\\EncryptCookies::class,\n            \\Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse::class,\n            \\Illuminate\\Session\\Middleware\\StartSession::class,\n            \\Illuminate\\View\\Middleware\\ShareErrorsFromSession::class,\n            \\App\\Http\\Middleware\\VerifyCsrfToken::class,\n            \\Illuminate\\Routing\\Middleware\\SubstituteBindings::class,\n            \\App\\Http\\Middleware\\HandleInertiaRequests::class,\n        ],\n\n        'api' => [\n            // \\Laravel\\Sanctum\\Http\\Middleware\\EnsureFrontendRequestsAreStateful::class,\n            'throttle:api',\n            \\Illuminate\\Routing\\Middleware\\SubstituteBindings::class,\n        ],\n    ];\n\n    /**\n     * The application's route middleware.\n     *\n     * These middleware may be assigned to groups or used individually.\n     *\n     * @var array<string, class-string|string>\n     */\n    protected $routeMiddleware = [\n        'auth' => \\App\\Http\\Middleware\\Authenticate::class,\n        'auth.basic' => \\Illuminate\\Auth\\Middleware\\AuthenticateWithBasicAuth::class,\n        'auth.session' => \\Illuminate\\Session\\Middleware\\AuthenticateSession::class,\n        'cache.headers' => \\Illuminate\\Http\\Middleware\\SetCacheHeaders::class,\n        'can' => \\Illuminate\\Auth\\Middleware\\Authorize::class,\n        'guest' => \\App\\Http\\Middleware\\RedirectIfAuthenticated::class,\n        'password.confirm' => \\Illuminate\\Auth\\Middleware\\RequirePassword::class,\n        'signed' => \\App\\Http\\Middleware\\ValidateSignature::class,\n        'throttle' => \\Illuminate\\Routing\\Middleware\\ThrottleRequests::class,\n        'verified' => \\Illuminate\\Auth\\Middleware\\EnsureEmailIsVerified::class,\n    ];\n}\n"
  },
  {
    "path": "playgrounds/react/app/Http/Middleware/Authenticate.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Auth\\Middleware\\Authenticate as Middleware;\n\nclass Authenticate extends Middleware\n{\n    /**\n     * Get the path the user should be redirected to when they are not authenticated.\n     *\n     * @param  \\Illuminate\\Http\\Request  $request\n     * @return string|null\n     */\n    protected function redirectTo($request)\n    {\n        if (! $request->expectsJson()) {\n            return route('login');\n        }\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/app/Http/Middleware/EncryptCookies.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Cookie\\Middleware\\EncryptCookies as Middleware;\n\nclass EncryptCookies extends Middleware\n{\n    /**\n     * The names of the cookies that should not be encrypted.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        //\n    ];\n}\n"
  },
  {
    "path": "playgrounds/react/app/Http/Middleware/HandleInertiaRequests.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Http\\Request;\nuse Inertia\\Middleware;\n\nclass HandleInertiaRequests extends Middleware\n{\n    /**\n     * The root template that's loaded on the first page visit.\n     *\n     * @see https://inertiajs.com/server-side-setup#root-template\n     * @var string\n     */\n    protected $rootView = 'app';\n\n    /**\n     * Determines the current asset version.\n     *\n     * @see https://inertiajs.com/asset-versioning\n     * @param  \\Illuminate\\Http\\Request  $request\n     * @return string|null\n     */\n    public function version(Request $request): ?string\n    {\n        return parent::version($request);\n    }\n\n    /**\n     * Defines the props that are shared by default.\n     *\n     * @see https://inertiajs.com/shared-data\n     * @param  \\Illuminate\\Http\\Request  $request\n     * @return array\n     */\n    public function share(Request $request): array\n    {\n        return array_merge(parent::share($request), [\n            'appName' => config('app.name'),\n        ]);\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/app/Http/Middleware/PreventRequestsDuringMaintenance.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance as Middleware;\n\nclass PreventRequestsDuringMaintenance extends Middleware\n{\n    /**\n     * The URIs that should be reachable while maintenance mode is enabled.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        //\n    ];\n}\n"
  },
  {
    "path": "playgrounds/react/app/Http/Middleware/RedirectIfAuthenticated.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse App\\Providers\\RouteServiceProvider;\nuse Closure;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Auth;\n\nclass RedirectIfAuthenticated\n{\n    /**\n     * Handle an incoming request.\n     *\n     * @param  \\Illuminate\\Http\\Request  $request\n     * @param  \\Closure(\\Illuminate\\Http\\Request): (\\Illuminate\\Http\\Response|\\Illuminate\\Http\\RedirectResponse)  $next\n     * @param  string|null  ...$guards\n     * @return \\Illuminate\\Http\\Response|\\Illuminate\\Http\\RedirectResponse\n     */\n    public function handle(Request $request, Closure $next, ...$guards)\n    {\n        $guards = empty($guards) ? [null] : $guards;\n\n        foreach ($guards as $guard) {\n            if (Auth::guard($guard)->check()) {\n                return redirect(RouteServiceProvider::HOME);\n            }\n        }\n\n        return $next($request);\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/app/Http/Middleware/TrimStrings.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Foundation\\Http\\Middleware\\TrimStrings as Middleware;\n\nclass TrimStrings extends Middleware\n{\n    /**\n     * The names of the attributes that should not be trimmed.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        'current_password',\n        'password',\n        'password_confirmation',\n    ];\n}\n"
  },
  {
    "path": "playgrounds/react/app/Http/Middleware/TrustHosts.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Http\\Middleware\\TrustHosts as Middleware;\n\nclass TrustHosts extends Middleware\n{\n    /**\n     * Get the host patterns that should be trusted.\n     *\n     * @return array<int, string|null>\n     */\n    public function hosts()\n    {\n        return [\n            $this->allSubdomainsOfApplicationUrl(),\n        ];\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/app/Http/Middleware/TrustProxies.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Http\\Middleware\\TrustProxies as Middleware;\nuse Illuminate\\Http\\Request;\n\nclass TrustProxies extends Middleware\n{\n    /**\n     * The trusted proxies for this application.\n     *\n     * @var array<int, string>|string|null\n     */\n    protected $proxies;\n\n    /**\n     * The headers that should be used to detect proxies.\n     *\n     * @var int\n     */\n    protected $headers =\n        Request::HEADER_X_FORWARDED_FOR |\n        Request::HEADER_X_FORWARDED_HOST |\n        Request::HEADER_X_FORWARDED_PORT |\n        Request::HEADER_X_FORWARDED_PROTO |\n        Request::HEADER_X_FORWARDED_AWS_ELB;\n}\n"
  },
  {
    "path": "playgrounds/react/app/Http/Middleware/ValidateSignature.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Routing\\Middleware\\ValidateSignature as Middleware;\n\nclass ValidateSignature extends Middleware\n{\n    /**\n     * The names of the query string parameters that should be ignored.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        // 'fbclid',\n        // 'utm_campaign',\n        // 'utm_content',\n        // 'utm_medium',\n        // 'utm_source',\n        // 'utm_term',\n    ];\n}\n"
  },
  {
    "path": "playgrounds/react/app/Http/Middleware/VerifyCsrfToken.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Foundation\\Http\\Middleware\\VerifyCsrfToken as Middleware;\n\nclass VerifyCsrfToken extends Middleware\n{\n    /**\n     * The URIs that should be excluded from CSRF verification.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        //\n    ];\n}\n"
  },
  {
    "path": "playgrounds/react/app/Http/Requests/PrecognitionFormRequest.php",
    "content": "<?php\n\nnamespace App\\Http\\Requests;\n\nuse Illuminate\\Foundation\\Http\\FormRequest;\n\nclass PrecognitionFormRequest extends FormRequest\n{\n    /**\n     * Determine if the user is authorized to make this request.\n     */\n    public function authorize(): bool\n    {\n        return true;\n    }\n\n    /**\n     * Get the validation rules that apply to the request.\n     *\n     * @return array<string, \\Illuminate\\Contracts\\Validation\\ValidationRule|array<mixed>|string>\n     */\n    public function rules(): array\n    {\n        sleep(1);\n\n        return [\n            'name' => ['required', 'string', 'min:3', 'max:255'],\n            'email' => ['required', 'email', 'max:255'],\n            'avatar' => ['nullable', 'file', 'image'],\n        ];\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/app/Http/Resources/UserResource.php",
    "content": "<?php\n\nnamespace App\\Http\\Resources;\n\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Http\\Resources\\Json\\JsonResource;\n\nclass UserResource extends JsonResource\n{\n    /**\n     * Transform the resource into an array.\n     *\n     * @return array<string, mixed>\n     */\n    public function toArray(Request $request): array\n    {\n        return parent::toArray($request);\n    }\n}"
  },
  {
    "path": "playgrounds/react/app/Models/ChatMessage.php",
    "content": "<?php\n\nnamespace App\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\n\nclass ChatMessage extends Model\n{\n    protected $hidden = ['updated_at'];\n\n    protected $guarded = [];\n\n    use HasFactory;\n}"
  },
  {
    "path": "playgrounds/react/app/Models/User.php",
    "content": "<?php\n\nnamespace App\\Models;\n\n// use Illuminate\\Contracts\\Auth\\MustVerifyEmail;\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Foundation\\Auth\\User as Authenticatable;\nuse Illuminate\\Notifications\\Notifiable;\nuse Laravel\\Sanctum\\HasApiTokens;\n\nclass User extends Authenticatable\n{\n    use HasApiTokens, HasFactory, Notifiable;\n\n    /**\n     * The attributes that are mass assignable.\n     *\n     * @var array<int, string>\n     */\n    protected $fillable = [\n        'name',\n        'email',\n        'password',\n    ];\n\n    /**\n     * The attributes that should be hidden for serialization.\n     *\n     * @var array<int, string>\n     */\n    protected $hidden = [\n        'password',\n        'remember_token',\n    ];\n\n    /**\n     * The attributes that should be cast.\n     *\n     * @var array<string, string>\n     */\n    protected $casts = [\n        'email_verified_at' => 'datetime',\n    ];\n}\n"
  },
  {
    "path": "playgrounds/react/app/Providers/AppServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Support\\ServiceProvider;\n\nclass AppServiceProvider extends ServiceProvider\n{\n    /**\n     * Register any application services.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        //\n    }\n\n    /**\n     * Bootstrap any application services.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/app/Providers/AuthServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\n// use Illuminate\\Support\\Facades\\Gate;\nuse Illuminate\\Foundation\\Support\\Providers\\AuthServiceProvider as ServiceProvider;\n\nclass AuthServiceProvider extends ServiceProvider\n{\n    /**\n     * The model to policy mappings for the application.\n     *\n     * @var array<class-string, class-string>\n     */\n    protected $policies = [\n        // 'App\\Models\\Model' => 'App\\Policies\\ModelPolicy',\n    ];\n\n    /**\n     * Register any authentication / authorization services.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        $this->registerPolicies();\n\n        //\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/app/Providers/BroadcastServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Support\\Facades\\Broadcast;\nuse Illuminate\\Support\\ServiceProvider;\n\nclass BroadcastServiceProvider extends ServiceProvider\n{\n    /**\n     * Bootstrap any application services.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        Broadcast::routes();\n\n        require base_path('routes/channels.php');\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/app/Providers/EventServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Auth\\Events\\Registered;\nuse Illuminate\\Auth\\Listeners\\SendEmailVerificationNotification;\nuse Illuminate\\Foundation\\Support\\Providers\\EventServiceProvider as ServiceProvider;\nuse Illuminate\\Support\\Facades\\Event;\n\nclass EventServiceProvider extends ServiceProvider\n{\n    /**\n     * The event to listener mappings for the application.\n     *\n     * @var array<class-string, array<int, class-string>>\n     */\n    protected $listen = [\n        Registered::class => [\n            SendEmailVerificationNotification::class,\n        ],\n    ];\n\n    /**\n     * Register any events for your application.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        //\n    }\n\n    /**\n     * Determine if events and listeners should be automatically discovered.\n     *\n     * @return bool\n     */\n    public function shouldDiscoverEvents()\n    {\n        return false;\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/app/Providers/RouteServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Cache\\RateLimiting\\Limit;\nuse Illuminate\\Foundation\\Support\\Providers\\RouteServiceProvider as ServiceProvider;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\RateLimiter;\nuse Illuminate\\Support\\Facades\\Route;\n\nclass RouteServiceProvider extends ServiceProvider\n{\n    /**\n     * The path to the \"home\" route for your application.\n     *\n     * Typically, users are redirected here after authentication.\n     *\n     * @var string\n     */\n    public const HOME = '/home';\n\n    /**\n     * Define your route model bindings, pattern filters, and other route configuration.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        $this->configureRateLimiting();\n\n        $this->routes(function () {\n            Route::middleware('api')\n                ->prefix('api')\n                ->group(base_path('routes/api.php'));\n\n            Route::middleware('web')\n                ->group(base_path('routes/web.php'));\n        });\n    }\n\n    /**\n     * Configure the rate limiters for the application.\n     *\n     * @return void\n     */\n    protected function configureRateLimiting()\n    {\n        RateLimiter::for('api', function (Request $request) {\n            return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());\n        });\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/artisan",
    "content": "#!/usr/bin/env php\n<?php\n\ndefine('LARAVEL_START', microtime(true));\n\n/*\n|--------------------------------------------------------------------------\n| Register The Auto Loader\n|--------------------------------------------------------------------------\n|\n| Composer provides a convenient, automatically generated class loader\n| for our application. We just need to utilize it! We'll require it\n| into the script here so that we do not have to worry about the\n| loading of any of our classes manually. It's great to relax.\n|\n*/\n\nrequire __DIR__.'/vendor/autoload.php';\n\n$app = require_once __DIR__.'/bootstrap/app.php';\n\n/*\n|--------------------------------------------------------------------------\n| Run The Artisan Application\n|--------------------------------------------------------------------------\n|\n| When we run the console application, the current CLI command will be\n| executed in this console and the response sent back to a terminal\n| or another output device for the developers. Here goes nothing!\n|\n*/\n\n$kernel = $app->make(Illuminate\\Contracts\\Console\\Kernel::class);\n\n$status = $kernel->handle(\n    $input = new Symfony\\Component\\Console\\Input\\ArgvInput,\n    new Symfony\\Component\\Console\\Output\\ConsoleOutput\n);\n\n/*\n|--------------------------------------------------------------------------\n| Shutdown The Application\n|--------------------------------------------------------------------------\n|\n| Once Artisan has finished running, we will fire off the shutdown events\n| so that any final work may be done by the application before we shut\n| down the process. This is the last thing to happen to the request.\n|\n*/\n\n$kernel->terminate($input, $status);\n\nexit($status);\n"
  },
  {
    "path": "playgrounds/react/bootstrap/app.php",
    "content": "<?php\n\n/*\n|--------------------------------------------------------------------------\n| Create The Application\n|--------------------------------------------------------------------------\n|\n| The first thing we will do is create a new Laravel application instance\n| which serves as the \"glue\" for all the components of Laravel, and is\n| the IoC container for the system binding all of the various parts.\n|\n*/\n\n$app = new Illuminate\\Foundation\\Application(\n    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)\n);\n\n/*\n|--------------------------------------------------------------------------\n| Bind Important Interfaces\n|--------------------------------------------------------------------------\n|\n| Next, we need to bind some important interfaces into the container so\n| we will be able to resolve them when needed. The kernels serve the\n| incoming requests to this application from both the web and CLI.\n|\n*/\n\n$app->singleton(\n    Illuminate\\Contracts\\Http\\Kernel::class,\n    App\\Http\\Kernel::class\n);\n\n$app->singleton(\n    Illuminate\\Contracts\\Console\\Kernel::class,\n    App\\Console\\Kernel::class\n);\n\n$app->singleton(\n    Illuminate\\Contracts\\Debug\\ExceptionHandler::class,\n    App\\Exceptions\\Handler::class\n);\n\n/*\n|--------------------------------------------------------------------------\n| Return The Application\n|--------------------------------------------------------------------------\n|\n| This script returns the application instance. The instance is given to\n| the calling script so we can separate the building of the instances\n| from the actual running of the application and sending responses.\n|\n*/\n\nreturn $app;\n"
  },
  {
    "path": "playgrounds/react/bootstrap/cache/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/react/composer.json",
    "content": "{\n    \"name\": \"laravel/laravel\",\n    \"type\": \"project\",\n    \"description\": \"The Laravel Framework.\",\n    \"keywords\": [\n        \"framework\",\n        \"laravel\"\n    ],\n    \"license\": \"MIT\",\n    \"require\": {\n        \"php\": \"^8.2\",\n        \"guzzlehttp/guzzle\": \"^7.2\",\n        \"inertiajs/inertia-laravel\": \"^2.0.16\",\n        \"laravel/framework\": \"^11.0\",\n        \"laravel/sanctum\": \"^4.0\",\n        \"laravel/tinker\": \"^2.7\",\n        \"prism-php/prism\": \"^0.89.0\"\n    },\n    \"require-dev\": {\n        \"fakerphp/faker\": \"^1.9.1\",\n        \"laravel/pint\": \"^1.0\",\n        \"laravel/sail\": \"^1.0.1\",\n        \"mockery/mockery\": \"^1.4.4\",\n        \"nunomaduro/collision\": \"^8.1\",\n        \"phpunit/phpunit\": \"^10.0\",\n        \"spatie/laravel-ignition\": \"^2.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"App\\\\\": \"app/\",\n            \"Database\\\\Factories\\\\\": \"database/factories/\",\n            \"Database\\\\Seeders\\\\\": \"database/seeders/\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Tests\\\\\": \"tests/\"\n        }\n    },\n    \"scripts\": {\n        \"post-autoload-dump\": [\n            \"Illuminate\\\\Foundation\\\\ComposerScripts::postAutoloadDump\",\n            \"@php artisan package:discover --ansi\"\n        ],\n        \"post-update-cmd\": [\n            \"@php artisan vendor:publish --tag=laravel-assets --ansi --force\"\n        ],\n        \"post-root-package-install\": [\n            \"@php -r \\\"file_exists('.env') || copy('.env.example', '.env');\\\"\"\n        ],\n        \"post-create-project-cmd\": [\n            \"@php artisan key:generate --ansi\"\n        ],\n        \"dev\": [\n            \"Composer\\\\Config::disableProcessTimeout\",\n            \"pnpx concurrently -c \\\"#93c5fd,#c4b5fd\\\" \\\"php artisan serve\\\" \\\"pnpm run dev\\\" --names=server,vite\"\n        ]\n    },\n    \"extra\": {\n        \"laravel\": {\n            \"dont-discover\": []\n        }\n    },\n    \"config\": {\n        \"optimize-autoloader\": true,\n        \"preferred-install\": \"dist\",\n        \"sort-packages\": true,\n        \"allow-plugins\": {\n            \"pestphp/pest-plugin\": true\n        }\n    },\n    \"minimum-stability\": \"dev\",\n    \"prefer-stable\": true\n}\n"
  },
  {
    "path": "playgrounds/react/config/app.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Facades\\Facade;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Name\n    |--------------------------------------------------------------------------\n    |\n    | This value is the name of your application. This value is used when the\n    | framework needs to place the application's name in a notification or\n    | any other location as required by the application or its packages.\n    |\n    */\n\n    'name' => env('APP_NAME', 'Laravel'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Environment\n    |--------------------------------------------------------------------------\n    |\n    | This value determines the \"environment\" your application is currently\n    | running in. This may determine how you prefer to configure various\n    | services the application utilizes. Set this in your \".env\" file.\n    |\n    */\n\n    'env' => env('APP_ENV', 'production'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Debug Mode\n    |--------------------------------------------------------------------------\n    |\n    | When your application is in debug mode, detailed error messages with\n    | stack traces will be shown on every error that occurs within your\n    | application. If disabled, a simple generic error page is shown.\n    |\n    */\n\n    'debug' => (bool) env('APP_DEBUG', false),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application URL\n    |--------------------------------------------------------------------------\n    |\n    | This URL is used by the console to properly generate URLs when using\n    | the Artisan command line tool. You should set this to the root of\n    | your application so that it is used when running Artisan tasks.\n    |\n    */\n\n    'url' => env('APP_URL', 'http://localhost'),\n\n    'asset_url' => env('ASSET_URL'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Timezone\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the default timezone for your application, which\n    | will be used by the PHP date and date-time functions. We have gone\n    | ahead and set this to a sensible default for you out of the box.\n    |\n    */\n\n    'timezone' => 'UTC',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Locale Configuration\n    |--------------------------------------------------------------------------\n    |\n    | The application locale determines the default locale that will be used\n    | by the translation service provider. You are free to set this value\n    | to any of the locales which will be supported by the application.\n    |\n    */\n\n    'locale' => 'en',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Fallback Locale\n    |--------------------------------------------------------------------------\n    |\n    | The fallback locale determines the locale to use when the current one\n    | is not available. You may change the value to correspond to any of\n    | the language folders that are provided through your application.\n    |\n    */\n\n    'fallback_locale' => 'en',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Faker Locale\n    |--------------------------------------------------------------------------\n    |\n    | This locale will be used by the Faker PHP library when generating fake\n    | data for your database seeds. For example, this will be used to get\n    | localized telephone numbers, street address information and more.\n    |\n    */\n\n    'faker_locale' => 'en_US',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Encryption Key\n    |--------------------------------------------------------------------------\n    |\n    | This key is used by the Illuminate encrypter service and should be set\n    | to a random, 32 character string, otherwise these encrypted strings\n    | will not be safe. Please do this before deploying an application!\n    |\n    */\n\n    'key' => env('APP_KEY'),\n\n    'cipher' => 'AES-256-CBC',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Maintenance Mode Driver\n    |--------------------------------------------------------------------------\n    |\n    | These configuration options determine the driver used to determine and\n    | manage Laravel's \"maintenance mode\" status. The \"cache\" driver will\n    | allow maintenance mode to be controlled across multiple machines.\n    |\n    | Supported drivers: \"file\", \"cache\"\n    |\n    */\n\n    'maintenance' => [\n        'driver' => 'file',\n        // 'store'  => 'redis',\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Autoloaded Service Providers\n    |--------------------------------------------------------------------------\n    |\n    | The service providers listed here will be automatically loaded on the\n    | request to your application. Feel free to add your own services to\n    | this array to grant expanded functionality to your applications.\n    |\n    */\n\n    'providers' => [\n\n        /*\n         * Laravel Framework Service Providers...\n         */\n        Illuminate\\Auth\\AuthServiceProvider::class,\n        Illuminate\\Broadcasting\\BroadcastServiceProvider::class,\n        Illuminate\\Bus\\BusServiceProvider::class,\n        Illuminate\\Cache\\CacheServiceProvider::class,\n        Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider::class,\n        Illuminate\\Cookie\\CookieServiceProvider::class,\n        Illuminate\\Database\\DatabaseServiceProvider::class,\n        Illuminate\\Encryption\\EncryptionServiceProvider::class,\n        Illuminate\\Filesystem\\FilesystemServiceProvider::class,\n        Illuminate\\Foundation\\Providers\\FoundationServiceProvider::class,\n        Illuminate\\Hashing\\HashServiceProvider::class,\n        Illuminate\\Mail\\MailServiceProvider::class,\n        Illuminate\\Notifications\\NotificationServiceProvider::class,\n        Illuminate\\Pagination\\PaginationServiceProvider::class,\n        Illuminate\\Pipeline\\PipelineServiceProvider::class,\n        Illuminate\\Queue\\QueueServiceProvider::class,\n        Illuminate\\Redis\\RedisServiceProvider::class,\n        Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider::class,\n        Illuminate\\Session\\SessionServiceProvider::class,\n        Illuminate\\Translation\\TranslationServiceProvider::class,\n        Illuminate\\Validation\\ValidationServiceProvider::class,\n        Illuminate\\View\\ViewServiceProvider::class,\n\n        /*\n         * Package Service Providers...\n         */\n\n        /*\n         * Application Service Providers...\n         */\n        App\\Providers\\AppServiceProvider::class,\n        App\\Providers\\AuthServiceProvider::class,\n        // App\\Providers\\BroadcastServiceProvider::class,\n        App\\Providers\\EventServiceProvider::class,\n        App\\Providers\\RouteServiceProvider::class,\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Class Aliases\n    |--------------------------------------------------------------------------\n    |\n    | This array of class aliases will be registered when this application\n    | is started. However, feel free to register as many as you wish as\n    | the aliases are \"lazy\" loaded so they don't hinder performance.\n    |\n    */\n\n    'aliases' => Facade::defaultAliases()->merge([\n        // 'ExampleClass' => App\\Example\\ExampleClass::class,\n    ])->toArray(),\n\n];\n"
  },
  {
    "path": "playgrounds/react/config/auth.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Authentication Defaults\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default authentication \"guard\" and password\n    | reset options for your application. You may change these defaults\n    | as required, but they're a perfect start for most applications.\n    |\n    */\n\n    'defaults' => [\n        'guard' => 'web',\n        'passwords' => 'users',\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Authentication Guards\n    |--------------------------------------------------------------------------\n    |\n    | Next, you may define every authentication guard for your application.\n    | Of course, a great default configuration has been defined for you\n    | here which uses session storage and the Eloquent user provider.\n    |\n    | All authentication drivers have a user provider. This defines how the\n    | users are actually retrieved out of your database or other storage\n    | mechanisms used by this application to persist your user's data.\n    |\n    | Supported: \"session\"\n    |\n    */\n\n    'guards' => [\n        'web' => [\n            'driver' => 'session',\n            'provider' => 'users',\n        ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | User Providers\n    |--------------------------------------------------------------------------\n    |\n    | All authentication drivers have a user provider. This defines how the\n    | users are actually retrieved out of your database or other storage\n    | mechanisms used by this application to persist your user's data.\n    |\n    | If you have multiple user tables or models you may configure multiple\n    | sources which represent each model / table. These sources may then\n    | be assigned to any extra authentication guards you have defined.\n    |\n    | Supported: \"database\", \"eloquent\"\n    |\n    */\n\n    'providers' => [\n        'users' => [\n            'driver' => 'eloquent',\n            'model' => App\\Models\\User::class,\n        ],\n\n        // 'users' => [\n        //     'driver' => 'database',\n        //     'table' => 'users',\n        // ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Resetting Passwords\n    |--------------------------------------------------------------------------\n    |\n    | You may specify multiple password reset configurations if you have more\n    | than one user table or model in the application and you want to have\n    | separate password reset settings based on the specific user types.\n    |\n    | The expire time is the number of minutes that each reset token will be\n    | considered valid. This security feature keeps tokens short-lived so\n    | they have less time to be guessed. You may change this as needed.\n    |\n    */\n\n    'passwords' => [\n        'users' => [\n            'provider' => 'users',\n            'table' => 'password_resets',\n            'expire' => 60,\n            'throttle' => 60,\n        ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Password Confirmation Timeout\n    |--------------------------------------------------------------------------\n    |\n    | Here you may define the amount of seconds before a password confirmation\n    | times out and the user is prompted to re-enter their password via the\n    | confirmation screen. By default, the timeout lasts for three hours.\n    |\n    */\n\n    'password_timeout' => 10800,\n\n];\n"
  },
  {
    "path": "playgrounds/react/config/broadcasting.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Broadcaster\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default broadcaster that will be used by the\n    | framework when an event needs to be broadcast. You may set this to\n    | any of the connections defined in the \"connections\" array below.\n    |\n    | Supported: \"pusher\", \"ably\", \"redis\", \"log\", \"null\"\n    |\n    */\n\n    'default' => env('BROADCAST_DRIVER', 'null'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Broadcast Connections\n    |--------------------------------------------------------------------------\n    |\n    | Here you may define all of the broadcast connections that will be used\n    | to broadcast events to other systems or over websockets. Samples of\n    | each available type of connection are provided inside this array.\n    |\n    */\n\n    'connections' => [\n\n        'pusher' => [\n            'driver' => 'pusher',\n            'key' => env('PUSHER_APP_KEY'),\n            'secret' => env('PUSHER_APP_SECRET'),\n            'app_id' => env('PUSHER_APP_ID'),\n            'options' => [\n                'host' => env('PUSHER_HOST') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com',\n                'port' => env('PUSHER_PORT', 443),\n                'scheme' => env('PUSHER_SCHEME', 'https'),\n                'encrypted' => true,\n                'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',\n            ],\n            'client_options' => [\n                // Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html\n            ],\n        ],\n\n        'ably' => [\n            'driver' => 'ably',\n            'key' => env('ABLY_KEY'),\n        ],\n\n        'redis' => [\n            'driver' => 'redis',\n            'connection' => 'default',\n        ],\n\n        'log' => [\n            'driver' => 'log',\n        ],\n\n        'null' => [\n            'driver' => 'null',\n        ],\n\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/react/config/cache.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Str;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Cache Store\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default cache connection that gets used while\n    | using this caching library. This connection is used when another is\n    | not explicitly specified when executing a given caching function.\n    |\n    */\n\n    'default' => env('CACHE_DRIVER', 'file'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cache Stores\n    |--------------------------------------------------------------------------\n    |\n    | Here you may define all of the cache \"stores\" for your application as\n    | well as their drivers. You may even define multiple stores for the\n    | same cache driver to group types of items stored in your caches.\n    |\n    | Supported drivers: \"apc\", \"array\", \"database\", \"file\",\n    |         \"memcached\", \"redis\", \"dynamodb\", \"octane\", \"null\"\n    |\n    */\n\n    'stores' => [\n\n        'apc' => [\n            'driver' => 'apc',\n        ],\n\n        'array' => [\n            'driver' => 'array',\n            'serialize' => false,\n        ],\n\n        'database' => [\n            'driver' => 'database',\n            'table' => 'cache',\n            'connection' => null,\n            'lock_connection' => null,\n        ],\n\n        'file' => [\n            'driver' => 'file',\n            'path' => storage_path('framework/cache/data'),\n        ],\n\n        'memcached' => [\n            'driver' => 'memcached',\n            'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),\n            'sasl' => [\n                env('MEMCACHED_USERNAME'),\n                env('MEMCACHED_PASSWORD'),\n            ],\n            'options' => [\n                // Memcached::OPT_CONNECT_TIMEOUT => 2000,\n            ],\n            'servers' => [\n                [\n                    'host' => env('MEMCACHED_HOST', '127.0.0.1'),\n                    'port' => env('MEMCACHED_PORT', 11211),\n                    'weight' => 100,\n                ],\n            ],\n        ],\n\n        'redis' => [\n            'driver' => 'redis',\n            'connection' => 'cache',\n            'lock_connection' => 'default',\n        ],\n\n        'dynamodb' => [\n            'driver' => 'dynamodb',\n            'key' => env('AWS_ACCESS_KEY_ID'),\n            'secret' => env('AWS_SECRET_ACCESS_KEY'),\n            'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),\n            'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),\n            'endpoint' => env('DYNAMODB_ENDPOINT'),\n        ],\n\n        'octane' => [\n            'driver' => 'octane',\n        ],\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cache Key Prefix\n    |--------------------------------------------------------------------------\n    |\n    | When utilizing the APC, database, memcached, Redis, or DynamoDB cache\n    | stores there might be other applications using the same cache. For\n    | that reason, you may prefix every cache key to avoid collisions.\n    |\n    */\n\n    'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'),\n\n];\n"
  },
  {
    "path": "playgrounds/react/config/cors.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cross-Origin Resource Sharing (CORS) Configuration\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure your settings for cross-origin resource sharing\n    | or \"CORS\". This determines what cross-origin operations may execute\n    | in web browsers. You are free to adjust these settings as needed.\n    |\n    | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS\n    |\n    */\n\n    'paths' => ['api/*', 'sanctum/csrf-cookie'],\n\n    'allowed_methods' => ['*'],\n\n    'allowed_origins' => ['*'],\n\n    'allowed_origins_patterns' => [],\n\n    'allowed_headers' => ['*'],\n\n    'exposed_headers' => [],\n\n    'max_age' => 0,\n\n    'supports_credentials' => false,\n\n];\n"
  },
  {
    "path": "playgrounds/react/config/database.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Str;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Database Connection Name\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify which of the database connections below you wish\n    | to use as your default connection for all database work. Of course\n    | you may use many connections at once using the Database library.\n    |\n    */\n\n    'default' => env('DB_CONNECTION', 'mysql'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Database Connections\n    |--------------------------------------------------------------------------\n    |\n    | Here are each of the database connections setup for your application.\n    | Of course, examples of configuring each database platform that is\n    | supported by Laravel is shown below to make development simple.\n    |\n    |\n    | All database work in Laravel is done through the PHP PDO facilities\n    | so make sure you have the driver for your particular database of\n    | choice installed on your machine before you begin development.\n    |\n    */\n\n    'connections' => [\n\n        'sqlite' => [\n            'driver' => 'sqlite',\n            'url' => env('DATABASE_URL'),\n            'database' => env('DB_DATABASE', database_path('database.sqlite')),\n            'prefix' => '',\n            'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),\n        ],\n\n        'mysql' => [\n            'driver' => 'mysql',\n            'url' => env('DATABASE_URL'),\n            'host' => env('DB_HOST', '127.0.0.1'),\n            'port' => env('DB_PORT', '3306'),\n            'database' => env('DB_DATABASE', 'forge'),\n            'username' => env('DB_USERNAME', 'forge'),\n            'password' => env('DB_PASSWORD', ''),\n            'unix_socket' => env('DB_SOCKET', ''),\n            'charset' => 'utf8mb4',\n            'collation' => 'utf8mb4_unicode_ci',\n            'prefix' => '',\n            'prefix_indexes' => true,\n            'strict' => true,\n            'engine' => null,\n            'options' => extension_loaded('pdo_mysql') ? array_filter([\n                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),\n            ]) : [],\n        ],\n\n        'pgsql' => [\n            'driver' => 'pgsql',\n            'url' => env('DATABASE_URL'),\n            'host' => env('DB_HOST', '127.0.0.1'),\n            'port' => env('DB_PORT', '5432'),\n            'database' => env('DB_DATABASE', 'forge'),\n            'username' => env('DB_USERNAME', 'forge'),\n            'password' => env('DB_PASSWORD', ''),\n            'charset' => 'utf8',\n            'prefix' => '',\n            'prefix_indexes' => true,\n            'search_path' => 'public',\n            'sslmode' => 'prefer',\n        ],\n\n        'sqlsrv' => [\n            'driver' => 'sqlsrv',\n            'url' => env('DATABASE_URL'),\n            'host' => env('DB_HOST', 'localhost'),\n            'port' => env('DB_PORT', '1433'),\n            'database' => env('DB_DATABASE', 'forge'),\n            'username' => env('DB_USERNAME', 'forge'),\n            'password' => env('DB_PASSWORD', ''),\n            'charset' => 'utf8',\n            'prefix' => '',\n            'prefix_indexes' => true,\n            // 'encrypt' => env('DB_ENCRYPT', 'yes'),\n            // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),\n        ],\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Migration Repository Table\n    |--------------------------------------------------------------------------\n    |\n    | This table keeps track of all the migrations that have already run for\n    | your application. Using this information, we can determine which of\n    | the migrations on disk haven't actually been run in the database.\n    |\n    */\n\n    'migrations' => 'migrations',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Redis Databases\n    |--------------------------------------------------------------------------\n    |\n    | Redis is an open source, fast, and advanced key-value store that also\n    | provides a richer body of commands than a typical key-value system\n    | such as APC or Memcached. Laravel makes it easy to dig right in.\n    |\n    */\n\n    'redis' => [\n\n        'client' => env('REDIS_CLIENT', 'phpredis'),\n\n        'options' => [\n            'cluster' => env('REDIS_CLUSTER', 'redis'),\n            'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),\n        ],\n\n        'default' => [\n            'url' => env('REDIS_URL'),\n            'host' => env('REDIS_HOST', '127.0.0.1'),\n            'username' => env('REDIS_USERNAME'),\n            'password' => env('REDIS_PASSWORD'),\n            'port' => env('REDIS_PORT', '6379'),\n            'database' => env('REDIS_DB', '0'),\n        ],\n\n        'cache' => [\n            'url' => env('REDIS_URL'),\n            'host' => env('REDIS_HOST', '127.0.0.1'),\n            'username' => env('REDIS_USERNAME'),\n            'password' => env('REDIS_PASSWORD'),\n            'port' => env('REDIS_PORT', '6379'),\n            'database' => env('REDIS_CACHE_DB', '1'),\n        ],\n\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/react/config/filesystems.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Filesystem Disk\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the default filesystem disk that should be used\n    | by the framework. The \"local\" disk, as well as a variety of cloud\n    | based disks are available to your application. Just store away!\n    |\n    */\n\n    'default' => env('FILESYSTEM_DISK', 'local'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Filesystem Disks\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure as many filesystem \"disks\" as you wish, and you\n    | may even configure multiple disks of the same driver. Defaults have\n    | been set up for each driver as an example of the required values.\n    |\n    | Supported Drivers: \"local\", \"ftp\", \"sftp\", \"s3\"\n    |\n    */\n\n    'disks' => [\n\n        'local' => [\n            'driver' => 'local',\n            'root' => storage_path('app'),\n            'throw' => false,\n        ],\n\n        'public' => [\n            'driver' => 'local',\n            'root' => storage_path('app/public'),\n            'url' => env('APP_URL').'/storage',\n            'visibility' => 'public',\n            'throw' => false,\n        ],\n\n        's3' => [\n            'driver' => 's3',\n            'key' => env('AWS_ACCESS_KEY_ID'),\n            'secret' => env('AWS_SECRET_ACCESS_KEY'),\n            'region' => env('AWS_DEFAULT_REGION'),\n            'bucket' => env('AWS_BUCKET'),\n            'url' => env('AWS_URL'),\n            'endpoint' => env('AWS_ENDPOINT'),\n            'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),\n            'throw' => false,\n        ],\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Symbolic Links\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure the symbolic links that will be created when the\n    | `storage:link` Artisan command is executed. The array keys should be\n    | the locations of the links and the values should be their targets.\n    |\n    */\n\n    'links' => [\n        public_path('storage') => storage_path('app/public'),\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/react/config/hashing.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Hash Driver\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default hash driver that will be used to hash\n    | passwords for your application. By default, the bcrypt algorithm is\n    | used; however, you remain free to modify this option if you wish.\n    |\n    | Supported: \"bcrypt\", \"argon\", \"argon2id\"\n    |\n    */\n\n    'driver' => 'bcrypt',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Bcrypt Options\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the configuration options that should be used when\n    | passwords are hashed using the Bcrypt algorithm. This will allow you\n    | to control the amount of time it takes to hash the given password.\n    |\n    */\n\n    'bcrypt' => [\n        'rounds' => env('BCRYPT_ROUNDS', 10),\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Argon Options\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the configuration options that should be used when\n    | passwords are hashed using the Argon algorithm. These will allow you\n    | to control the amount of time it takes to hash the given password.\n    |\n    */\n\n    'argon' => [\n        'memory' => 65536,\n        'threads' => 1,\n        'time' => 4,\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/react/config/inertia.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Server Side Rendering\n    |--------------------------------------------------------------------------\n    |\n    | These options configures if and how Inertia uses Server Side Rendering\n    | to pre-render the initial visits made to your application's pages.\n    |\n    | You can specify a custom SSR bundle path, or omit it to let Inertia\n    | try and automatically detect it for you.\n    |\n    | Do note that enabling these options will NOT automatically make SSR work,\n    | as a separate rendering service needs to be available. To learn more,\n    | please visit https://inertiajs.com/server-side-rendering\n    |\n    */\n\n    'ssr' => [\n\n        'enabled' => (bool) env('INERTIA_SSR_ENABLED', true),\n\n        'url' => env('INERTIA_SSR_URL', 'http://127.0.0.1:13714'),\n\n        'ensure_bundle_exists' => (bool) env('INERTIA_SSR_ENSURE_BUNDLE_EXISTS', true),\n\n        // 'bundle' => base_path('bootstrap/ssr/ssr.mjs'),\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Pages\n    |--------------------------------------------------------------------------\n    |\n    | Set `ensure_pages_exist` to true if you want to enforce that Inertia page\n    | components exist on disk when rendering a page. This is useful for\n    | catching missing or misnamed components.\n    |\n    | The `page_paths` and `page_extensions` options define where to look\n    | for page components and which file extensions to consider.\n    |\n    */\n\n    'ensure_pages_exist' => false,\n\n    'page_paths' => [\n\n        resource_path('js/Pages'),\n\n    ],\n\n    'page_extensions' => [\n\n        'js',\n        'jsx',\n        'svelte',\n        'ts',\n        'tsx',\n        'vue',\n\n    ],\n\n    'use_script_element_for_initial_page' => (bool) env('INERTIA_USE_SCRIPT_ELEMENT_FOR_INITIAL_PAGE', false),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Testing\n    |--------------------------------------------------------------------------\n    |\n    | The values described here are used to locate Inertia components on the\n    | filesystem. For instance, when using `assertInertia`, the assertion\n    | attempts to locate the component as a file relative to any of the\n    | paths AND with any of the extensions specified here.\n    |\n    | Note: In a future release, the `page_paths` and `page_extensions`\n    | options below will be removed. The root-level options above\n    | will be used for both application and testing purposes.\n    |\n    */\n\n    'testing' => [\n\n        'ensure_pages_exist' => true,\n\n        'page_paths' => [\n\n            resource_path('js/Pages'),\n\n        ],\n\n        'page_extensions' => [\n\n            'js',\n            'jsx',\n            'svelte',\n            'ts',\n            'tsx',\n            'vue',\n\n        ],\n\n    ],\n\n    'history' => [\n\n        'encrypt' => (bool) env('INERTIA_ENCRYPT_HISTORY', true),\n\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/react/config/logging.php",
    "content": "<?php\n\nuse Monolog\\Handler\\NullHandler;\nuse Monolog\\Handler\\StreamHandler;\nuse Monolog\\Handler\\SyslogUdpHandler;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Log Channel\n    |--------------------------------------------------------------------------\n    |\n    | This option defines the default log channel that gets used when writing\n    | messages to the logs. The name specified in this option should match\n    | one of the channels defined in the \"channels\" configuration array.\n    |\n    */\n\n    'default' => env('LOG_CHANNEL', 'stack'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Deprecations Log Channel\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the log channel that should be used to log warnings\n    | regarding deprecated PHP and library features. This allows you to get\n    | your application ready for upcoming major versions of dependencies.\n    |\n    */\n\n    'deprecations' => [\n        'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),\n        'trace' => false,\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Log Channels\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure the log channels for your application. Out of\n    | the box, Laravel uses the Monolog PHP logging library. This gives\n    | you a variety of powerful log handlers / formatters to utilize.\n    |\n    | Available Drivers: \"single\", \"daily\", \"slack\", \"syslog\",\n    |                    \"errorlog\", \"monolog\",\n    |                    \"custom\", \"stack\"\n    |\n    */\n\n    'channels' => [\n        'stack' => [\n            'driver' => 'stack',\n            'channels' => ['single'],\n            'ignore_exceptions' => false,\n        ],\n\n        'single' => [\n            'driver' => 'single',\n            'path' => storage_path('logs/laravel.log'),\n            'level' => env('LOG_LEVEL', 'debug'),\n        ],\n\n        'daily' => [\n            'driver' => 'daily',\n            'path' => storage_path('logs/laravel.log'),\n            'level' => env('LOG_LEVEL', 'debug'),\n            'days' => 14,\n        ],\n\n        'slack' => [\n            'driver' => 'slack',\n            'url' => env('LOG_SLACK_WEBHOOK_URL'),\n            'username' => 'Laravel Log',\n            'emoji' => ':boom:',\n            'level' => env('LOG_LEVEL', 'critical'),\n        ],\n\n        'papertrail' => [\n            'driver' => 'monolog',\n            'level' => env('LOG_LEVEL', 'debug'),\n            'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class),\n            'handler_with' => [\n                'host' => env('PAPERTRAIL_URL'),\n                'port' => env('PAPERTRAIL_PORT'),\n                'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),\n            ],\n        ],\n\n        'stderr' => [\n            'driver' => 'monolog',\n            'level' => env('LOG_LEVEL', 'debug'),\n            'handler' => StreamHandler::class,\n            'formatter' => env('LOG_STDERR_FORMATTER'),\n            'with' => [\n                'stream' => 'php://stderr',\n            ],\n        ],\n\n        'syslog' => [\n            'driver' => 'syslog',\n            'level' => env('LOG_LEVEL', 'debug'),\n        ],\n\n        'errorlog' => [\n            'driver' => 'errorlog',\n            'level' => env('LOG_LEVEL', 'debug'),\n        ],\n\n        'null' => [\n            'driver' => 'monolog',\n            'handler' => NullHandler::class,\n        ],\n\n        'emergency' => [\n            'path' => storage_path('logs/laravel.log'),\n        ],\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/react/config/mail.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Mailer\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default mailer that is used to send any email\n    | messages sent by your application. Alternative mailers may be setup\n    | and used as needed; however, this mailer will be used by default.\n    |\n    */\n\n    'default' => env('MAIL_MAILER', 'smtp'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Mailer Configurations\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure all of the mailers used by your application plus\n    | their respective settings. Several examples have been configured for\n    | you and you are free to add your own as your application requires.\n    |\n    | Laravel supports a variety of mail \"transport\" drivers to be used while\n    | sending an e-mail. You will specify which one you are using for your\n    | mailers below. You are free to add additional mailers as required.\n    |\n    | Supported: \"smtp\", \"sendmail\", \"mailgun\", \"ses\",\n    |            \"postmark\", \"log\", \"array\", \"failover\"\n    |\n    */\n\n    'mailers' => [\n        'smtp' => [\n            'transport' => 'smtp',\n            'host' => env('MAIL_HOST', 'smtp.mailgun.org'),\n            'port' => env('MAIL_PORT', 587),\n            'encryption' => env('MAIL_ENCRYPTION', 'tls'),\n            'username' => env('MAIL_USERNAME'),\n            'password' => env('MAIL_PASSWORD'),\n            'timeout' => null,\n            'local_domain' => env('MAIL_EHLO_DOMAIN'),\n        ],\n\n        'ses' => [\n            'transport' => 'ses',\n        ],\n\n        'mailgun' => [\n            'transport' => 'mailgun',\n        ],\n\n        'postmark' => [\n            'transport' => 'postmark',\n        ],\n\n        'sendmail' => [\n            'transport' => 'sendmail',\n            'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'),\n        ],\n\n        'log' => [\n            'transport' => 'log',\n            'channel' => env('MAIL_LOG_CHANNEL'),\n        ],\n\n        'array' => [\n            'transport' => 'array',\n        ],\n\n        'failover' => [\n            'transport' => 'failover',\n            'mailers' => [\n                'smtp',\n                'log',\n            ],\n        ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Global \"From\" Address\n    |--------------------------------------------------------------------------\n    |\n    | You may wish for all e-mails sent by your application to be sent from\n    | the same address. Here, you may specify a name and address that is\n    | used globally for all e-mails that are sent by your application.\n    |\n    */\n\n    'from' => [\n        'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),\n        'name' => env('MAIL_FROM_NAME', 'Example'),\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Markdown Mail Settings\n    |--------------------------------------------------------------------------\n    |\n    | If you are using Markdown based email rendering, you may configure your\n    | theme and component paths here, allowing you to customize the design\n    | of the emails. Or, you may simply stick with the Laravel defaults!\n    |\n    */\n\n    'markdown' => [\n        'theme' => 'default',\n\n        'paths' => [\n            resource_path('views/vendor/mail'),\n        ],\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/react/config/prism.php",
    "content": "<?php\n\nreturn [\n    'prism_server' => [\n        // The middleware that will be applied to the Prism Server routes.\n        'middleware' => [],\n        'enabled' => env('PRISM_SERVER_ENABLED', false),\n    ],\n    'providers' => [\n        'openai' => [\n            'url' => env('OPENAI_URL', 'https://api.openai.com/v1'),\n            'api_key' => env('OPENAI_API_KEY', ''),\n            'organization' => env('OPENAI_ORGANIZATION', null),\n            'project' => env('OPENAI_PROJECT', null),\n        ],\n        'anthropic' => [\n            'api_key' => env('ANTHROPIC_API_KEY', ''),\n            'version' => env('ANTHROPIC_API_VERSION', '2023-06-01'),\n            'default_thinking_budget' => env('ANTHROPIC_DEFAULT_THINKING_BUDGET', 1024),\n            // Include beta strings as a comma separated list.\n            'anthropic_beta' => env('ANTHROPIC_BETA', null),\n        ],\n        'ollama' => [\n            'url' => env('OLLAMA_URL', 'http://localhost:11434'),\n        ],\n        'mistral' => [\n            'api_key' => env('MISTRAL_API_KEY', ''),\n            'url' => env('MISTRAL_URL', 'https://api.mistral.ai/v1'),\n        ],\n        'groq' => [\n            'api_key' => env('GROQ_API_KEY', ''),\n            'url' => env('GROQ_URL', 'https://api.groq.com/openai/v1'),\n        ],\n        'xai' => [\n            'api_key' => env('XAI_API_KEY', ''),\n            'url' => env('XAI_URL', 'https://api.x.ai/v1'),\n        ],\n        'gemini' => [\n            'api_key' => env('GEMINI_API_KEY', ''),\n            'url' => env('GEMINI_URL', 'https://generativelanguage.googleapis.com/v1beta/models'),\n        ],\n        'deepseek' => [\n            'api_key' => env('DEEPSEEK_API_KEY', ''),\n            'url' => env('DEEPSEEK_URL', 'https://api.deepseek.com/v1'),\n        ],\n        'elevenlabs' => [\n            'api_key' => env('ELEVENLABS_API_KEY', ''),\n            'url' => env('ELEVENLABS_URL', 'https://api.elevenlabs.io/v1/'),\n        ],\n        'voyageai' => [\n            'api_key' => env('VOYAGEAI_API_KEY', ''),\n            'url' => env('VOYAGEAI_URL', 'https://api.voyageai.com/v1'),\n        ],\n        'openrouter' => [\n            'api_key' => env('OPENROUTER_API_KEY', ''),\n            'url' => env('OPENROUTER_URL', 'https://openrouter.ai/api/v1'),\n        ],\n    ],\n];\n"
  },
  {
    "path": "playgrounds/react/config/queue.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Queue Connection Name\n    |--------------------------------------------------------------------------\n    |\n    | Laravel's queue API supports an assortment of back-ends via a single\n    | API, giving you convenient access to each back-end using the same\n    | syntax for every one. Here you may define a default connection.\n    |\n    */\n\n    'default' => env('QUEUE_CONNECTION', 'sync'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Queue Connections\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure the connection information for each server that\n    | is used by your application. A default configuration has been added\n    | for each back-end shipped with Laravel. You are free to add more.\n    |\n    | Drivers: \"sync\", \"database\", \"beanstalkd\", \"sqs\", \"redis\", \"null\"\n    |\n    */\n\n    'connections' => [\n\n        'sync' => [\n            'driver' => 'sync',\n        ],\n\n        'database' => [\n            'driver' => 'database',\n            'table' => 'jobs',\n            'queue' => 'default',\n            'retry_after' => 90,\n            'after_commit' => false,\n        ],\n\n        'beanstalkd' => [\n            'driver' => 'beanstalkd',\n            'host' => 'localhost',\n            'queue' => 'default',\n            'retry_after' => 90,\n            'block_for' => 0,\n            'after_commit' => false,\n        ],\n\n        'sqs' => [\n            'driver' => 'sqs',\n            'key' => env('AWS_ACCESS_KEY_ID'),\n            'secret' => env('AWS_SECRET_ACCESS_KEY'),\n            'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),\n            'queue' => env('SQS_QUEUE', 'default'),\n            'suffix' => env('SQS_SUFFIX'),\n            'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),\n            'after_commit' => false,\n        ],\n\n        'redis' => [\n            'driver' => 'redis',\n            'connection' => 'default',\n            'queue' => env('REDIS_QUEUE', 'default'),\n            'retry_after' => 90,\n            'block_for' => null,\n            'after_commit' => false,\n        ],\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Failed Queue Jobs\n    |--------------------------------------------------------------------------\n    |\n    | These options configure the behavior of failed queue job logging so you\n    | can control which database and table are used to store the jobs that\n    | have failed. You may change them to any database / table you wish.\n    |\n    */\n\n    'failed' => [\n        'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),\n        'database' => env('DB_CONNECTION', 'mysql'),\n        'table' => 'failed_jobs',\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/react/config/sanctum.php",
    "content": "<?php\n\nuse Laravel\\Sanctum\\Sanctum;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Stateful Domains\n    |--------------------------------------------------------------------------\n    |\n    | Requests from the following domains / hosts will receive stateful API\n    | authentication cookies. Typically, these should include your local\n    | and production domains which access your API via a frontend SPA.\n    |\n    */\n\n    'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(\n        '%s%s',\n        'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',\n        Sanctum::currentApplicationUrlWithPort()\n    ))),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Sanctum Guards\n    |--------------------------------------------------------------------------\n    |\n    | This array contains the authentication guards that will be checked when\n    | Sanctum is trying to authenticate a request. If none of these guards\n    | are able to authenticate the request, Sanctum will use the bearer\n    | token that's present on an incoming request for authentication.\n    |\n    */\n\n    'guard' => ['web'],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Expiration Minutes\n    |--------------------------------------------------------------------------\n    |\n    | This value controls the number of minutes until an issued token will be\n    | considered expired. If this value is null, personal access tokens do\n    | not expire. This won't tweak the lifetime of first-party sessions.\n    |\n    */\n\n    'expiration' => null,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Sanctum Middleware\n    |--------------------------------------------------------------------------\n    |\n    | When authenticating your first-party SPA with Sanctum you may need to\n    | customize some of the middleware Sanctum uses while processing the\n    | request. You may change the middleware listed below as required.\n    |\n    */\n\n    'middleware' => [\n        'verify_csrf_token' => App\\Http\\Middleware\\VerifyCsrfToken::class,\n        'encrypt_cookies' => App\\Http\\Middleware\\EncryptCookies::class,\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/react/config/services.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Third Party Services\n    |--------------------------------------------------------------------------\n    |\n    | This file is for storing the credentials for third party services such\n    | as Mailgun, Postmark, AWS and more. This file provides the de facto\n    | location for this type of information, allowing packages to have\n    | a conventional file to locate the various service credentials.\n    |\n    */\n\n    'mailgun' => [\n        'domain' => env('MAILGUN_DOMAIN'),\n        'secret' => env('MAILGUN_SECRET'),\n        'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),\n        'scheme' => 'https',\n    ],\n\n    'postmark' => [\n        'token' => env('POSTMARK_TOKEN'),\n    ],\n\n    'ses' => [\n        'key' => env('AWS_ACCESS_KEY_ID'),\n        'secret' => env('AWS_SECRET_ACCESS_KEY'),\n        'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/react/config/session.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Str;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Session Driver\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default session \"driver\" that will be used on\n    | requests. By default, we will use the lightweight native driver but\n    | you may specify any of the other wonderful drivers provided here.\n    |\n    | Supported: \"file\", \"cookie\", \"database\", \"apc\",\n    |            \"memcached\", \"redis\", \"dynamodb\", \"array\"\n    |\n    */\n\n    'driver' => env('SESSION_DRIVER', 'file'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Lifetime\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the number of minutes that you wish the session\n    | to be allowed to remain idle before it expires. If you want them\n    | to immediately expire on the browser closing, set that option.\n    |\n    */\n\n    'lifetime' => env('SESSION_LIFETIME', 120),\n\n    'expire_on_close' => false,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Encryption\n    |--------------------------------------------------------------------------\n    |\n    | This option allows you to easily specify that all of your session data\n    | should be encrypted before it is stored. All encryption will be run\n    | automatically by Laravel and you can use the Session like normal.\n    |\n    */\n\n    'encrypt' => false,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session File Location\n    |--------------------------------------------------------------------------\n    |\n    | When using the native session driver, we need a location where session\n    | files may be stored. A default has been set for you but a different\n    | location may be specified. This is only needed for file sessions.\n    |\n    */\n\n    'files' => storage_path('framework/sessions'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Database Connection\n    |--------------------------------------------------------------------------\n    |\n    | When using the \"database\" or \"redis\" session drivers, you may specify a\n    | connection that should be used to manage these sessions. This should\n    | correspond to a connection in your database configuration options.\n    |\n    */\n\n    'connection' => env('SESSION_CONNECTION'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Database Table\n    |--------------------------------------------------------------------------\n    |\n    | When using the \"database\" session driver, you may specify the table we\n    | should use to manage the sessions. Of course, a sensible default is\n    | provided for you; however, you are free to change this as needed.\n    |\n    */\n\n    'table' => 'sessions',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Cache Store\n    |--------------------------------------------------------------------------\n    |\n    | While using one of the framework's cache driven session backends you may\n    | list a cache store that should be used for these sessions. This value\n    | must match with one of the application's configured cache \"stores\".\n    |\n    | Affects: \"apc\", \"dynamodb\", \"memcached\", \"redis\"\n    |\n    */\n\n    'store' => env('SESSION_STORE'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Sweeping Lottery\n    |--------------------------------------------------------------------------\n    |\n    | Some session drivers must manually sweep their storage location to get\n    | rid of old sessions from storage. Here are the chances that it will\n    | happen on a given request. By default, the odds are 2 out of 100.\n    |\n    */\n\n    'lottery' => [2, 100],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Cookie Name\n    |--------------------------------------------------------------------------\n    |\n    | Here you may change the name of the cookie used to identify a session\n    | instance by ID. The name specified here will get used every time a\n    | new session cookie is created by the framework for every driver.\n    |\n    */\n\n    'cookie' => env(\n        'SESSION_COOKIE',\n        Str::slug(env('APP_NAME', 'laravel'), '_').'_session'\n    ),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Cookie Path\n    |--------------------------------------------------------------------------\n    |\n    | The session cookie path determines the path for which the cookie will\n    | be regarded as available. Typically, this will be the root path of\n    | your application but you are free to change this when necessary.\n    |\n    */\n\n    'path' => '/',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Cookie Domain\n    |--------------------------------------------------------------------------\n    |\n    | Here you may change the domain of the cookie used to identify a session\n    | in your application. This will determine which domains the cookie is\n    | available to in your application. A sensible default has been set.\n    |\n    */\n\n    'domain' => env('SESSION_DOMAIN'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | HTTPS Only Cookies\n    |--------------------------------------------------------------------------\n    |\n    | By setting this option to true, session cookies will only be sent back\n    | to the server if the browser has a HTTPS connection. This will keep\n    | the cookie from being sent to you when it can't be done securely.\n    |\n    */\n\n    'secure' => env('SESSION_SECURE_COOKIE'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | HTTP Access Only\n    |--------------------------------------------------------------------------\n    |\n    | Setting this value to true will prevent JavaScript from accessing the\n    | value of the cookie and the cookie will only be accessible through\n    | the HTTP protocol. You are free to modify this option if needed.\n    |\n    */\n\n    'http_only' => true,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Same-Site Cookies\n    |--------------------------------------------------------------------------\n    |\n    | This option determines how your cookies behave when cross-site requests\n    | take place, and can be used to mitigate CSRF attacks. By default, we\n    | will set this value to \"lax\" since this is a secure default value.\n    |\n    | Supported: \"lax\", \"strict\", \"none\", null\n    |\n    */\n\n    'same_site' => 'lax',\n\n];\n"
  },
  {
    "path": "playgrounds/react/config/view.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | View Storage Paths\n    |--------------------------------------------------------------------------\n    |\n    | Most templating systems load templates from disk. Here you may specify\n    | an array of paths that should be checked for your views. Of course\n    | the usual Laravel view path has already been registered for you.\n    |\n    */\n\n    'paths' => [\n        resource_path('views'),\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Compiled View Path\n    |--------------------------------------------------------------------------\n    |\n    | This option determines where all the compiled Blade templates will be\n    | stored for your application. Typically, this is within the storage\n    | directory. However, as usual, you are free to change this value.\n    |\n    */\n\n    'compiled' => env(\n        'VIEW_COMPILED_PATH',\n        realpath(storage_path('framework/views'))\n    ),\n\n];\n"
  },
  {
    "path": "playgrounds/react/database/.gitignore",
    "content": "*.sqlite*\n"
  },
  {
    "path": "playgrounds/react/database/factories/ChatMessageFactory.php",
    "content": "<?php\n\nnamespace Database\\Factories;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\n\n/**\n * @extends \\Illuminate\\Database\\Eloquent\\Factories\\Factory<\\App\\Models\\ChatMessage>\n */\nclass ChatMessageFactory extends Factory\n{\n    /**\n     * Define the model's default state.\n     *\n     * @return array<string, mixed>\n     */\n    public function definition(): array\n    {\n        return [\n            'type' => $this->faker->randomElement(['prompt', 'response']),\n            'content' => $this->faker->sentence,\n        ];\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/database/factories/UserFactory.php",
    "content": "<?php\n\nnamespace Database\\Factories;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\nuse Illuminate\\Support\\Str;\n\n/**\n * @extends \\Illuminate\\Database\\Eloquent\\Factories\\Factory<\\App\\Models\\User>\n */\nclass UserFactory extends Factory\n{\n    /**\n     * Define the model's default state.\n     *\n     * @return array<string, mixed>\n     */\n    public function definition()\n    {\n        return [\n            'name' => fake()->name(),\n            'email' => fake()->unique()->safeEmail(),\n            'email_verified_at' => now(),\n            'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password\n            'remember_token' => Str::random(10),\n        ];\n    }\n\n    /**\n     * Indicate that the model's email address should be unverified.\n     *\n     * @return static\n     */\n    public function unverified()\n    {\n        return $this->state(fn (array $attributes) => [\n            'email_verified_at' => null,\n        ]);\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/database/migrations/2014_10_12_000000_create_users_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('users', function (Blueprint $table) {\n            $table->id();\n            $table->string('name');\n            $table->string('email')->unique();\n            $table->timestamp('email_verified_at')->nullable();\n            $table->string('password');\n            $table->rememberToken();\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('users');\n    }\n};\n"
  },
  {
    "path": "playgrounds/react/database/migrations/2014_10_12_100000_create_password_resets_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('password_resets', function (Blueprint $table) {\n            $table->string('email')->index();\n            $table->string('token');\n            $table->timestamp('created_at')->nullable();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('password_resets');\n    }\n};\n"
  },
  {
    "path": "playgrounds/react/database/migrations/2019_08_19_000000_create_failed_jobs_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('failed_jobs', function (Blueprint $table) {\n            $table->id();\n            $table->string('uuid')->unique();\n            $table->text('connection');\n            $table->text('queue');\n            $table->longText('payload');\n            $table->longText('exception');\n            $table->timestamp('failed_at')->useCurrent();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('failed_jobs');\n    }\n};\n"
  },
  {
    "path": "playgrounds/react/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('personal_access_tokens', function (Blueprint $table) {\n            $table->id();\n            $table->morphs('tokenable');\n            $table->string('name');\n            $table->string('token', 64)->unique();\n            $table->text('abilities')->nullable();\n            $table->timestamp('last_used_at')->nullable();\n            $table->timestamp('expires_at')->nullable();\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('personal_access_tokens');\n    }\n};\n"
  },
  {
    "path": "playgrounds/react/database/migrations/2025_08_29_115526_create_chat_messages_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     */\n    public function up(): void\n    {\n        Schema::create('chat_messages', function (Blueprint $table) {\n            $table->id();\n            $table->string('type');\n            $table->text('content');\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     */\n    public function down(): void\n    {\n        Schema::dropIfExists('chat_messages');\n    }\n};\n"
  },
  {
    "path": "playgrounds/react/database/seeders/DatabaseSeeder.php",
    "content": "<?php\n\nnamespace Database\\Seeders;\n\n// use Illuminate\\Database\\Console\\Seeds\\WithoutModelEvents;\n\nuse App\\Models\\ChatMessage;\nuse Illuminate\\Database\\Seeder;\nuse Illuminate\\Support\\Facades\\File;\n\nclass DatabaseSeeder extends Seeder\n{\n    /**\n     * Seed the application's database.\n     *\n     * @return void\n     */\n    public function run()\n    {\n        collect(File::json(database_path('seeders/conversation.json')))\n            ->each(fn ($chatMessage) => ChatMessage::create($chatMessage));\n\n        // \\App\\Models\\User::factory(5000)->create();\n\n        // \\App\\Models\\User::factory()->create([\n        //     'name' => 'Test User',\n        //     'email' => 'test@example.com',\n        // ]);\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/database/seeders/conversation.json",
    "content": "[\n  {\n    \"type\": \"prompt\",\n    \"content\": \"Hey! Tell me about PHP\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Okay, let's talk about PHP (Hypertext Preprocessor). PHP is a widely-used, open-source scripting language primarily designed for web development. It\\u2019s known for its ease of use and large community support.  \\n\\nHere's a breakdown of key aspects:\\n\\n1.  **Server-Side Scripting:** PHP code runs on the web server, generating HTML that is sent to the user's browser.  This is different from client-side languages like JavaScript, which execute in the browser.\\n\\n2.  **Dynamic Content:** PHP excels at creating dynamic web pages. It can generate content based on user input, database queries, or other variables.\\n\\n   ```php\\n   <?php\\n   echo \\\"Hello, World!\\\"; \\/\\/ Prints \\\"Hello, World!\\\" to the browser.\\n   ?>\\n   ```\\n\\n3.  **Database Integration:** PHP has excellent support for connecting to and interacting with various databases like MySQL, PostgreSQL, and MongoDB.\\n\\n   ```php\\n   <?php\\n   $servername = \\\"localhost\\\";\\n   $username = \\\"your_username\\\";\\n   $password = \\\"your_password\\\";\\n   $dbname = \\\"your_database\\\";\\n\\n   \\/\\/ Create connection\\n   $conn = new mysqli($servername, $username, $password, $dbname);\\n\\n   \\/\\/ Check connection\\n   if ($conn->connect_error) {\\n     die(\\\"Connection failed: \\\" . $conn->connect_error);\\n   }\\n\\n   echo \\\"Connected to database successfully\\\";\\n   ?>\\n   ```\\n\\n4.  **Frameworks:** Popular PHP frameworks like Laravel, Symfony, and CodeIgniter provide structure and tools to streamline development.\\n\\n5.  **Usage:** PHP is used to build everything from simple websites and blogs to complex web applications, e-commerce platforms, and APIs. \\n\\n6.  **Evolution:** PHP has evolved significantly over the years, with modern versions (PHP 7.x and 8.x) offering improved performance and features.\\n\\nIn essence, PHP is a versatile and mature language that remains a significant force in web development.\\n\\n\\n\\nDo you want to know about a specific aspect of PHP, such as its syntax, frameworks, or usage examples?\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"What is Laravel?\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Laravel is a popular, open-source PHP framework designed for building web applications efficiently. It follows the Model-View-Controller (MVC) architectural pattern, promoting organized code and maintainability. Laravel provides a robust set of tools and features to simplify development.\\n\\nHere's a basic example:\\n\\n```php\\n<?php\\n\\/\\/ Example: A simple Laravel route\\nRoute::get('\\/', function () {\\n    return \\\"Hello, World!\\\";\\n});\\n?>\\n```\\n\\nKey features include:\\n\\n*   **Eloquent ORM:** For easy database interaction.\\n*   **Templating Engine (Blade):**  For creating dynamic HTML.\\n*   **Routing:** For mapping URLs to controller actions.\\n*   **Security Features:** Built-in protection against common vulnerabilities.\\n\\nLaravel\\u2019s ecosystem has a huge community and lots of packages, making it a solid choice for modern web development. Essentially, it\\u2019s a toolkit that accelerates the process of creating robust and scalable PHP applications.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"Eloquent sounds... very nice!\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Laravel is a popular PHP framework known for its elegant design and powerful features. It follows the MVC architectural pattern, promoting organized code. Eloquent, Laravel\\u2019s ORM (Object-Relational Mapper), simplifies database interactions \\u2013 like this: `$users = User::all();`. Laravel\\u2019s routing system, like `Route::get('\\/', function () { return \\\"Hello, World!\\\"; });`, connects URLs to your application\\u2019s logic. Blade, Laravel's templating engine, allows you to create dynamic HTML. Laravel includes built-in security features to protect your app. It\\u2019s a robust framework for building web applications quickly and efficiently.  Laravel\\u2019s large community provides plenty of support and resources.  It is a great choice for modern web development.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"I want to know more about Eloquent\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Eloquent is Laravel\\u2019s powerful ORM (Object-Relational Mapper), simplifying database interactions. It allows you to interact with your database using PHP objects instead of raw SQL.  \\n\\nFor example, `$users = User::all();` retrieves all users from your database. Eloquent models represent database tables, offering a cleaner and more object-oriented approach. It handles SQL queries automatically, making development faster and more maintainable. \\n\\nEloquent provides features like relationships (one-to-one, one-to-many, many-to-many) to model complex data connections. You can also use Eloquent to perform CRUD (Create, Read, Update, Delete) operations. \\n\\n```php\\n\\/\\/ Example: Retrieving a user by ID\\n$user = User::find(1);\\n```\\n\\nEloquent is a core component of Laravel, streamlining database access and improving development efficiency.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"Does it work with MySQL?\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Yes, Eloquent works seamlessly with MySQL. It\\u2019s Laravel\\u2019s primary ORM, designed for database interactions, and MySQL is a very common and well-supported database backend for Laravel applications. Eloquent models represent your MySQL tables, allowing you to retrieve, create, update, and delete data using PHP objects. For example, `$users = User::all();` fetches all records from the `users` table. You can define relationships between models, like one-to-many, to represent data connections. Eloquent simplifies database interactions significantly, reducing the need for raw SQL queries in many cases. It\\u2019s a robust and efficient way to manage your data within a Laravel application and MySQL.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"What other engins does it support?\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Based on our discussion, Eloquent primarily supports MySQL. While the context didn\\u2019t explicitly list all supported engines, Laravel\\u2019s ORM is designed for flexibility and can be used with other databases like PostgreSQL, MongoDB, and SQLite. For example, `$users = User::all();` works regardless of the database backend.  Eloquent\\u2019s core architecture allows for database abstraction, meaning you can change the underlying database without altering your application logic. The framework provides tools to manage connections and queries. Laravel\\u2019s flexibility makes it a powerful choice for diverse database environments.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"Ah, even SQLite! What's the difference between MySQL and MariaDB these days?\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Eloquent primarily supports MySQL and SQLite. Both are excellent choices for Laravel development. MySQL is a robust, widely-used relational database, while SQLite is a lightweight, file-based database \\u2013 perfect for smaller projects or development environments.  Eloquent works identically with both, simplifying database interactions.  There isn't a significant difference in functionality between MySQL and MariaDB that would impact Eloquent\\u2019s usage. MariaDB is a fork of MySQL, offering similar features and compatibility.  Eloquent\\u2019s abstraction layer handles the underlying differences, allowing you to focus on your application logic. Essentially, you can use Eloquent with either database without needing to adjust your code significantly.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"But outside of Laravel and Eloquent, why should I use MariaDB?\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Based on our conversation, Eloquent primarily supports MySQL and SQLite. MariaDB is a fork of MySQL, offering similar features. While Laravel\\u2019s Eloquent works with both, MariaDB\\u2019s primary advantage lies in its performance and open-source nature. It\\u2019s often faster than MySQL, especially for certain workloads. MariaDB\\u2019s open-source license provides greater flexibility and control compared to proprietary databases. For example, `$users = User::all();` would function identically with MariaDB as with MySQL. MariaDB\\u2019s community support is strong. It's a viable alternative if you\\u2019re seeking a robust, open-source database solution, offering similar functionality to MySQL.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"Ok, let's change topics. Tell me about Event Broadcasting in Laravel\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Laravel\\u2019s Event Broadcasting system allows decoupled communication between services and components. It uses events and listeners to trigger actions without direct dependencies.\\n\\nTo create an event, define a class extending `Illuminate\\\\Events\\\\DispatchableEvent`.  For example:\\n\\n```php\\n<?php\\n\\nnamespace App\\\\Events;\\n\\nuse Illuminate\\\\Broadcasting\\\\Channel;\\nuse Illuminate\\\\Contracts\\\\Broadcasting\\\\Broadcastable;\\n\\nclass UserRegistered implements Broadcastable\\n{\\n    public function __construct() {}\\n}\\n```\\n\\nThen, use `dispatch()` to trigger the event: `$event = new UserRegistered(); Event::dispatch($event);`\\n\\nListeners subscribe to events using `listen()` or `subscribe()` to receive and react to them.\\n\\n```php\\n<?php\\n\\nnamespace App\\\\Listeners;\\n\\nuse App\\\\Events\\\\UserRegistered;\\nuse Illuminate\\\\Contracts\\\\Events\\\\Listener;\\n\\nclass UserRegistrationListener implements Listener\\n{\\n    public function listen(UserRegistered $event)\\n    {\\n        \\/\\/ Handle the event here.\\n        echo \\\"User registered!\\\";\\n    }\\n}\\n```\\n\\nThis allows for flexible and scalable applications. Events promote loosely coupled architecture.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"Broadcastable? Really? Shouldn't that be ShouldBroadcast?\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"You're right to question that \\u2013 the context provided focuses on the core Event Broadcasting system. Laravel\\u2019s `Broadcastable` interface defines events that can be broadcast to channels. The `Broadcastable` interface is used for events meant to be sent to clients (like web browsers) using WebSockets.  It\\u2019s not directly tied to the channel itself.  To broadcast an event to a specific channel, you\\u2019d use `Event::dispatch($event, ['channel' => 'your_channel_name']);` The `Broadcastable` interface is essential for establishing the communication channel. For example: `$event = new UserRegistered(); Event::dispatch($event, ['channel' => 'channel_name']);` Laravel\\u2019s Event Broadcasting simplifies real-time communication by decoupling event publishers and subscribers.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"Hmm you don't know a lot about this topic... let's talk about Inertia.js\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Okay, let\\u2019s discuss Inertia.js. Inertia.js simplifies building modern Vue.js applications with Laravel. It allows you to serve Vue components from your Laravel backend, handling routing and authentication.\\n\\nTo use Inertia, you\\u2019d typically create a Vue component \\u2013 for instance, a `components\\/HelloWorld.vue` file. Then, you\\u2019d use Inertia to \\u201chydrate\\u201d this component on the server. \\n\\n```php\\nuse Inertia\\\\Payload;\\nuse Illuminate\\\\Support\\\\Facades\\\\Route;\\n\\nRoute::get('\\/hello', function () {\\n    $payload = new Payload([\\n        'message' => 'Hello from Inertia!'\\n    ]);\\n    return inertia('hello', $payload);\\n});\\n```\\n\\nThis sends the Vue component and its data to the browser. The browser renders the Vue component. Inertia manages the separation of concerns, streamlining your Laravel and Vue development workflow.\"\n  }\n]\n"
  },
  {
    "path": "playgrounds/react/init.sh",
    "content": "#!/bin/bash\nset -e\n\n# Install PHP dependencies via Composer\nif [ ! -d \"vendor\" ]; then\n    echo \"Installing PHP dependencies...\"\n    composer install\nelse\n    echo \"PHP dependencies already installed\"\nfi\n\n# Install Node.js dependencies via pnpm\nif [ ! -d \"node_modules\" ]; then\n    echo \"Installing Node.js dependencies...\"\n    pnpm install\nelse\n    echo \"Node.js dependencies already installed\"\nfi\n\n# Set up environment configuration\nif [ ! -f \".env\" ]; then\n    echo \"Creating environment configuration...\"\n    cp .env.example .env\n    php artisan key:generate\nelse\n    echo \"Environment configuration already exists\"\nfi\n\n# Set up SQLite database\nif [ ! -f \"database/database.sqlite\" ]; then\n    echo \"Creating SQLite database...\"\n    touch database/database.sqlite\n    echo \"Running fresh migrations with seed data...\"\n    php artisan migrate:fresh --seed\nelse\n    echo \"Database already exists\"\nfi\n\n# Ensure database is up to date\necho \"Running any pending migrations...\"\nphp artisan migrate\n"
  },
  {
    "path": "playgrounds/react/lang/en/auth.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Authentication Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines are used during authentication for various\n    | messages that we need to display to the user. You are free to modify\n    | these language lines according to your application's requirements.\n    |\n    */\n\n    'failed' => 'These credentials do not match our records.',\n    'password' => 'The provided password is incorrect.',\n    'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',\n\n];\n"
  },
  {
    "path": "playgrounds/react/lang/en/pagination.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Pagination Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines are used by the paginator library to build\n    | the simple pagination links. You are free to change them to anything\n    | you want to customize your views to better match your application.\n    |\n    */\n\n    'previous' => '&laquo; Previous',\n    'next' => 'Next &raquo;',\n\n];\n"
  },
  {
    "path": "playgrounds/react/lang/en/passwords.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Password Reset Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines are the default lines which match reasons\n    | that are given by the password broker for a password update attempt\n    | has failed, such as for an invalid token or invalid new password.\n    |\n    */\n\n    'reset' => 'Your password has been reset!',\n    'sent' => 'We have emailed your password reset link!',\n    'throttled' => 'Please wait before retrying.',\n    'token' => 'This password reset token is invalid.',\n    'user' => \"We can't find a user with that email address.\",\n\n];\n"
  },
  {
    "path": "playgrounds/react/lang/en/validation.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Validation Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines contain the default error messages used by\n    | the validator class. Some of these rules have multiple versions such\n    | as the size rules. Feel free to tweak each of these messages here.\n    |\n    */\n\n    'accepted' => 'The :attribute must be accepted.',\n    'accepted_if' => 'The :attribute must be accepted when :other is :value.',\n    'active_url' => 'The :attribute is not a valid URL.',\n    'after' => 'The :attribute must be a date after :date.',\n    'after_or_equal' => 'The :attribute must be a date after or equal to :date.',\n    'alpha' => 'The :attribute must only contain letters.',\n    'alpha_dash' => 'The :attribute must only contain letters, numbers, dashes and underscores.',\n    'alpha_num' => 'The :attribute must only contain letters and numbers.',\n    'array' => 'The :attribute must be an array.',\n    'ascii' => 'The :attribute must only contain single-byte alphanumeric characters and symbols.',\n    'before' => 'The :attribute must be a date before :date.',\n    'before_or_equal' => 'The :attribute must be a date before or equal to :date.',\n    'between' => [\n        'array' => 'The :attribute must have between :min and :max items.',\n        'file' => 'The :attribute must be between :min and :max kilobytes.',\n        'numeric' => 'The :attribute must be between :min and :max.',\n        'string' => 'The :attribute must be between :min and :max characters.',\n    ],\n    'boolean' => 'The :attribute field must be true or false.',\n    'confirmed' => 'The :attribute confirmation does not match.',\n    'current_password' => 'The password is incorrect.',\n    'date' => 'The :attribute is not a valid date.',\n    'date_equals' => 'The :attribute must be a date equal to :date.',\n    'date_format' => 'The :attribute does not match the format :format.',\n    'decimal' => 'The :attribute must have :decimal decimal places.',\n    'declined' => 'The :attribute must be declined.',\n    'declined_if' => 'The :attribute must be declined when :other is :value.',\n    'different' => 'The :attribute and :other must be different.',\n    'digits' => 'The :attribute must be :digits digits.',\n    'digits_between' => 'The :attribute must be between :min and :max digits.',\n    'dimensions' => 'The :attribute has invalid image dimensions.',\n    'distinct' => 'The :attribute field has a duplicate value.',\n    'doesnt_end_with' => 'The :attribute may not end with one of the following: :values.',\n    'doesnt_start_with' => 'The :attribute may not start with one of the following: :values.',\n    'email' => 'The :attribute must be a valid email address.',\n    'ends_with' => 'The :attribute must end with one of the following: :values.',\n    'enum' => 'The selected :attribute is invalid.',\n    'exists' => 'The selected :attribute is invalid.',\n    'file' => 'The :attribute must be a file.',\n    'filled' => 'The :attribute field must have a value.',\n    'gt' => [\n        'array' => 'The :attribute must have more than :value items.',\n        'file' => 'The :attribute must be greater than :value kilobytes.',\n        'numeric' => 'The :attribute must be greater than :value.',\n        'string' => 'The :attribute must be greater than :value characters.',\n    ],\n    'gte' => [\n        'array' => 'The :attribute must have :value items or more.',\n        'file' => 'The :attribute must be greater than or equal to :value kilobytes.',\n        'numeric' => 'The :attribute must be greater than or equal to :value.',\n        'string' => 'The :attribute must be greater than or equal to :value characters.',\n    ],\n    'image' => 'The :attribute must be an image.',\n    'in' => 'The selected :attribute is invalid.',\n    'in_array' => 'The :attribute field does not exist in :other.',\n    'integer' => 'The :attribute must be an integer.',\n    'ip' => 'The :attribute must be a valid IP address.',\n    'ipv4' => 'The :attribute must be a valid IPv4 address.',\n    'ipv6' => 'The :attribute must be a valid IPv6 address.',\n    'json' => 'The :attribute must be a valid JSON string.',\n    'lowercase' => 'The :attribute must be lowercase.',\n    'lt' => [\n        'array' => 'The :attribute must have less than :value items.',\n        'file' => 'The :attribute must be less than :value kilobytes.',\n        'numeric' => 'The :attribute must be less than :value.',\n        'string' => 'The :attribute must be less than :value characters.',\n    ],\n    'lte' => [\n        'array' => 'The :attribute must not have more than :value items.',\n        'file' => 'The :attribute must be less than or equal to :value kilobytes.',\n        'numeric' => 'The :attribute must be less than or equal to :value.',\n        'string' => 'The :attribute must be less than or equal to :value characters.',\n    ],\n    'mac_address' => 'The :attribute must be a valid MAC address.',\n    'max' => [\n        'array' => 'The :attribute must not have more than :max items.',\n        'file' => 'The :attribute must not be greater than :max kilobytes.',\n        'numeric' => 'The :attribute must not be greater than :max.',\n        'string' => 'The :attribute must not be greater than :max characters.',\n    ],\n    'max_digits' => 'The :attribute must not have more than :max digits.',\n    'mimes' => 'The :attribute must be a file of type: :values.',\n    'mimetypes' => 'The :attribute must be a file of type: :values.',\n    'min' => [\n        'array' => 'The :attribute must have at least :min items.',\n        'file' => 'The :attribute must be at least :min kilobytes.',\n        'numeric' => 'The :attribute must be at least :min.',\n        'string' => 'The :attribute must be at least :min characters.',\n    ],\n    'min_digits' => 'The :attribute must have at least :min digits.',\n    'multiple_of' => 'The :attribute must be a multiple of :value.',\n    'not_in' => 'The selected :attribute is invalid.',\n    'not_regex' => 'The :attribute format is invalid.',\n    'numeric' => 'The :attribute must be a number.',\n    'password' => [\n        'letters' => 'The :attribute must contain at least one letter.',\n        'mixed' => 'The :attribute must contain at least one uppercase and one lowercase letter.',\n        'numbers' => 'The :attribute must contain at least one number.',\n        'symbols' => 'The :attribute must contain at least one symbol.',\n        'uncompromised' => 'The given :attribute has appeared in a data leak. Please choose a different :attribute.',\n    ],\n    'present' => 'The :attribute field must be present.',\n    'prohibited' => 'The :attribute field is prohibited.',\n    'prohibited_if' => 'The :attribute field is prohibited when :other is :value.',\n    'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.',\n    'prohibits' => 'The :attribute field prohibits :other from being present.',\n    'regex' => 'The :attribute format is invalid.',\n    'required' => 'The :attribute field is required.',\n    'required_array_keys' => 'The :attribute field must contain entries for: :values.',\n    'required_if' => 'The :attribute field is required when :other is :value.',\n    'required_if_accepted' => 'The :attribute field is required when :other is accepted.',\n    'required_unless' => 'The :attribute field is required unless :other is in :values.',\n    'required_with' => 'The :attribute field is required when :values is present.',\n    'required_with_all' => 'The :attribute field is required when :values are present.',\n    'required_without' => 'The :attribute field is required when :values is not present.',\n    'required_without_all' => 'The :attribute field is required when none of :values are present.',\n    'same' => 'The :attribute and :other must match.',\n    'size' => [\n        'array' => 'The :attribute must contain :size items.',\n        'file' => 'The :attribute must be :size kilobytes.',\n        'numeric' => 'The :attribute must be :size.',\n        'string' => 'The :attribute must be :size characters.',\n    ],\n    'starts_with' => 'The :attribute must start with one of the following: :values.',\n    'string' => 'The :attribute must be a string.',\n    'timezone' => 'The :attribute must be a valid timezone.',\n    'unique' => 'The :attribute has already been taken.',\n    'uploaded' => 'The :attribute failed to upload.',\n    'uppercase' => 'The :attribute must be uppercase.',\n    'url' => 'The :attribute must be a valid URL.',\n    'ulid' => 'The :attribute must be a valid ULID.',\n    'uuid' => 'The :attribute must be a valid UUID.',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Custom Validation Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify custom validation messages for attributes using the\n    | convention \"attribute.rule\" to name the lines. This makes it quick to\n    | specify a specific custom language line for a given attribute rule.\n    |\n    */\n\n    'custom' => [\n        'attribute-name' => [\n            'rule-name' => 'custom-message',\n        ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Custom Validation Attributes\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines are used to swap our attribute placeholder\n    | with something more reader friendly such as \"E-Mail Address\" instead\n    | of \"email\". This simply helps us make our message more expressive.\n    |\n    */\n\n    'attributes' => [],\n\n];\n"
  },
  {
    "path": "playgrounds/react/package.json",
    "content": "{\n  \"name\": \"@inertiajs/react-playground\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"vite build && vite build --ssr\"\n  },\n  \"type\": \"module\",\n  \"devDependencies\": {\n    \"@inertiajs/core\": \"workspace:*\",\n    \"@inertiajs/react\": \"workspace:*\",\n    \"@laravel/stream-react\": \"^0.3.13\",\n    \"@tailwindcss/typography\": \"^0.5.19\",\n    \"@tailwindcss/vite\": \"^4.2.1\",\n    \"@types/react\": \"^19.2.14\",\n    \"@types/react-dom\": \"^19.2.3\",\n    \"@vitejs/plugin-react\": \"^5.1.4\",\n    \"autosize\": \"^6.0.1\",\n    \"axios\": \"^1.13.5\",\n    \"laravel-vite-plugin\": \"^2.1.0\",\n    \"lodash\": \"^4.17.23\",\n    \"marked\": \"^17.0.3\",\n    \"react\": \"^19.2.4\",\n    \"react-dom\": \"^19.2.4\",\n    \"tailwindcss\": \"^4.2.1\",\n    \"typescript\": \"^5.9.3\",\n    \"vite\": \"^7.3.1\"\n  }\n}\n"
  },
  {
    "path": "playgrounds/react/phpunit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:noNamespaceSchemaLocation=\"./vendor/phpunit/phpunit/phpunit.xsd\"\n         bootstrap=\"vendor/autoload.php\"\n         colors=\"true\"\n>\n    <testsuites>\n        <testsuite name=\"Unit\">\n            <directory suffix=\"Test.php\">./tests/Unit</directory>\n        </testsuite>\n        <testsuite name=\"Feature\">\n            <directory suffix=\"Test.php\">./tests/Feature</directory>\n        </testsuite>\n    </testsuites>\n    <coverage processUncoveredFiles=\"true\">\n        <include>\n            <directory suffix=\".php\">./app</directory>\n        </include>\n    </coverage>\n    <php>\n        <env name=\"APP_ENV\" value=\"testing\"/>\n        <env name=\"BCRYPT_ROUNDS\" value=\"4\"/>\n        <env name=\"CACHE_DRIVER\" value=\"array\"/>\n        <!-- <env name=\"DB_CONNECTION\" value=\"sqlite\"/> -->\n        <!-- <env name=\"DB_DATABASE\" value=\":memory:\"/> -->\n        <env name=\"MAIL_MAILER\" value=\"array\"/>\n        <env name=\"QUEUE_CONNECTION\" value=\"sync\"/>\n        <env name=\"SESSION_DRIVER\" value=\"array\"/>\n        <env name=\"TELESCOPE_ENABLED\" value=\"false\"/>\n    </php>\n</phpunit>\n"
  },
  {
    "path": "playgrounds/react/public/.htaccess",
    "content": "<IfModule mod_rewrite.c>\n    <IfModule mod_negotiation.c>\n        Options -MultiViews -Indexes\n    </IfModule>\n\n    RewriteEngine On\n\n    # Handle Authorization Header\n    RewriteCond %{HTTP:Authorization} .\n    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]\n\n    # Redirect Trailing Slashes If Not A Folder...\n    RewriteCond %{REQUEST_FILENAME} !-d\n    RewriteCond %{REQUEST_URI} (.+)/$\n    RewriteRule ^ %1 [L,R=301]\n\n    # Send Requests To Front Controller...\n    RewriteCond %{REQUEST_FILENAME} !-d\n    RewriteCond %{REQUEST_FILENAME} !-f\n    RewriteRule ^ index.php [L]\n</IfModule>\n"
  },
  {
    "path": "playgrounds/react/public/index.php",
    "content": "<?php\n\nuse Illuminate\\Contracts\\Http\\Kernel;\nuse Illuminate\\Http\\Request;\n\ndefine('LARAVEL_START', microtime(true));\n\n/*\n|--------------------------------------------------------------------------\n| Check If The Application Is Under Maintenance\n|--------------------------------------------------------------------------\n|\n| If the application is in maintenance / demo mode via the \"down\" command\n| we will load this file so that any pre-rendered content can be shown\n| instead of starting the framework, which could cause an exception.\n|\n*/\n\nif (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {\n    require $maintenance;\n}\n\n/*\n|--------------------------------------------------------------------------\n| Register The Auto Loader\n|--------------------------------------------------------------------------\n|\n| Composer provides a convenient, automatically generated class loader for\n| this application. We just need to utilize it! We'll simply require it\n| into the script here so we don't need to manually load our classes.\n|\n*/\n\nrequire __DIR__.'/../vendor/autoload.php';\n\n/*\n|--------------------------------------------------------------------------\n| Run The Application\n|--------------------------------------------------------------------------\n|\n| Once we have the application, we can handle the incoming request using\n| the application's HTTP kernel. Then, we will send the response back\n| to this client's browser, allowing them to enjoy our application.\n|\n*/\n\n$app = require_once __DIR__.'/../bootstrap/app.php';\n\n$kernel = $app->make(Kernel::class);\n\n$response = $kernel->handle(\n    $request = Request::capture()\n)->send();\n\n$kernel->terminate($request, $response);\n"
  },
  {
    "path": "playgrounds/react/public/robots.txt",
    "content": "User-agent: *\nDisallow:\n"
  },
  {
    "path": "playgrounds/react/resources/css/app.css",
    "content": "@import 'tailwindcss';\n@plugin '@tailwindcss/typography';\n"
  },
  {
    "path": "playgrounds/react/resources/js/Components/DeferredFood.tsx",
    "content": "import { useDeferred } from '@inertiajs/react'\n\nexport default () => {\n  const { foods } = useDeferred('foods')\n\n  return foods.map((food) => (\n    <div key={food.id}>\n      <p>\n        #{food.id}: {food.name}\n      </p>\n    </div>\n  ))\n}\n"
  },
  {
    "path": "playgrounds/react/resources/js/Components/DeferredOrganizations.tsx",
    "content": "import { useDeferred } from '@inertiajs/react'\n\nexport default () => {\n  const { organizations } = useDeferred('organizations')\n\n  return organizations.map((org) => (\n    <div key={org.id}>\n      <p>\n        #{org.id}: {org.name} ({org.url})\n      </p>\n    </div>\n  ))\n}\n"
  },
  {
    "path": "playgrounds/react/resources/js/Components/DeferredUsers.tsx",
    "content": "import { usePage } from '@inertiajs/react'\n\nexport default () => {\n  const users = usePage().props.users\n\n  return users.map((user) => (\n    <div key={user.id}>\n      <p>\n        #{user.id}: {user.name} ({user.email})\n      </p>\n    </div>\n  ))\n}\n"
  },
  {
    "path": "playgrounds/react/resources/js/Components/Image.tsx",
    "content": "import { useState } from 'react'\n\nexport default function Image({ id, url }: { id: number; url: string }) {\n  const [loaded, setLoaded] = useState(false)\n\n  return (\n    <div className=\"relative aspect-square overflow-hidden rounded-lg bg-gray-200\">\n      {!loaded && <div className=\"absolute inset-0 animate-pulse bg-gray-300\" aria-hidden=\"true\" />}\n\n      <img\n        src={url}\n        loading=\"lazy\"\n        decoding=\"async\"\n        className={`h-full w-full object-cover transition duration-500 ease-out ${\n          loaded ? 'blur-0 scale-100 opacity-100' : 'scale-105 opacity-0 blur-sm'\n        }`}\n        onLoad={() => setLoaded(true)}\n      />\n\n      <span className=\"pointer-events-none absolute bottom-2 left-2 rounded bg-black/50 px-2 py-1 text-sm text-white\">\n        {id}\n      </span>\n    </div>\n  )\n}\n"
  },
  {
    "path": "playgrounds/react/resources/js/Components/Layout.tsx",
    "content": "import { Link, usePage } from '@inertiajs/react'\n\nexport default function Layout({ children, padding = true }: { children: React.ReactNode; padding?: boolean }) {\n  const { appName } = usePage().props\n\n  return (\n    <>\n      <nav className=\"flex items-center space-x-6 bg-slate-800 px-10 py-6 text-white\">\n        <div className=\"rounded-lg bg-slate-700 px-4 py-1\">{appName}</div>\n        <Link href=\"/\" className=\"hover:underline\" prefetch>\n          Home\n        </Link>\n        <Link href=\"/users\" className=\"hover:underline\" prefetch=\"hover\" cacheFor={6000}>\n          Users\n        </Link>\n        <Link href=\"/article\" className=\"hover:underline\" prefetch=\"mount\" stale-after=\"10s\">\n          Article\n        </Link>\n        <Link href=\"/form\" className=\"hover:underline\" prefetch={['mount', 'click']} stale-after=\"1m\">\n          useForm\n        </Link>\n        <Link href=\"/form-component\" className=\"hover:underline\">\n          {'<Form>'}\n        </Link>\n        <Link href=\"/form-component/precognition\" className=\"hover:underline\">\n          Precognition\n        </Link>\n        <Link href=\"/async\" className=\"hover:underline\">\n          Async\n        </Link>\n        <Link href=\"/defer\" className=\"hover:underline\">\n          Defer\n        </Link>\n        <Link href=\"/poll\" className=\"hover:underline\">\n          Poll\n        </Link>\n        <Link href=\"/chat\" className=\"hover:underline\">\n          Chat\n        </Link>\n        <Link href=\"/photo-grid\" className=\"hover:underline\">\n          Photo Grid\n        </Link>\n        <Link href=\"/photo-grid/horizontal\" className=\"hover:underline\">\n          Photo Row\n        </Link>\n        <Link href=\"/data-table\" className=\"hover:underline\">\n          Table\n        </Link>\n        <Link href=\"/once/1\" className=\"hover:underline\">\n          Once\n        </Link>\n        <Link href=\"/flash\" className=\"hover:underline\">\n          Flash\n        </Link>\n        <Link href=\"/logout\" method=\"post\" className=\"hover:underline\">\n          Logout\n        </Link>\n      </nav>\n      <main className={padding ? 'px-10 py-8' : ''}>{children}</main>\n    </>\n  )\n}\n"
  },
  {
    "path": "playgrounds/react/resources/js/Components/Message.tsx",
    "content": "import { marked } from 'marked'\n\nexport interface Message {\n  id: number | string\n  type: 'prompt' | 'response'\n  content: string\n}\n\nexport default function MessageComponent({ message }: { message: Message }) {\n  const htmlContent = marked(message.content)\n\n  return (\n    <div className={`flex w-full ${message.type === 'prompt' ? 'ml-auto justify-end' : 'mr-auto justify-start'}`}>\n      <div className=\"flex max-w-[80%] items-start\">\n        <div\n          dangerouslySetInnerHTML={{ __html: htmlContent }}\n          className={`prose min-w-0 flex-1 text-[15px] leading-relaxed ${\n            message.type === 'prompt' ? 'rounded-xl bg-gray-800 px-4 py-2 text-white' : 'text-gray-800'\n          }`}\n        />\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "playgrounds/react/resources/js/Components/PaperAirplaneIcon.tsx",
    "content": "export default function PaperAirplaneIcon({ className = 'size-6' }: { className?: string }) {\n  return (\n    <svg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      fill=\"none\"\n      viewBox=\"0 0 24 24\"\n      strokeWidth=\"1.5\"\n      stroke=\"currentColor\"\n      className={className}\n    >\n      <path\n        strokeLinecap=\"round\"\n        strokeLinejoin=\"round\"\n        d=\"M6 12 3.269 3.125A59.769 59.769 0 0 1 21.485 12 59.768 59.768 0 0 1 3.27 20.875L5.999 12Zm0 0h7.5\"\n      />\n    </svg>\n  )\n}\n"
  },
  {
    "path": "playgrounds/react/resources/js/Components/Spinner.tsx",
    "content": "export default function Spinner({ className = '' }: { className?: string }) {\n  return (\n    <svg\n      className={`animate-spin text-black ${className}`}\n      xmlns=\"http://www.w3.org/2000/svg\"\n      fill=\"none\"\n      viewBox=\"0 0 24 24\"\n    >\n      <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\"></circle>\n      <path\n        className=\"opacity-75\"\n        fill=\"currentColor\"\n        d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n      ></path>\n    </svg>\n  )\n}\n"
  },
  {
    "path": "playgrounds/react/resources/js/Components/StreamingIndicator.tsx",
    "content": "export default function StreamingIndicator({ className = '' }: { className?: string }) {\n  return (\n    <div className={`flex justify-start ${className}`}>\n      <div className=\"mr-auto flex max-w-[80%] items-start\">\n        <div className=\"min-w-0 flex-1\">\n          <div className=\"py-2 text-[15px] leading-relaxed text-gray-800\">\n            <div className=\"flex items-center space-x-2\">\n              <div className=\"flex space-x-1\">\n                <div className=\"h-2 w-2 animate-bounce rounded-full bg-gray-500\"></div>\n                <div\n                  className=\"h-2 w-2 animate-bounce rounded-full bg-gray-500\"\n                  style={{ animationDelay: '0.1s' }}\n                ></div>\n                <div\n                  className=\"h-2 w-2 animate-bounce rounded-full bg-gray-500\"\n                  style={{ animationDelay: '0.2s' }}\n                ></div>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "playgrounds/react/resources/js/Components/TestGrid.tsx",
    "content": "const TestGrid = ({ children }) => {\n  return <div className=\"mt-6 grid grid-cols-3 gap-4\">{children}</div>\n}\n\nexport default TestGrid\n"
  },
  {
    "path": "playgrounds/react/resources/js/Components/TestGridItem.tsx",
    "content": "const TestGridItem = ({ children, title }) => {\n  return (\n    <div className=\"rounded-sm border border-gray-300 p-4 text-sm text-gray-500\">\n      {title && <div className=\"mb-2 font-bold\">{title}</div>}\n      {children}\n    </div>\n  )\n}\n\nexport default TestGridItem\n"
  },
  {
    "path": "playgrounds/react/resources/js/Components/Textarea.tsx",
    "content": "import { useEffect, useRef } from 'react'\n\nfunction autosize(element: HTMLTextAreaElement) {\n  element.style.height = 'auto'\n  element.style.height = element.scrollHeight + 'px'\n}\n\nexport default function Textarea({\n  value,\n  onChange,\n  placeholder,\n  onKeyDown,\n  className = '',\n}: {\n  value: string\n  onChange: (value: string) => void\n  placeholder?: string\n  onKeyDown?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void\n  className?: string\n}) {\n  const textareaRef = useRef<HTMLTextAreaElement>(null)\n\n  useEffect(() => {\n    if (textareaRef.current) {\n      autosize(textareaRef.current)\n    }\n  }, [value])\n\n  return (\n    <textarea\n      ref={textareaRef}\n      rows={1}\n      value={value}\n      onChange={(e) => onChange(e.target.value)}\n      placeholder={placeholder}\n      onKeyDown={onKeyDown}\n      className={`block w-full resize-none border-0 bg-transparent py-1 text-[16px] text-gray-900 placeholder-gray-500 outline-none ${className}`}\n    />\n  )\n}\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/Article.tsx",
    "content": "import { Head } from '@inertiajs/react'\nimport Layout from '../Components/Layout'\n\nconst Article = () => {\n  return (\n    <>\n      <Head title=\"Article\" />\n      <h1 className=\"text-3xl\">Article</h1>\n      <article className=\"max-w-3xl\">\n        <p className=\"my-6\">\n          Sunt culpa sit sunt enim aliquip. Esse ea ea quis voluptate. Enim consectetur aliqua ex ex magna cupidatat id\n          minim sit elit. Amet pariatur occaecat pariatur duis eiusmod dolore magna. Et commodo cupidatat in commodo\n          elit cupidatat minim qui id non enim ad. Culpa aliquip ad Lorem sit consectetur ullamco culpa duis nisi et\n          fugiat mollit eiusmod. Laboris voluptate veniam consequat proident in nulla irure velit.\n        </p>\n        <p className=\"my-6\">\n          Sit sint laboris sunt eiusmod ipsum laborum eiusmod amet commodo exercitation in duis magna. Proident sunt\n          minim in elit qui. Id pariatur commodo fugiat excepteur in deserunt Lorem ipsum occaecat est. Excepteur sit\n          tempor ipsum ex officia veniam enim amet velit fugiat mollit cillum. Incididunt aliqua nulla id occaecat\n          nulla. Non ea ad est occaecat deserunt officia qui commodo exercitation.\n        </p>\n        <p className=\"my-6\">\n          Voluptate laborum quis aliqua ullamco magna amet ullamco laborum qui cillum eu. Dolore dolore aliqua proident\n          proident sunt ipsum in. Enim velit dolore labore dolor quis incididunt duis culpa Lorem. Eu adipisicing non\n          elit fugiat voluptate labore ipsum dolore consectetur commodo. Et in et cillum duis consequat quis ex eu\n          commodo. Eiusmod aliqua excepteur consectetur eiusmod aute et consectetur sit pariatur dolore qui officia\n          pariatur.\n        </p>\n        <p className=\"my-6\">\n          Non sunt eu mollit qui reprehenderit. Aute culpa anim voluptate do in esse duis laborum ad dolore. Ullamco\n          nisi in nostrud officia do. Duis pariatur officia id duis. Deserunt ad incididunt est sint consectetur\n          reprehenderit mollit est Lorem ea pariatur anim dolor adipisicing. Nostrud irure magna nostrud laboris aute\n          sunt veniam laboris veniam incididunt sit. Nulla proident ad aliqua fugiat culpa sunt est in dolor velit ad\n          irure nulla.\n        </p>\n        <p className=\"my-6\">\n          Do aute laborum deserunt non laborum voluptate voluptate. Anim ut laborum magna sunt cupidatat irure.\n          Cupidatat fugiat minim sint cillum laborum excepteur irure id est irure ad occaecat adipisicing enim. Deserunt\n          nulla anim proident velit irure nostrud est est reprehenderit consequat pariatur qui. Fugiat Lorem sint eu\n          laborum minim pariatur cillum mollit nulla consequat ullamco ex. Ex consectetur ad ut irure fugiat occaecat\n          aliqua exercitation cillum ipsum anim dolore tempor.\n        </p>\n        <p className=\"my-6\">\n          Adipisicing consequat irure fugiat Lorem deserunt aliquip do cupidatat. Lorem labore elit ex qui nostrud qui\n          cillum sunt adipisicing occaecat. Sunt nostrud amet amet cupidatat fugiat Lorem quis nulla id cillum esse eu.\n          Ullamco aliqua dolore irure amet mollit anim velit dolore.\n        </p>\n        <p className=\"my-6\">\n          Veniam cupidatat ipsum ea officia ipsum nisi laborum culpa qui dolore. Aliqua Lorem nisi labore ea velit\n          aliquip irure excepteur eu. Laboris proident duis non labore sunt quis aute tempor laboris enim anim eiusmod.\n        </p>\n        <p className=\"my-6\">\n          Minim proident ut aliqua ea ut culpa fugiat ullamco nisi esse nostrud reprehenderit id. Id id ullamco velit\n          anim nisi magna Lorem tempor. Et veniam occaecat ut labore consequat fugiat duis.\n        </p>\n        <p className=\"my-6\">\n          Adipisicing ea consectetur adipisicing aute eu pariatur enim labore consequat occaecat consectetur minim nisi.\n          Cillum commodo sunt labore reprehenderit. Duis esse excepteur magna tempor eiusmod exercitation Lorem\n          reprehenderit excepteur pariatur. Esse cupidatat occaecat magna do aliquip Lorem. Consectetur adipisicing\n          consequat dolore nostrud esse eu cillum id commodo duis. Aliquip dolor cillum cupidatat fugiat.\n        </p>\n        <h2 id=\"far-down\" className=\"mt-8 text-2xl\">\n          Far down\n        </h2>\n        <p className=\"my-6\">\n          Ex eiusmod id est laborum sunt ex ea aute adipisicing ad magna deserunt duis. Nostrud velit dolore id commodo\n          quis enim fugiat. Sint non quis consectetur voluptate aliqua dolore ad voluptate nulla. Irure sit\n          reprehenderit sint laboris non elit. Duis minim nisi esse dolor. Sit ex in consequat non occaecat commodo\n          irure et. Commodo qui ipsum Lorem magna consequat consequat et minim eiusmod Lorem eiusmod cupidatat\n          voluptate.\n        </p>\n      </article>\n    </>\n  )\n}\n\nArticle.layout = (page) => <Layout children={page} />\n\nexport default Article\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/Async.tsx",
    "content": "import { Head } from '@inertiajs/react'\nimport Layout from '../Components/Layout'\n\nconst Async = ({\n  sleep,\n  jonathan,\n  taylor,\n  joe,\n}: {\n  sleep?: boolean\n  jonathan?: boolean\n  taylor?: boolean\n  joe?: boolean\n}) => {\n  return (\n    <>\n      <Head title=\"Async\" />\n      <h1 className=\"text-3xl\">Async</h1>\n      <div className=\"mt-6 rounded-sm border border-yellow-500 bg-yellow-200 p-4\">\n        <p>Page is loaded!</p>\n      </div>\n\n      <div className=\"mt-6 flex space-x-6\">\n        <div className=\"w-1/2 rounded-sm border border-gray-200 p-4\">\n          <p>Sleep: {sleep ? 'Yes' : 'No'}</p>\n        </div>\n\n        <div className=\"w-1/2 rounded-sm border border-gray-200 p-4\">\n          <p>Jonathan: {jonathan ? 'Yes' : 'No'}</p>\n        </div>\n\n        <div className=\"w-1/2 rounded-sm border border-gray-200 p-4\">\n          <p>Taylor: {taylor ? 'Yes' : 'No'}</p>\n        </div>\n\n        <div className=\"w-1/2 rounded-sm border border-gray-200 p-4\">\n          <p>Joe: {joe ? 'Yes' : 'No'}</p>\n        </div>\n      </div>\n    </>\n  )\n}\n\nAsync.layout = (page) => <Layout children={page} />\n\nexport default Async\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/Chat.tsx",
    "content": "import { Head, InfiniteScroll, router } from '@inertiajs/react'\nimport { useStream } from '@laravel/stream-react'\nimport { FormEvent, useMemo, useRef, useState } from 'react'\nimport Layout from '../Components/Layout'\nimport MessageComponent, { Message } from '../Components/Message'\nimport PaperAirplaneIcon from '../Components/PaperAirplaneIcon'\nimport Spinner from '../Components/Spinner'\nimport StreamingIndicator from '../Components/StreamingIndicator'\nimport Textarea from '../Components/Textarea'\n\nconst Chat = ({\n  messages = { data: [] },\n}: {\n  messages?: {\n    data: Message[]\n  }\n}) => {\n  const [newPrompt, setNewPrompt] = useState('')\n  const [pendingResponse, setPendingResponse] = useState('')\n  const [requestCount, setRequestCount] = useState(0)\n  const scrollContainer = useRef<HTMLDivElement>(null)\n\n  const { isFetching, isStreaming, send } = useStream('messages', {\n    csrfToken: document.querySelector('meta[name=\"csrf-token\"]')?.getAttribute('content') as string,\n    onData: (data) => setPendingResponse((prev) => prev + data),\n    onFinish: () => {\n      router.prependToProp('messages.data', {\n        id: Date.now(),\n        content: pendingResponse,\n        type: 'response',\n      })\n\n      setPendingResponse('')\n    },\n  })\n\n  const canSendPrompt = !!newPrompt.trim() && !isFetching && !isStreaming\n\n  const sendMessage = (e: FormEvent) => {\n    e.preventDefault()\n\n    if (!canSendPrompt) {\n      return\n    }\n\n    setRequestCount((prev) => prev + 1)\n\n    router.prependToProp(\n      'messages.data',\n      {\n        id: Date.now(),\n        content: newPrompt,\n        type: 'prompt',\n      },\n      {\n        onSuccess: () => {\n          setTimeout(() => {\n            scrollContainer.current?.scrollTo({\n              top: scrollContainer.current.scrollHeight,\n              behavior: 'smooth',\n            })\n          })\n\n          send({ message: newPrompt })\n\n          setNewPrompt('')\n        },\n      },\n    )\n  }\n\n  const reversedMessages = useMemo(() => {\n    const msgs = [...messages.data].reverse()\n\n    if (pendingResponse) {\n      msgs.push({\n        id: 'pending',\n        content: pendingResponse,\n        type: 'response',\n      })\n    }\n\n    return msgs\n  }, [messages.data, pendingResponse])\n\n  const isLastMessage = (message: Message) => {\n    return message === reversedMessages[reversedMessages.length - 1]\n  }\n\n  return (\n    <>\n      <Head title=\"Chat\" />\n\n      <div className=\"relative flex h-[calc(100vh-80px)] flex-col bg-gray-50\">\n        <div ref={scrollContainer} className=\"h-full flex-1 overflow-y-auto\">\n          <InfiniteScroll\n            reverse\n            data=\"messages\"\n            className=\"mx-auto grid max-w-3xl gap-6 px-8 py-16\"\n            loading={({ loadingNext }) => (\n              <div className={`flex justify-center ${loadingNext ? 'pt-16' : 'pb-16'}`}>\n                <Spinner className=\"size-6 text-gray-400\" />\n              </div>\n            )}\n          >\n            {reversedMessages.map((message) => (\n              <div\n                key={message.id}\n                className={isLastMessage(message) && requestCount > 0 ? 'min-h-[calc(100vh-80px-131px-64px)]' : ''}\n              >\n                <MessageComponent message={message} />\n                {isLastMessage(message) && isFetching && <StreamingIndicator className=\"mt-6\" />}\n              </div>\n            ))}\n          </InfiniteScroll>\n        </div>\n\n        <div className=\"sticky bottom-0 border-t border-gray-200 bg-white px-8 py-6\">\n          <form\n            onSubmit={sendMessage}\n            className=\"relative mx-auto flex max-w-3xl items-end rounded-xl border border-gray-300 bg-white px-4 py-3 shadow-sm transition-colors focus-within:border-gray-400\"\n          >\n            <Textarea\n              value={newPrompt}\n              onChange={setNewPrompt}\n              placeholder=\"Type your message...\"\n              onKeyDown={(e) => {\n                if (e.key === 'Enter' && !e.shiftKey) {\n                  e.preventDefault()\n                  sendMessage(e as any)\n                } else if (e.key === 'Enter' && e.shiftKey) {\n                  e.preventDefault()\n                  setNewPrompt((prev) => prev + '\\n')\n                }\n              }}\n            />\n\n            <button\n              type=\"submit\"\n              disabled={!canSendPrompt}\n              className=\"ml-3 flex size-8 items-center justify-center rounded-lg bg-gray-800 disabled:cursor-not-allowed disabled:opacity-50\"\n            >\n              {isFetching || isStreaming ? (\n                <Spinner className=\"size-4 text-white\" />\n              ) : (\n                <PaperAirplaneIcon className=\"size-4 rotate-270 text-white\" />\n              )}\n            </button>\n          </form>\n        </div>\n      </div>\n    </>\n  )\n}\n\nChat.layout = (page: React.ReactElement) => <Layout padding={false}>{page}</Layout>\n\nexport default Chat\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/DataTable.tsx",
    "content": "import { Head, InfiniteScroll } from '@inertiajs/react'\nimport Layout from '../Components/Layout'\nimport Spinner from '../Components/Spinner'\n\nconst DataTable = ({\n  users,\n}: {\n  users: {\n    data: {\n      id: number\n      name: string\n    }[]\n  }\n}) => {\n  return (\n    <>\n      <Head title=\"Data Table\" />\n\n      <InfiniteScroll\n        loading={\n          <div className=\"flex justify-center py-16\">\n            <Spinner className=\"size-6 text-gray-400\" />\n          </div>\n        }\n        data=\"users\"\n        className=\"mx-auto max-w-7xl px-8\"\n        buffer={3000}\n        itemsElement=\"tbody\"\n      >\n        <div className=\"overflow-hidden rounded-2xl shadow ring-1 ring-gray-200\">\n          <table className=\"min-w-full\">\n            <thead className=\"bg-gray-50\">\n              <tr>\n                <th className=\"px-6 py-4 text-left text-sm font-semibold text-gray-900\">ID</th>\n                <th className=\"px-6 py-4 text-left text-sm font-semibold text-gray-900\">Name</th>\n              </tr>\n            </thead>\n            <tbody className=\"divide-y divide-gray-200 bg-white\">\n              {users.data.map((user) => (\n                <tr key={user.id} className=\"transition-colors hover:bg-gray-50\">\n                  <td className=\"px-6 py-4 text-sm text-gray-700\">{user.id}</td>\n                  <td className=\"px-6 py-4 text-sm text-gray-700\">{user.name}</td>\n                </tr>\n              ))}\n            </tbody>\n          </table>\n        </div>\n      </InfiniteScroll>\n    </>\n  )\n}\n\nDataTable.layout = (page: React.ReactElement) => <Layout>{page}</Layout>\n\nexport default DataTable\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/Defer.tsx",
    "content": "import { Deferred, Head } from '@inertiajs/react'\nimport DeferredUsers from '../Components/DeferredUsers'\nimport Layout from '../Components/Layout'\n\nconst Defer = ({\n  users,\n  foods,\n  organizations,\n}: {\n  users?: {\n    id: number\n    name: string\n    email: string\n  }[]\n  organizations?: {\n    id: number\n    name: string\n    url: string\n  }[]\n  foods?: {\n    id: number\n    name: string\n  }[]\n}) => {\n  return (\n    <>\n      <Head title=\"Form\" />\n      <h1 className=\"text-3xl\">Defer</h1>\n      <div className=\"mt-6 rounded-sm border border-yellow-500 bg-yellow-200 p-4\">\n        <p>Page is loaded!</p>\n      </div>\n\n      <div className=\"mt-6 flex space-x-6\">\n        <div className=\"w-1/2 rounded-sm border border-gray-200 p-4\">\n          <Deferred data=\"users\" fallback={<p>Loading Users...</p>}>\n            <DeferredUsers />\n          </Deferred>\n        </div>\n\n        <div className=\"w-1/2 rounded-sm border border-gray-200 p-4\">\n          {/* <Suspense fallback={<p>Loading Food...</p>}>\n            <DeferredFood />\n          </Suspense> */}\n        </div>\n\n        <div className=\"w-1/2 rounded-sm border border-gray-200 p-4\">\n          {/* <Suspense fallback={<p>Loading Organizations...</p>}>\n            <DeferredOrganizations />\n          </Suspense> */}\n        </div>\n      </div>\n    </>\n  )\n}\n\nDefer.layout = (page) => <Layout children={page} />\n\nexport default Defer\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/Flash.tsx",
    "content": "import { Head, Link, router, usePage } from '@inertiajs/react'\nimport { useEffect, useState } from 'react'\nimport Layout from '../Components/Layout'\n\nconst Flash = () => {\n  const { flash } = usePage()\n  const [flashLog, setFlashLog] = useState<Record<string, unknown>[]>([])\n\n  useEffect(() => {\n    return router.on('flash', ({ detail: { flash } }) => {\n      setFlashLog((prev) => [...prev, flash])\n    })\n  }, [])\n\n  const triggerFrontendFlash = () => {\n    router.flash('message', 'Hello from the frontend!')\n  }\n\n  const triggerMultipleFlash = () => {\n    router.flash({\n      message: 'Multiple items',\n      count: 42,\n    })\n  }\n\n  const clearLog = () => {\n    setFlashLog([])\n  }\n\n  return (\n    <>\n      <Head title=\"Flash\" />\n      <h1 className=\"text-3xl\">Flash</h1>\n\n      <div className=\"mt-6 space-y-6\">\n        <div>\n          <h2 className=\"text-lg font-semibold\">Current page.flash</h2>\n          <pre className=\"mt-2 rounded-sm bg-gray-100 p-3 text-sm\">{JSON.stringify(flash ?? 'null', null, 2)}</pre>\n        </div>\n\n        <div>\n          <h2 className=\"text-lg font-semibold\">Flash Event Log</h2>\n          <pre className=\"mt-2 rounded-sm bg-gray-100 p-3 text-sm\">\n            {JSON.stringify(flashLog.length ? flashLog : 'No flash events yet', null, 2)}\n          </pre>\n          {flashLog.length > 0 && (\n            <button onClick={clearLog} className=\"mt-2 text-sm text-gray-500 underline\">\n              Clear log\n            </button>\n          )}\n        </div>\n\n        <div className=\"space-y-3\">\n          <h2 className=\"text-lg font-semibold\">Server-side Flash</h2>\n          <div>\n            <Link href=\"/flash/direct\" className=\"rounded-sm bg-slate-800 px-4 py-2 text-white\">\n              Flash with render\n            </Link>\n          </div>\n          <form\n            onSubmit={(e) => {\n              e.preventDefault()\n              router.post('/flash/form')\n            }}\n          >\n            <button type=\"submit\" className=\"rounded-sm bg-slate-800 px-4 py-2 text-white\">\n              Flash with redirect\n            </button>\n          </form>\n        </div>\n\n        <div className=\"space-y-3\">\n          <h2 className=\"text-lg font-semibold\">Frontend Flash</h2>\n          <div className=\"flex gap-3\">\n            <button onClick={triggerFrontendFlash} className=\"rounded-sm bg-slate-800 px-4 py-2 text-white\">\n              router.flash(key, value)\n            </button>\n            <button onClick={triggerMultipleFlash} className=\"rounded-sm bg-slate-800 px-4 py-2 text-white\">\n              router.flash(object)\n            </button>\n          </div>\n        </div>\n      </div>\n    </>\n  )\n}\n\nFlash.layout = (page) => <Layout children={page} />\n\nexport default Flash\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/Form.tsx",
    "content": "import { Head, useForm } from '@inertiajs/react'\nimport Layout from '../Components/Layout'\n\nconst Form = () => {\n  const form = useForm('NewUser', {\n    name: '',\n    company: '',\n    role: '',\n  })\n\n  function submit(e) {\n    e.preventDefault()\n    form.post('/user')\n  }\n\n  return (\n    <>\n      <Head title=\"Form\" />\n      <h1 className=\"text-3xl\">Form</h1>\n      <form onSubmit={submit} className=\"mt-6 max-w-md space-y-4\">\n        {form.isDirty && (\n          <div className=\"my-5 rounded-sm border border-amber-100 bg-amber-50 p-3 text-amber-800\">\n            There are unsaved changes!\n          </div>\n        )}\n        <div>\n          <label className=\"block\" htmlFor=\"name\">\n            Name:\n          </label>\n          <input\n            type=\"text\"\n            value={form.data.name}\n            onChange={(e) => form.setData('name', e.target.value)}\n            id=\"name\"\n            className=\"mt-1 w-full appearance-none rounded-sm border border-gray-200 px-2 py-1 shadow-xs\"\n          />\n          {form.errors.name && <div className=\"mt-2 text-sm text-red-600\">{form.errors.name}</div>}\n        </div>\n        <div>\n          <label className=\"block\" htmlFor=\"company\">\n            Company:\n          </label>\n          <input\n            type=\"text\"\n            value={form.data.company}\n            onChange={(e) => form.setData('company', e.target.value)}\n            id=\"company\"\n            className=\"mt-1 w-full appearance-none rounded-sm border border-gray-200 px-2 py-1 shadow-xs\"\n          />\n          {form.errors.company && <div className=\"mt-2 text-sm text-red-600\">{form.errors.company}</div>}\n        </div>\n        <div>\n          <label className=\"block\" htmlFor=\"role\">\n            Role:\n          </label>\n          <select\n            value={form.data.role}\n            onChange={(e) => form.setData('role', e.target.value)}\n            id=\"role\"\n            className=\"mt-1 w-full appearance-none rounded-sm border border-gray-200 px-2 py-1 shadow-xs\"\n          >\n            <option></option>\n            <option>User</option>\n            <option>Admin</option>\n            <option>Super</option>\n          </select>\n          {form.errors.role && <div className=\"mt-2 text-sm text-red-600\">{form.errors.role}</div>}\n        </div>\n        <div className=\"flex gap-4\">\n          <button type=\"submit\" disabled={form.processing} className=\"rounded-sm bg-slate-800 px-6 py-2 text-white\">\n            Submit\n          </button>\n          <button type=\"button\" onClick={() => form.reset()}>\n            Reset\n          </button>\n        </div>\n      </form>\n    </>\n  )\n}\n\nForm.layout = (page) => <Layout children={page} />\n\nexport default Form\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/FormComponent.tsx",
    "content": "import { Form, Head } from '@inertiajs/react'\nimport { useState } from 'react'\nimport Layout from '../Components/Layout'\n\nconst FormComponent = () => {\n  const [customHeaders, setCustomHeaders] = useState({ 'X-Custom-Header': 'Demo-Value' })\n  const [errorBag, setErrorBag] = useState('custom-bag')\n\n  return (\n    <>\n      <Head title=\"Form Component\" />\n\n      <h1 className=\"text-3xl\">Form Component</h1>\n\n      <Form\n        action=\"/form-component\"\n        method=\"post\"\n        headers={customHeaders}\n        errorBag={errorBag}\n        options={{\n          only: ['foo'],\n          reset: ['bar'],\n        }}\n        transform={(data) => ({ ...data, demo: 'data' })}\n        className=\"mt-6 max-w-2xl space-y-6\"\n      >\n        {({\n          errors,\n          hasErrors,\n          processing,\n          progress,\n          wasSuccessful,\n          recentlySuccessful,\n          setError,\n          clearErrors,\n          isDirty,\n          reset,\n          submit,\n        }) => (\n          <>\n            <div className=\"rounded border border-gray-200 bg-gray-50 p-4\">\n              <h3 className=\"mb-3 text-lg font-medium\">Form Status (slot props)</h3>\n              <div className=\"grid grid-cols-2 gap-4 text-sm\">\n                <div>\n                  isDirty:{' '}\n                  <span className={`font-mono ${isDirty ? 'text-orange-600' : 'text-gray-500'}`}>\n                    {String(isDirty)}\n                  </span>\n                </div>\n                <div>\n                  hasErrors:{' '}\n                  <span className={`font-mono ${hasErrors ? 'text-red-600' : 'text-gray-500'}`}>\n                    {String(hasErrors)}\n                  </span>\n                </div>\n                <div>\n                  processing:{' '}\n                  <span className={`font-mono ${processing ? 'text-blue-600' : 'text-gray-500'}`}>\n                    {String(processing)}\n                  </span>\n                </div>\n                <div>\n                  wasSuccessful:{' '}\n                  <span className={`font-mono ${wasSuccessful ? 'text-green-600' : 'text-gray-500'}`}>\n                    {String(wasSuccessful)}\n                  </span>\n                </div>\n                <div>\n                  recentlySuccessful:{' '}\n                  <span className={`font-mono ${recentlySuccessful ? 'text-green-600' : 'text-gray-500'}`}>\n                    {String(recentlySuccessful)}\n                  </span>\n                </div>\n                {progress && (\n                  <div>\n                    progress: <span className=\"font-mono text-blue-600\">{Math.round(progress.percentage)}%</span>\n                  </div>\n                )}\n              </div>\n            </div>\n\n            {isDirty && (\n              <div className=\"rounded border border-amber-100 bg-amber-50 p-3 text-amber-800\">\n                There are unsaved changes!\n              </div>\n            )}\n\n            <div className=\"space-y-4\">\n              <div>\n                <label className=\"block font-medium\" htmlFor=\"name\">\n                  Name\n                </label>\n                <input\n                  type=\"text\"\n                  name=\"name\"\n                  id=\"name\"\n                  placeholder=\"Enter your name\"\n                  className={`mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm ${errors.name ? 'border-red-500' : ''}`}\n                />\n                {errors.name && <div className=\"mt-1 text-sm text-red-600\">{errors.name}</div>}\n              </div>\n\n              <div>\n                <label className=\"block font-medium\" htmlFor=\"avatar\">\n                  Avatar\n                </label>\n                <input\n                  type=\"file\"\n                  name=\"avatar\"\n                  id=\"avatar\"\n                  className=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n                />\n                {errors.avatar && <div className=\"mt-1 text-sm text-red-600\">{errors.avatar}</div>}\n              </div>\n\n              <div>\n                <label className=\"block font-medium\" htmlFor=\"skills\">\n                  Skills (Multiple)\n                </label>\n                <select\n                  name=\"skills[]\"\n                  id=\"skills\"\n                  multiple\n                  className=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n                  defaultValue={[]}\n                >\n                  <option value=\"vue\">Vue.js</option>\n                  <option value=\"react\">React</option>\n                  <option value=\"laravel\">Laravel</option>\n                  <option value=\"tailwind\">Tailwind CSS</option>\n                </select>\n                {errors.skills && <div className=\"mt-1 text-sm text-red-600\">{errors.skills}</div>}\n              </div>\n\n              <div>\n                <label className=\"block font-medium\">Tags</label>\n                <div className=\"mt-1 space-y-2\">\n                  <input\n                    type=\"text\"\n                    name=\"tags[]\"\n                    placeholder=\"Tag 1\"\n                    className=\"w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n                  />\n                  {errors['tags.0'] && <div className=\"text-sm text-red-600\">{errors['tags.0']}</div>}\n                  <input\n                    type=\"text\"\n                    name=\"tags[]\"\n                    placeholder=\"Tag 2\"\n                    className=\"w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n                  />\n                  {errors['tags.1'] && <div className=\"text-sm text-red-600\">{errors['tags.1']}</div>}\n                </div>\n              </div>\n\n              <div>\n                <label className=\"block font-medium\">Address</label>\n                <div className=\"mt-1 grid grid-cols-2 gap-2\">\n                  <input\n                    type=\"text\"\n                    name=\"user[address][street]\"\n                    placeholder=\"Street\"\n                    className=\"appearance-none rounded border px-2 py-1 shadow-sm\"\n                  />\n                  <input\n                    type=\"text\"\n                    name=\"user[address][city]\"\n                    placeholder=\"City\"\n                    className=\"appearance-none rounded border px-2 py-1 shadow-sm\"\n                  />\n                </div>\n              </div>\n            </div>\n\n            <div className=\"flex flex-wrap gap-2\">\n              <button\n                type=\"submit\"\n                disabled={processing}\n                className=\"rounded bg-slate-800 px-4 py-2 text-white disabled:opacity-50\"\n              >\n                Submit\n              </button>\n\n              <button type=\"button\" onClick={reset} className=\"rounded bg-gray-500 px-4 py-2 text-white\">\n                Reset\n              </button>\n\n              <button\n                type=\"button\"\n                onClick={() => setError({ name: 'Name is required', avatar: 'Please select a file' })}\n                className=\"rounded bg-red-500 px-4 py-2 text-white\"\n              >\n                Set Errors\n              </button>\n\n              <button type=\"button\" onClick={() => clearErrors()} className=\"rounded bg-green-500 px-4 py-2 text-white\">\n                Clear Errors\n              </button>\n            </div>\n          </>\n        )}\n      </Form>\n\n      <div className=\"mt-8 max-w-2xl space-y-4\">\n        <h2 className=\"text-2xl\">Form Configuration</h2>\n\n        <div className=\"grid grid-cols-1 gap-6 md:grid-cols-2\">\n          <div className=\"space-y-1 rounded border border-gray-200 bg-gray-50 p-4 text-sm\">\n            <div>\n              <strong>Headers:</strong> <code className=\"text-xs\">{JSON.stringify(customHeaders)}</code>\n            </div>\n            <div>\n              <strong>Error Bag:</strong> <code>{errorBag}</code>\n            </div>\n            <div>\n              <strong>Only:</strong> <code>['foo']</code>\n            </div>\n            <div>\n              <strong>Reset:</strong> <code>['bar']</code>\n            </div>\n            <div>\n              <strong>Method:</strong> <code>POST</code>\n            </div>\n          </div>\n\n          <div className=\"space-y-3\">\n            <div>\n              <label className=\"block text-sm font-medium\">Error Bag</label>\n              <input\n                type=\"text\"\n                value={errorBag}\n                onChange={(e) => setErrorBag(e.target.value)}\n                className=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n                placeholder=\"Error bag name\"\n              />\n            </div>\n\n            <div>\n              <label className=\"block text-sm font-medium\">Custom Header Value</label>\n              <input\n                type=\"text\"\n                value={customHeaders['X-Custom-Header']}\n                onChange={(e) => setCustomHeaders({ 'X-Custom-Header': e.target.value })}\n                className=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n                placeholder=\"Header value\"\n              />\n            </div>\n          </div>\n        </div>\n      </div>\n    </>\n  )\n}\n\nFormComponent.layout = (page) => <Layout children={page} />\n\nexport default FormComponent\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/FormComponentPrecognition.tsx",
    "content": "import { FormComponentMethods } from '@inertiajs/core'\nimport { Form, Head } from '@inertiajs/react'\nimport { useState } from 'react'\nimport Layout from '../Components/Layout'\n\nconst FormComponentPrecognition = () => {\n  const [validateFiles, setValidateFiles] = useState(false)\n  const [validationTimeout, setValidationTimeout] = useState(1500)\n\n  const [callbacks, setCallbacks] = useState({\n    success: false,\n    error: false,\n    finish: false,\n  })\n\n  const validateWithCallbacks = (validate: FormComponentMethods['validate']) => {\n    setCallbacks({ success: false, error: false, finish: false })\n\n    validate({\n      onPrecognitionSuccess: () => setCallbacks((prev) => ({ ...prev, success: true })),\n      onValidationError: () => setCallbacks((prev) => ({ ...prev, error: true })),\n      onFinish: () => setCallbacks((prev) => ({ ...prev, finish: true })),\n      onBeforeValidation: (newReq) => {\n        if (newReq.data?.name === 'block') {\n          alert('Validation blocked by onBeforeValidation!')\n          return false\n        }\n      },\n    })\n  }\n\n  return (\n    <>\n      <Head title=\"Form Component Precognition\" />\n      <h1 className=\"text-3xl\">Form Component Precognition</h1>\n\n      <Form\n        action=\"/form-component/precognition\"\n        method=\"post\"\n        validateFiles={validateFiles}\n        validationTimeout={validationTimeout}\n        className=\"mt-6 max-w-2xl space-y-6\"\n      >\n        {({ errors, invalid, valid, validate, validating, touch, touched, processing }) => (\n          <>\n            {/* Status Display */}\n            <div className=\"rounded border border-gray-200 bg-gray-50 p-4\">\n              <h3 className=\"mb-3 text-lg font-medium\">Validation Status (slot props)</h3>\n              <div className=\"grid grid-cols-2 gap-4 text-sm\">\n                <div>\n                  validating:{' '}\n                  <span className={`font-mono ${validating ? 'text-blue-600' : 'text-gray-500'}`}>\n                    {String(validating)}\n                  </span>\n                </div>\n                <div>\n                  processing:{' '}\n                  <span className={`font-mono ${processing ? 'text-blue-600' : 'text-gray-500'}`}>\n                    {String(processing)}\n                  </span>\n                </div>\n                <div>\n                  touched():{' '}\n                  <span className={`font-mono ${touched() ? 'text-orange-600' : 'text-gray-500'}`}>\n                    {String(touched())}\n                  </span>\n                </div>\n                <div>\n                  touched('name'):{' '}\n                  <span className={`font-mono ${touched('name') ? 'text-orange-600' : 'text-gray-500'}`}>\n                    {String(touched('name'))}\n                  </span>\n                </div>\n                <div>\n                  touched('email'):{' '}\n                  <span className={`font-mono ${touched('email') ? 'text-orange-600' : 'text-gray-500'}`}>\n                    {String(touched('email'))}\n                  </span>\n                </div>\n              </div>\n            </div>\n\n            {/* Form Fields */}\n            <div className=\"space-y-4\">\n              {/* Name Input */}\n              <div>\n                <label className=\"block font-medium\" htmlFor=\"name\">\n                  Name\n                </label>\n                <input\n                  type=\"text\"\n                  name=\"name\"\n                  id=\"name\"\n                  placeholder=\"Enter your name (min 3 chars)\"\n                  onBlur={() => validate('name')}\n                  className={`mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm ${\n                    invalid('name') ? 'border-red-500' : valid('name') ? 'border-green-500' : ''\n                  }`}\n                />\n                {invalid('name') && <div className=\"mt-1 text-sm text-red-600\">{errors.name}</div>}\n                {valid('name') && <div className=\"mt-1 text-sm text-green-600\">Valid!</div>}\n              </div>\n\n              {/* Email Input */}\n              <div>\n                <label className=\"block font-medium\" htmlFor=\"email\">\n                  Email\n                </label>\n                <input\n                  type=\"email\"\n                  name=\"email\"\n                  id=\"email\"\n                  placeholder=\"Enter your email\"\n                  onBlur={() => validate('email')}\n                  className={`mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm ${\n                    invalid('email') ? 'border-red-500' : valid('email') ? 'border-green-500' : ''\n                  }`}\n                />\n                {invalid('email') && <div className=\"mt-1 text-sm text-red-600\">{errors.email}</div>}\n                {valid('email') && <div className=\"mt-1 text-sm text-green-600\">Valid!</div>}\n              </div>\n\n              {/* File Input */}\n              <div>\n                <label className=\"block font-medium\" htmlFor=\"avatar\">\n                  Avatar\n                </label>\n                <input\n                  type=\"file\"\n                  name=\"avatar\"\n                  id=\"avatar\"\n                  onChange={() => validate('avatar')}\n                  className={`mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm ${\n                    invalid('avatar') ? 'border-red-500' : valid('avatar') ? 'border-green-500' : ''\n                  }`}\n                />\n                {invalid('avatar') && <div className=\"mt-1 text-sm text-red-600\">{errors.avatar}</div>}\n                {valid('avatar') && <div className=\"mt-1 text-sm text-green-600\">Valid!</div>}\n              </div>\n            </div>\n\n            {/* Action Buttons */}\n            <div className=\"flex flex-wrap gap-2\">\n              <button\n                type=\"submit\"\n                disabled={processing}\n                className=\"rounded bg-slate-800 px-4 py-2 text-white disabled:opacity-50\"\n              >\n                Submit\n              </button>\n\n              <button\n                type=\"button\"\n                onClick={() => validate()}\n                className=\"rounded border border-slate-300 px-4 py-2 hover:bg-slate-50\"\n              >\n                Validate Touched\n              </button>\n\n              <button\n                type=\"button\"\n                onClick={() => touch('name')}\n                className=\"rounded border border-slate-300 px-4 py-2 hover:bg-slate-50\"\n              >\n                Touch Name\n              </button>\n\n              <button\n                type=\"button\"\n                onClick={() => validateWithCallbacks(validate)}\n                className=\"rounded border border-slate-300 px-4 py-2 hover:bg-slate-50\"\n              >\n                Validate with Callbacks\n              </button>\n            </div>\n\n            {/* Callbacks Display */}\n            <div className=\"rounded border border-gray-200 bg-gray-50 p-4\">\n              <h3 className=\"mb-3 text-lg font-medium\">Validation Callbacks</h3>\n              <p className=\"mb-3 text-sm text-gray-600\">\n                Enter \"block\" in the name field to test onBeforeValidation blocking.\n              </p>\n              <div className=\"grid grid-cols-3 gap-4 text-sm\">\n                <div>\n                  onPrecognitionSuccess:{' '}\n                  <span className={`font-mono ${callbacks.success ? 'text-green-600' : 'text-gray-500'}`}>\n                    {String(callbacks.success)}\n                  </span>\n                </div>\n                <div>\n                  onValidationError:{' '}\n                  <span className={`font-mono ${callbacks.error ? 'text-red-600' : 'text-gray-500'}`}>\n                    {String(callbacks.error)}\n                  </span>\n                </div>\n                <div>\n                  onFinish:{' '}\n                  <span className={`font-mono ${callbacks.finish ? 'text-blue-600' : 'text-gray-500'}`}>\n                    {String(callbacks.finish)}\n                  </span>\n                </div>\n              </div>\n            </div>\n          </>\n        )}\n      </Form>\n\n      {/* Configuration */}\n      <div className=\"mt-8 max-w-2xl space-y-4\">\n        <h2 className=\"text-2xl\">Configuration</h2>\n\n        <div className=\"grid grid-cols-1 gap-6 md:grid-cols-2\">\n          <div className=\"rounded border border-gray-200 bg-gray-50 p-4\">\n            <div className=\"space-y-1 text-sm\">\n              <div>\n                <strong>Validate Files:</strong> <code>{String(validateFiles)}</code>\n              </div>\n              <div>\n                <strong>Validation Timeout:</strong> <code>{validationTimeout}ms</code>\n              </div>\n              <div>\n                <strong>Method:</strong> <code>POST</code>\n              </div>\n            </div>\n          </div>\n\n          <div className=\"space-y-3\">\n            <div>\n              <label className=\"flex items-center gap-2\">\n                <input\n                  type=\"checkbox\"\n                  checked={validateFiles}\n                  onChange={(e) => setValidateFiles(e.target.checked)}\n                  className=\"rounded\"\n                />\n                <span className=\"text-sm\">Enable file validation</span>\n              </label>\n            </div>\n\n            <div>\n              <label className=\"block text-sm font-medium\">Validation Timeout</label>\n              <select\n                value={validationTimeout}\n                onChange={(e) => setValidationTimeout(Number(e.target.value))}\n                className=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n              >\n                <option value={500}>500ms</option>\n                <option value={1000}>1000ms</option>\n                <option value={1500}>1500ms</option>\n                <option value={2000}>2000ms</option>\n              </select>\n            </div>\n          </div>\n        </div>\n      </div>\n    </>\n  )\n}\n\nFormComponentPrecognition.layout = (page) => <Layout children={page} />\n\nexport default FormComponentPrecognition\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/Home.tsx",
    "content": "import { Head, Link } from '@inertiajs/react'\nimport Layout from '../Components/Layout'\n\nconst Home = () => {\n  return (\n    <>\n      <Head title=\"Home\" />\n      <h1 className=\"text-3xl\">Home</h1>\n      <p className=\"mt-6\">\n        <Link href=\"/article#far-down\" className=\"text-blue-700 underline\">\n          Link to bottom of article page\n        </Link>\n      </p>\n    </>\n  )\n}\n\nHome.layout = (page) => <Layout children={page} />\n\nexport default Home\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/Login.tsx",
    "content": "import { Head } from '@inertiajs/react'\nimport Layout from '../Components/Layout'\n\nconst Login = () => {\n  return (\n    <>\n      <Head title=\"Login\" />\n      <h1 className=\"text-3xl\">Login</h1>\n      <p className=\"mt-6\">\n        You made a <code>POST</code> request to the logout endpoint and were redirected to the login page.\n      </p>\n    </>\n  )\n}\n\nLogin.layout = (page) => <Layout children={page} />\n\nexport default Login\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/Once/First.tsx",
    "content": "import { Head } from '@inertiajs/react'\nimport Layout from './Layout'\n\nconst First = ({ foo, bar, baz1, qux }: { foo: string; bar: string; baz1: string; qux?: string }) => {\n  return (\n    <>\n      <Head title=\"Once Props: First Page\" />\n      <h1 className=\"text-3xl\">Once Props: First Page</h1>\n      <p>Foo: {foo}</p>\n      <p>Bar: {bar}</p>\n      <p>Baz: {baz1}</p>\n      <p>Qux: {qux ?? 'Loading...'}</p>\n    </>\n  )\n}\n\nFirst.layout = (page: React.ReactNode) => <Layout children={page} />\n\nexport default First\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/Once/Fourth.tsx",
    "content": "import { Head } from '@inertiajs/react'\nimport Layout from './Layout'\n\nconst Fourth = ({ foo, bar, baz4, qux }: { foo: string; bar: string; baz4: string; qux?: string }) => {\n  return (\n    <>\n      <Head title=\"Once Props: Fourth Page\" />\n      <h1 className=\"text-3xl\">Once Props: Fourth Page</h1>\n      <p>Foo: {foo}</p>\n      <p>Bar: {bar}</p>\n      <p>Baz: {baz4}</p>\n      <p>Qux: {qux ?? 'Loading...'}</p>\n    </>\n  )\n}\n\nFourth.layout = (page: React.ReactNode) => <Layout children={page} />\n\nexport default Fourth\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/Once/Layout.tsx",
    "content": "import { Link, router } from '@inertiajs/react'\nimport MainLayout from '../../Components/Layout'\n\nexport default function Layout({ children }: { children: React.ReactNode }) {\n  return (\n    <MainLayout>\n      {children}\n      <Link href=\"/once/1\" className=\"text-blue-500 underline\">\n        Go to First Page\n      </Link>\n      <Link href=\"/once/2\" className=\"ml-4 text-blue-500 underline\">\n        Go to Second Page\n      </Link>\n      <Link href=\"/once/3\" className=\"ml-4 text-blue-500 underline\">\n        Go to Third Page\n      </Link>\n      <Link href=\"/once/4\" className=\"ml-4 text-blue-500 underline\" prefetch=\"mount\">\n        Go to Fourth Page\n      </Link>\n      <button onClick={() => router.reload({ only: ['foo'] })} className=\"ml-4 text-blue-500 underline\">\n        Reload Foo\n      </button>\n      <button onClick={() => router.reload({ only: ['bar'] })} className=\"ml-4 text-blue-500 underline\">\n        Reload Bar\n      </button>\n      <button\n        onClick={() => router.reload({ only: ['baz1', 'baz2', 'baz3', 'baz4'] })}\n        className=\"ml-4 text-blue-500 underline\"\n      >\n        Reload Baz\n      </button>\n      <button onClick={() => router.reload({ only: ['qux'] })} className=\"ml-4 text-blue-500 underline\">\n        Reload Qux\n      </button>\n    </MainLayout>\n  )\n}\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/Once/Second.tsx",
    "content": "import { Head } from '@inertiajs/react'\nimport Layout from './Layout'\n\nconst Second = ({ foo, bar, baz2, qux }: { foo: string; bar: string; baz2: string; qux?: string }) => {\n  return (\n    <>\n      <Head title=\"Once Props: Second Page\" />\n      <h1 className=\"text-3xl\">Once Props: Second Page</h1>\n      <p>Foo: {foo}</p>\n      <p>Bar: {bar}</p>\n      <p>Baz: {baz2}</p>\n      <p>Qux: {qux ?? 'Loading...'}</p>\n    </>\n  )\n}\n\nSecond.layout = (page: React.ReactNode) => <Layout children={page} />\n\nexport default Second\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/Once/Third.tsx",
    "content": "import { Head } from '@inertiajs/react'\nimport Layout from './Layout'\n\nconst Third = ({ foo, bar, baz3, qux }: { foo: string; bar: string; baz3: string; qux?: string }) => {\n  return (\n    <>\n      <Head title=\"Once Props: Third Page\" />\n      <h1 className=\"text-3xl\">Once Props: Third Page</h1>\n      <p>Foo: {foo}</p>\n      <p>Bar: {bar}</p>\n      <p>Baz: {baz3}</p>\n      <p>Qux: {qux ?? 'Loading...'}</p>\n    </>\n  )\n}\n\nThird.layout = (page: React.ReactNode) => <Layout children={page} />\n\nexport default Third\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/PhotoGrid.tsx",
    "content": "import { Head, InfiniteScroll } from '@inertiajs/react'\nimport Image from '../Components/Image'\nimport Layout from '../Components/Layout'\nimport Spinner from '../Components/Spinner'\n\nconst PhotoGrid = ({\n  photos,\n}: {\n  photos: {\n    data: {\n      id: number\n      url: string\n    }[]\n  }\n}) => {\n  return (\n    <>\n      <Head title=\"Photo Grid\" />\n\n      <InfiniteScroll\n        data=\"photos\"\n        className=\"mx-auto grid max-w-7xl grid-cols-1 gap-6 px-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\"\n        buffer={1000}\n        loading={\n          <div className=\"flex justify-center py-16\">\n            <Spinner className=\"size-6 text-gray-400\" />\n          </div>\n        }\n      >\n        {photos.data.map((photo) => (\n          <Image key={photo.id} id={photo.id} url={photo.url} />\n        ))}\n      </InfiniteScroll>\n    </>\n  )\n}\n\nPhotoGrid.layout = (page: React.ReactElement) => <Layout>{page}</Layout>\n\nexport default PhotoGrid\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/PhotoHorizontal.tsx",
    "content": "import { Head, InfiniteScroll } from '@inertiajs/react'\nimport Image from '../Components/Image'\nimport Layout from '../Components/Layout'\nimport Spinner from '../Components/Spinner'\n\nconst PhotoHorizontal = ({\n  photos,\n}: {\n  photos: {\n    data: {\n      id: number\n      url: string\n    }[]\n  }\n}) => {\n  return (\n    <>\n      <Head title=\"Photo Grid (Horizontal)\" />\n\n      <div className=\"flex h-[200px] w-full overflow-x-scroll\">\n        <InfiniteScroll\n          data=\"photos\"\n          buffer={1000}\n          className=\"flex h-[200px] gap-6\"\n          preserveUrl\n          onlyNext\n          loading={\n            <div className=\"flex size-[200px] items-center justify-center\">\n              <Spinner className=\"size-6 text-gray-400\" />\n            </div>\n          }\n        >\n          {photos.data.map((photo) => (\n            <Image key={photo.id} id={photo.id} url={photo.url} />\n          ))}\n        </InfiniteScroll>\n      </div>\n    </>\n  )\n}\n\nPhotoHorizontal.layout = (page: React.ReactElement) => <Layout>{page}</Layout>\n\nexport default PhotoHorizontal\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/Poll.tsx",
    "content": "import { Head, router } from '@inertiajs/react'\nimport { useEffect, useState } from 'react'\nimport Layout from '../Components/Layout'\nimport TestGrid from '../Components/TestGrid'\nimport TestGridItem from '../Components/TestGridItem'\n\nconst Poll = ({ users, companies }) => {\n  const [userPollCount, setUserPollCount] = useState(0)\n  const [hookPollCount, setHookPollCount] = useState(0)\n  const [companyPollCount, setCompanyPollCount] = useState(0)\n\n  const triggerAsyncRedirect = () => {\n    router.get(\n      '/elsewhere',\n      {},\n      {\n        only: ['something'],\n        async: true,\n      },\n    )\n  }\n\n  useEffect(() => {\n    const startHookPolling = () => {\n      const interval = setInterval(() => {\n        setHookPollCount((prev) => prev + 1)\n      }, 2000)\n      return () => clearInterval(interval)\n    }\n\n    const stopUserPolling = () => {\n      const interval = setInterval(() => {\n        setUserPollCount((prev) => prev + 1)\n      }, 1000)\n      setTimeout(() => {\n        clearInterval(interval)\n        console.log('stopping user polling')\n      }, 3000)\n    }\n\n    setTimeout(() => {\n      startHookPolling()\n    }, 2000)\n\n    stopUserPolling()\n  }, [])\n\n  return (\n    <>\n      <Head title=\"Async Request\" />\n      <h1 className=\"text-3xl\">Poll</h1>\n      <TestGrid>\n        <TestGridItem>\n          <div>User Poll Request Count: {userPollCount}</div>\n          {users.map((user, index) => (\n            <div key={index}>{user}</div>\n          ))}\n        </TestGridItem>\n        <TestGridItem>\n          <div>Companies Poll Request Count: {companyPollCount}</div>\n          {companies.map((company, index) => (\n            <div key={index}>{company}</div>\n          ))}\n        </TestGridItem>\n        <TestGridItem>\n          <div>Hook Poll Request Count: {hookPollCount}</div>\n        </TestGridItem>\n        <TestGridItem>\n          <button onClick={triggerAsyncRedirect}>Trigger Async Redirect</button>\n        </TestGridItem>\n      </TestGrid>\n    </>\n  )\n}\n\nPoll.layout = (page) => <Layout children={page} />\n\nexport default Poll\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/User.tsx",
    "content": "import { Head } from '@inertiajs/react'\nimport Layout from '../Components/Layout'\n\nconst User = ({ user }) => {\n  return (\n    <>\n      <Head title=\"User\" />\n      <h1 className=\"text-3xl\">User</h1>\n      <p className=\"mt-6\">You successfully created a new user! Well not really, there is no persistence in this app.</p>\n      <ul className=\"mt-6 space-y-2\">\n        <li>\n          <strong>Name:</strong> {user.name}\n        </li>\n        <li>\n          <strong>Company:</strong> {user.company}\n        </li>\n        <li>\n          <strong>Role:</strong> {user.role}\n        </li>\n      </ul>\n    </>\n  )\n}\n\nUser.layout = (page) => <Layout children={page} />\n\nexport default User\n"
  },
  {
    "path": "playgrounds/react/resources/js/Pages/Users.tsx",
    "content": "import { Head } from '@inertiajs/react'\nimport Layout from '../Components/Layout'\n\nconst Users = ({ users }) => {\n  return (\n    <>\n      <Head title=\"Users\" />\n      <h1 className=\"text-3xl\">Users</h1>\n      <div className=\"mt-6 w-full max-w-2xl overflow-hidden rounded-sm border border-gray-200 shadow-xs\">\n        <table className=\"w-full text-left\">\n          <thead>\n            <tr>\n              <th className=\"px-4 py-2\">Id</th>\n              <th className=\"px-4 py-2\">Name</th>\n              <th className=\"px-4 py-2\">Email</th>\n            </tr>\n          </thead>\n          <tbody>\n            {users.map((user) => (\n              <tr key={user.id} className=\"border-t border-gray-200\">\n                <td className=\"px-4 py-2\">{user.id}</td>\n                <td className=\"px-4 py-2\">{user.name}</td>\n                <td className=\"px-4 py-2\">{user.email}</td>\n              </tr>\n            ))}\n          </tbody>\n        </table>\n      </div>\n    </>\n  )\n}\n\nUsers.layout = (page) => <Layout children={page} />\n\nexport default Users\n"
  },
  {
    "path": "playgrounds/react/resources/js/app.tsx",
    "content": "import { type ResolvedComponent, createInertiaApp } from '@inertiajs/react'\nimport { hydrateRoot } from 'react-dom/client'\n\ncreateInertiaApp({\n  title: (title) => `${title} - React Playground`,\n  resolve: (name) => {\n    const pages = import.meta.glob<ResolvedComponent>('./Pages/**/*.tsx', { eager: true })\n    return pages[`./Pages/${name}.tsx`]\n  },\n  setup({ el, App, props }) {\n    hydrateRoot(el, <App {...props} />)\n    // createRoot(el).render(<App {...props} />)\n  },\n})\n"
  },
  {
    "path": "playgrounds/react/resources/js/ssr.tsx",
    "content": "import { type ResolvedComponent, createInertiaApp } from '@inertiajs/react'\nimport createServer from '@inertiajs/react/server'\nimport * as ReactDOMServer from 'react-dom/server'\n\ncreateServer((page) =>\n  createInertiaApp({\n    page,\n    render: ReactDOMServer.renderToString,\n    title: (title) => `${title} - React Playground`,\n    resolve: (name) => {\n      const pages = import.meta.glob<ResolvedComponent>('./Pages/**/*.tsx', { eager: true })\n      return pages[`./Pages/${name}.tsx`]\n    },\n    setup: ({ App, props }) => <App {...props} />,\n  }),\n)\n"
  },
  {
    "path": "playgrounds/react/resources/js/types/globals.d.ts",
    "content": "import '@inertiajs/core'\n\ndeclare module '@inertiajs/core' {\n  export interface InertiaConfig {\n    sharedPageProps: {\n      appName: string\n    }\n  }\n}\n"
  },
  {
    "path": "playgrounds/react/resources/js/vite.d.ts",
    "content": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "playgrounds/react/resources/views/app.blade.php",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\" />\n    <meta name=\"csrf-token\" content=\"{{ csrf_token() }}\">\n    @viteReactRefresh\n    @vite(['resources/css/app.css', 'resources/js/app.tsx'])\n    @inertiaHead\n  </head>\n  <body>\n    @inertia\n  </body>\n</html>\n"
  },
  {
    "path": "playgrounds/react/routes/api.php",
    "content": "<?php\n\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Route;\n\n/*\n|--------------------------------------------------------------------------\n| API Routes\n|--------------------------------------------------------------------------\n|\n| Here is where you can register API routes for your application. These\n| routes are loaded by the RouteServiceProvider within a group which\n| is assigned the \"api\" middleware group. Enjoy building your API!\n|\n*/\n\nRoute::middleware('auth:sanctum')->get('/user', function (Request $request) {\n    return $request->user();\n});\n"
  },
  {
    "path": "playgrounds/react/routes/channels.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Facades\\Broadcast;\n\n/*\n|--------------------------------------------------------------------------\n| Broadcast Channels\n|--------------------------------------------------------------------------\n|\n| Here you may register all of the event broadcasting channels that your\n| application supports. The given channel authorization callbacks are\n| used to check if an authenticated user can listen to the channel.\n|\n*/\n\nBroadcast::channel('App.Models.User.{id}', function ($user, $id) {\n    return (int) $user->id === (int) $id;\n});\n"
  },
  {
    "path": "playgrounds/react/routes/console.php",
    "content": "<?php\n\nuse Illuminate\\Foundation\\Inspiring;\nuse Illuminate\\Support\\Facades\\Artisan;\n\n/*\n|--------------------------------------------------------------------------\n| Console Routes\n|--------------------------------------------------------------------------\n|\n| This file is where you may define all of your Closure based console\n| commands. Each Closure is bound to a command instance allowing a\n| simple approach to interacting with each command's IO methods.\n|\n*/\n\nArtisan::command('inspire', function () {\n    $this->comment(Inspiring::quote());\n})->purpose('Display an inspiring quote');\n"
  },
  {
    "path": "playgrounds/react/routes/web.php",
    "content": "<?php\n\nuse App\\Http\\Requests\\PrecognitionFormRequest;\nuse App\\Models\\ChatMessage;\nuse Illuminate\\Foundation\\Http\\Middleware\\HandlePrecognitiveRequests;\nuse Illuminate\\Foundation\\Precognition;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Pagination\\LengthAwarePaginator;\nuse Illuminate\\Support\\Facades\\Cache;\nuse Illuminate\\Support\\Facades\\Route;\nuse Inertia\\Inertia;\nuse Prism\\Prism\\Enums\\Provider;\nuse Prism\\Prism\\Prism;\nuse Prism\\Prism\\ValueObjects\\Messages\\AssistantMessage;\nuse Prism\\Prism\\ValueObjects\\Messages\\UserMessage;\n\n/*\n|--------------------------------------------------------------------------\n| Web Routes\n|--------------------------------------------------------------------------\n|\n| Here is where you can register web routes for your application. These\n| routes are loaded by the RouteServiceProvider within a group which\n| contains the \"web\" middleware group. Now create something great!\n|\n*/\n\nRoute::get('/', function () {\n    return inertia('Home');\n});\n\nRoute::get('/users', function () {\n    return inertia('Users', [\n        'users' => [\n            [\n                'id' => 1,\n                'name' => 'Jonathan Reinink',\n                'email' => 'jonathan@example.com',\n            ],\n            [\n                'id' => 2,\n                'name' => 'Adam Wathan',\n                'email' => 'adam@example.com',\n            ],\n            [\n                'id' => 3,\n                'name' => 'Taylor Otwell',\n                'email' => 'taylor@example.com',\n            ],\n            [\n                'id' => 4,\n                'name' => 'Jordan Pittman',\n                'email' => 'jordan@example.com',\n            ],\n            [\n                'id' => 5,\n                'name' => 'Jess Archer',\n                'email' => 'jess@example.com',\n            ],\n            [\n                'id' => 6,\n                'name' => 'Claudio Dekker',\n                'email' => 'claudio@example.com',\n            ],\n            [\n                'id' => 7,\n                'name' => 'Sebastian De Deyne',\n                'email' => 'sebastian@example.com',\n            ],\n            [\n                'id' => 8,\n                'name' => 'Pedro Borges',\n                'email' => 'pedro@example.com',\n            ],\n        ],\n    ]);\n});\n\nRoute::get('/article', function () {\n    return inertia('Article');\n});\n\nRoute::get('/form', function () {\n    return inertia('Form');\n});\n\nRoute::get('/form-component', function () {\n    return inertia('FormComponent', [\n        'foo' => fn () => now()->getTimestampMs(),\n        'bar' => fn () => now()->getTimestampMs(),\n        'quux' => fn () => now()->getTimestampMs(),\n    ]);\n});\n\nRoute::post('/form-component', function () {\n    $data = request()->validateWithBag('custom-bag', [\n        'name' => ['required', 'string', 'max:255'],\n        'avatar' => ['nullable', 'file', 'image', 'max:2048'],\n        'skills' => ['nullable', 'array', 'min:2'],\n        'skills.*' => ['string', 'in:vue,react,laravel,tailwind'],\n        'tags' => ['nullable', 'array'],\n        'tags.*' => ['string', 'max:50'],\n        'user.address.street' => ['nullable', 'string', 'max:255'],\n        'user.address.city' => ['nullable', 'string', 'max:255'],\n    ]);\n\n    // Simulate file upload progress\n    if (request()->hasFile('avatar')) {\n        sleep(1);\n    }\n\n    return back();\n});\n\nRoute::get('/form-component/precognition', function () {\n    return inertia('FormComponentPrecognition');\n});\n\nRoute::post('/form-component/precognition', function (PrecognitionFormRequest $request) {\n    $data = $request->validated();\n\n    // dd($data);\n\n    return back();\n})->middleware([HandlePrecognitiveRequests::class]);\n\nRoute::post('/user', function () {\n    return inertia('User', [\n        'user' => request()->validate([\n            'name' => ['required'],\n            'company' => ['required'],\n            'role' => ['required', 'in:User,Admin,Super'],\n        ]),\n    ]);\n});\n\nRoute::get('/login', function () {\n    return inertia('Login');\n});\n\nRoute::post('/logout', function () {\n    return redirect('/login');\n});\n\nRoute::get('/async', function () {\n    return inertia('Async', [\n        'sleep' => Inertia::lazy(function () {\n            sleep(4);\n        }),\n        'jonathan' => Cache::get('jonathan', false),\n        'taylor' => Cache::get('taylor', false),\n        'joe' => Cache::get('joe', false),\n    ]);\n});\n\nRoute::post('/async/checkbox', function () {\n    sleep(2);\n    $previousJoe = Cache::get('joe', false);\n\n    Cache::put('jonathan', request('jonathan'), 10);\n    Cache::put('taylor', request('taylor'), 10);\n    Cache::put('joe', request('joe'), 10);\n\n    if (! $previousJoe && request()->boolean('joe')) {\n        return redirect('article');\n    }\n\n    return redirect('/async');\n});\n\nRoute::get('/defer', function () {\n    info('defer route');\n\n    return inertia('Defer', [\n        'users' => Inertia::defer(function () {\n            info('resolving users');\n            sleep(1);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => 'Jonathan Reinink',\n                    'email' => 'hello@reinink.com',\n                ],\n                [\n                    'id' => 2,\n                    'name' => 'Taylor Otwell',\n                    'email' => 'howdy@otwell.biz',\n                ],\n                [\n                    'id' => 3,\n                    'name' => 'Joe Tannenbaum',\n                    'email' => 'yo@tannenbaum.edu',\n                ],\n            ];\n        }, 'u'),\n        'foods' => Inertia::defer(function () {\n            info('resolving foods');\n            sleep(3);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => 'Pizza',\n                ],\n                [\n                    'id' => 2,\n                    'name' => 'Tacos',\n                ],\n                [\n                    'id' => 3,\n                    'name' => 'Sushi',\n                ],\n            ];\n        }, 'f'),\n        'organizations' => Inertia::defer(function () {\n            info('resolving organizations');\n            sleep(2);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => 'InertiaJS',\n                    'url' => 'https://inertiajs.com',\n                ],\n                [\n                    'id' => 2,\n                    'name' => 'Laravel',\n                    'url' => 'https://laravel.com',\n                ],\n                [\n                    'id' => 3,\n                    'name' => 'VueJS',\n                    'url' => 'https://vuejs.org',\n                ],\n            ];\n        }, 'o'),\n    ]);\n});\n\nRoute::get('/goodbye', function () {\n    return Inertia::location('https://inertiajs.com/redirects');\n});\n\nRoute::get('/poll', function () {\n    return inertia('Poll', [\n        'users' => collect([\n            'Jonathan Reinink',\n            'Taylor Otwell',\n            'Joe Tannenbaum',\n            'Jess Archer',\n            'Claudio Dekker',\n            'Sebastian De Deyne',\n            'Pedro Borges',\n        ])->shuffle()->take(3)->values(),\n        'companies' => collect([\n            'InertiaJS',\n            'Laravel',\n            'VueJS',\n            'Tailwind CSS',\n            'AlpineJS',\n            'Livewire',\n            'Spatie',\n        ])->shuffle()->take(3)->values(),\n    ]);\n});\n\nRoute::get('/elsewhere', function () {\n    return inertia('Users');\n});\n\nRoute::get('/sleepy/{duration}', function ($duration) {\n    sleep($duration);\n\n    return inertia('Users');\n});\n\nRoute::post('/sleepy/{duration}', function ($duration) {\n    sleep($duration);\n\n    return inertia('Article');\n});\n\nRoute::post('/messages', function (Request $request) {\n    $data = $request->validate([\n        'message' => ['required', 'string'],\n    ]);\n\n    // Store the new user message\n    $prompt = ChatMessage::create([\n        'type' => 'prompt',\n        'content' => $data['message'],\n    ]);\n\n    $messages = ChatMessage::latest('id')\n        ->limit(10)\n        ->get()\n        ->reverse()\n        ->map(function (ChatMessage $message) use ($prompt) {\n            $content = $message->content;\n\n            if ($message->is($prompt)) {\n                // Tell LLM not to answer too long and don't halucinate\n                $content = \"Answer in max. 10 sentences, may be shorter. Code examples allowed when needed. Don't hallucinate, just answer based on the provided context.\\n\\n\".$content;\n            }\n\n            return $message->type === 'prompt'\n                ? new UserMessage($content)\n                : new AssistantMessage($content);\n        })\n        ->all();\n\n    // Create a streaming response from the LLM\n    $stream = Prism::text()\n        ->using(Provider::Ollama, 'gemma3:4b')\n        ->withMessages($messages)\n        ->asStream();\n\n    return response()->stream(function () use ($stream) {\n        $response = '';\n\n        foreach ($stream as $chunk) {\n            $response .= $chunk->text;\n            echo $chunk->text;\n            ob_flush();\n            flush();\n        }\n\n        if (! blank($response)) {\n            ChatMessage::create([\n                'type' => 'response',\n                'content' => $response,\n            ]);\n        }\n    }, 200, ['X-Accel-Buffering' => 'no']);\n});\n\nRoute::get('/chat', function () {\n    if (request()->header('X-Inertia-Partial-Component')) {\n        // Simulate latency for partial reloads\n        usleep(500_000);\n    }\n\n    return inertia('Chat', [\n        'messages' => Inertia::scroll(ChatMessage::latest('id')->cursorPaginate(10)),\n    ]);\n});\n\nRoute::get('/photo-grid/{horizontal?}', function ($horizontal = null) {\n    if (request()->header('X-Inertia-Partial-Component')) {\n        // Simulate latency for partial reloads\n        usleep(250_000);\n    }\n\n    $perPage = 24;\n    $pages = 30;\n    $total = $perPage * $pages;\n    $page = request()->integer('page', 1);\n\n    $photos = collect()\n        ->range(1, $total)\n        ->forPage($page, $perPage)\n        ->map(fn ($i) => [\n            'id' => $i,\n            'url' => \"https://picsum.photos/id/{$i}/300/300\",\n        ])\n        ->pipe(fn ($photos) => new LengthAwarePaginator(\n            $photos->values(),\n            $total,\n            $perPage,\n            $page,\n        ));\n\n    return inertia($horizontal ? 'PhotoHorizontal' : 'PhotoGrid', [\n        'photos' => Inertia::scroll($photos),\n    ]);\n});\n\nRoute::get('/data-table', function () {\n    if (request()->header('X-Inertia-Partial-Component')) {\n        // Simulate latency for partial reloads\n        usleep(500_000);\n    }\n\n    $perPage = 200;\n    $pages = 30;\n    $total = $perPage * $pages;\n    $page = request()->integer('page', 1);\n\n    $users = collect()\n        ->range(1, $total)\n        ->forPage($page, $perPage)\n        ->map(fn ($i) => [\n            'id' => $i,\n            'name' => \"User {$i}\",\n        ])\n        ->pipe(fn ($photos) => new LengthAwarePaginator(\n            $photos->values(),\n            $total,\n            $perPage,\n            $page,\n        ));\n\n    return inertia('DataTable', [\n        'users' => Inertia::scroll($users),\n    ]);\n});\n\nRoute::get('/once/{page}', function (int $page) {\n    $component = match ($page) {\n        1 => 'Once/First',\n        2 => 'Once/Second',\n        3 => 'Once/Third',\n        4 => 'Once/Fourth',\n        default => abort(404),\n    };\n\n    return inertia($component, [\n        'foo' => Inertia::once(fn () => 'foo value: '.now()->getTimestampMs())->fresh($page === 3),\n        'bar' => Inertia::once(fn () => 'bar value: '.now()->getTimestampMs())->until(10),\n        'baz' . $page => Inertia::once(fn () => 'baz value: '.now()->getTimestampMs())->as('baz'),\n        'qux' => Inertia::defer(fn () => 'qux value: '.now()->getTimestampMs())->once(),\n    ]);\n});\n\nRoute::get('/flash', function () {\n    return inertia('Flash');\n});\n\nRoute::get('/flash/direct', function () {\n    return Inertia::flash('message', 'Sent with render!')->render('Flash');\n});\n\nRoute::post('/flash/form', function () {\n    return Inertia::flash('message', 'Sent with redirect!')->back();\n});\n"
  },
  {
    "path": "playgrounds/react/storage/app/.gitignore",
    "content": "*\n!public/\n!.gitignore\n"
  },
  {
    "path": "playgrounds/react/storage/framework/.gitignore",
    "content": "compiled.php\nconfig.php\ndown\nevents.scanned.php\nmaintenance.php\nroutes.php\nroutes.scanned.php\nschedule-*\nservices.json\n"
  },
  {
    "path": "playgrounds/react/storage/framework/cache/.gitignore",
    "content": "*\n!data/\n!.gitignore\n"
  },
  {
    "path": "playgrounds/react/storage/framework/sessions/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/react/storage/framework/testing/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/react/storage/framework/views/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/react/storage/logs/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/react/tests/CreatesApplication.php",
    "content": "<?php\n\nnamespace Tests;\n\nuse Illuminate\\Contracts\\Console\\Kernel;\n\ntrait CreatesApplication\n{\n    /**\n     * Creates the application.\n     *\n     * @return \\Illuminate\\Foundation\\Application\n     */\n    public function createApplication()\n    {\n        $app = require __DIR__.'/../bootstrap/app.php';\n\n        $app->make(Kernel::class)->bootstrap();\n\n        return $app;\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/tests/Feature/ExampleTest.php",
    "content": "<?php\n\nnamespace Tests\\Feature;\n\n// use Illuminate\\Foundation\\Testing\\RefreshDatabase;\nuse Tests\\TestCase;\n\nclass ExampleTest extends TestCase\n{\n    /**\n     * A basic test example.\n     *\n     * @return void\n     */\n    public function test_the_application_returns_a_successful_response()\n    {\n        $response = $this->get('/');\n\n        $response->assertStatus(200);\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/tests/TestCase.php",
    "content": "<?php\n\nnamespace Tests;\n\nuse Illuminate\\Foundation\\Testing\\TestCase as BaseTestCase;\n\nabstract class TestCase extends BaseTestCase\n{\n    use CreatesApplication;\n}\n"
  },
  {
    "path": "playgrounds/react/tests/Unit/ExampleTest.php",
    "content": "<?php\n\nnamespace Tests\\Unit;\n\nuse PHPUnit\\Framework\\TestCase;\n\nclass ExampleTest extends TestCase\n{\n    /**\n     * A basic test example.\n     *\n     * @return void\n     */\n    public function test_that_true_is_true()\n    {\n        $this->assertTrue(true);\n    }\n}\n"
  },
  {
    "path": "playgrounds/react/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"isolatedModules\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"jsx\": \"react-jsx\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"node\",\n    \"skipLibCheck\": true\n  }\n}\n"
  },
  {
    "path": "playgrounds/react/vite.config.ts",
    "content": "import tailwindcss from '@tailwindcss/vite'\nimport react from '@vitejs/plugin-react'\nimport laravel from 'laravel-vite-plugin'\nimport { defineConfig } from 'vite'\n\nexport default defineConfig({\n  build: {\n    minify: false,\n  },\n  plugins: [\n    laravel({\n      input: ['resources/css/app.css', 'resources/js/app.tsx'],\n      ssr: 'resources/js/ssr.tsx',\n      refresh: true,\n    }),\n    react(),\n    tailwindcss(),\n  ],\n})\n"
  },
  {
    "path": "playgrounds/svelte4/.gitattributes",
    "content": "* text=auto\n\n*.blade.php diff=html\n*.css diff=css\n*.html diff=html\n*.md diff=markdown\n*.php diff=php\n\n/.github export-ignore\nCHANGELOG.md export-ignore\n.styleci.yml export-ignore\n"
  },
  {
    "path": "playgrounds/svelte4/.gitignore",
    "content": "/node_modules\n/bootstrap/ssr\n/public/build\n/public/hot\n/public/storage\n/storage/*.key\n/vendor\n.env\n.env.backup\n.env.production\n.phpunit.result.cache\nHomestead.json\nHomestead.yaml\nauth.json\nnpm-debug.log\nyarn-error.log\n/.fleet\n/.idea\n/.vscode\n"
  },
  {
    "path": "playgrounds/svelte4/README.md",
    "content": "<p align=\"center\"><a href=\"https://laravel.com\" target=\"_blank\"><img src=\"https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg\" width=\"400\" alt=\"Laravel Logo\"></a></p>\n\n<p align=\"center\">\n<a href=\"https://travis-ci.org/laravel/framework\"><img src=\"https://travis-ci.org/laravel/framework.svg\" alt=\"Build Status\"></a>\n<a href=\"https://packagist.org/packages/laravel/framework\"><img src=\"https://img.shields.io/packagist/dt/laravel/framework\" alt=\"Total Downloads\"></a>\n<a href=\"https://packagist.org/packages/laravel/framework\"><img src=\"https://img.shields.io/packagist/v/laravel/framework\" alt=\"Latest Stable Version\"></a>\n<a href=\"https://packagist.org/packages/laravel/framework\"><img src=\"https://img.shields.io/packagist/l/laravel/framework\" alt=\"License\"></a>\n</p>\n\n## About Laravel\n\nLaravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:\n\n- [Simple, fast routing engine](https://laravel.com/docs/routing).\n- [Powerful dependency injection container](https://laravel.com/docs/container).\n- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.\n- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).\n- Database agnostic [schema migrations](https://laravel.com/docs/migrations).\n- [Robust background job processing](https://laravel.com/docs/queues).\n- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).\n\nLaravel is accessible, powerful, and provides tools required for large, robust applications.\n\n## Learning Laravel\n\nLaravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.\n\nYou may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.\n\nIf you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 2000 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.\n\n## Laravel Sponsors\n\nWe would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell).\n\n### Premium Partners\n\n- **[Vehikl](https://vehikl.com/)**\n- **[Tighten Co.](https://tighten.co)**\n- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**\n- **[64 Robots](https://64robots.com)**\n- **[Cubet Techno Labs](https://cubettech.com)**\n- **[Cyber-Duck](https://cyber-duck.co.uk)**\n- **[Many](https://www.many.co.uk)**\n- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**\n- **[DevSquad](https://devsquad.com)**\n- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**\n- **[OP.GG](https://op.gg)**\n- **[WebReinvent](https://webreinvent.com/?utm_source=laravel&utm_medium=github&utm_campaign=patreon-sponsors)**\n- **[Lendio](https://lendio.com)**\n\n## Contributing\n\nThank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).\n\n## Code of Conduct\n\nIn order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).\n\n## Security Vulnerabilities\n\nIf you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.\n\n## License\n\nThe Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).\n"
  },
  {
    "path": "playgrounds/svelte4/app/Console/Kernel.php",
    "content": "<?php\n\nnamespace App\\Console;\n\nuse Illuminate\\Console\\Scheduling\\Schedule;\nuse Illuminate\\Foundation\\Console\\Kernel as ConsoleKernel;\n\nclass Kernel extends ConsoleKernel\n{\n    /**\n     * Define the application's command schedule.\n     *\n     * @return void\n     */\n    protected function schedule(Schedule $schedule)\n    {\n        // $schedule->command('inspire')->hourly();\n    }\n\n    /**\n     * Register the commands for the application.\n     *\n     * @return void\n     */\n    protected function commands()\n    {\n        $this->load(__DIR__.'/Commands');\n\n        require base_path('routes/console.php');\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Exceptions/Handler.php",
    "content": "<?php\n\nnamespace App\\Exceptions;\n\nuse Illuminate\\Foundation\\Exceptions\\Handler as ExceptionHandler;\nuse Throwable;\n\nclass Handler extends ExceptionHandler\n{\n    /**\n     * A list of exception types with their corresponding custom log levels.\n     *\n     * @var array<class-string<\\Throwable>, \\Psr\\Log\\LogLevel::*>\n     */\n    protected $levels = [\n        //\n    ];\n\n    /**\n     * A list of the exception types that are not reported.\n     *\n     * @var array<int, class-string<\\Throwable>>\n     */\n    protected $dontReport = [\n        //\n    ];\n\n    /**\n     * A list of the inputs that are never flashed to the session on validation exceptions.\n     *\n     * @var array<int, string>\n     */\n    protected $dontFlash = [\n        'current_password',\n        'password',\n        'password_confirmation',\n    ];\n\n    /**\n     * Register the exception handling callbacks for the application.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        $this->reportable(function (Throwable $e) {\n            //\n        });\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Http/Controllers/Controller.php",
    "content": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Foundation\\Auth\\Access\\AuthorizesRequests;\nuse Illuminate\\Foundation\\Bus\\DispatchesJobs;\nuse Illuminate\\Foundation\\Validation\\ValidatesRequests;\nuse Illuminate\\Routing\\Controller as BaseController;\n\nclass Controller extends BaseController\n{\n    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Http/Kernel.php",
    "content": "<?php\n\nnamespace App\\Http;\n\nuse Illuminate\\Foundation\\Http\\Kernel as HttpKernel;\n\nclass Kernel extends HttpKernel\n{\n    /**\n     * The application's global HTTP middleware stack.\n     *\n     * These middleware are run during every request to your application.\n     *\n     * @var array<int, class-string|string>\n     */\n    protected $middleware = [\n        // \\App\\Http\\Middleware\\TrustHosts::class,\n        \\App\\Http\\Middleware\\TrustProxies::class,\n        \\Illuminate\\Http\\Middleware\\HandleCors::class,\n        \\App\\Http\\Middleware\\PreventRequestsDuringMaintenance::class,\n        \\Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize::class,\n        \\App\\Http\\Middleware\\TrimStrings::class,\n        \\Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull::class,\n    ];\n\n    /**\n     * The application's route middleware groups.\n     *\n     * @var array<string, array<int, class-string|string>>\n     */\n    protected $middlewareGroups = [\n        'web' => [\n            \\App\\Http\\Middleware\\EncryptCookies::class,\n            \\Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse::class,\n            \\Illuminate\\Session\\Middleware\\StartSession::class,\n            \\Illuminate\\View\\Middleware\\ShareErrorsFromSession::class,\n            \\App\\Http\\Middleware\\VerifyCsrfToken::class,\n            \\Illuminate\\Routing\\Middleware\\SubstituteBindings::class,\n            \\App\\Http\\Middleware\\HandleInertiaRequests::class,\n        ],\n\n        'api' => [\n            // \\Laravel\\Sanctum\\Http\\Middleware\\EnsureFrontendRequestsAreStateful::class,\n            'throttle:api',\n            \\Illuminate\\Routing\\Middleware\\SubstituteBindings::class,\n        ],\n    ];\n\n    /**\n     * The application's route middleware.\n     *\n     * These middleware may be assigned to groups or used individually.\n     *\n     * @var array<string, class-string|string>\n     */\n    protected $routeMiddleware = [\n        'auth' => \\App\\Http\\Middleware\\Authenticate::class,\n        'auth.basic' => \\Illuminate\\Auth\\Middleware\\AuthenticateWithBasicAuth::class,\n        'auth.session' => \\Illuminate\\Session\\Middleware\\AuthenticateSession::class,\n        'cache.headers' => \\Illuminate\\Http\\Middleware\\SetCacheHeaders::class,\n        'can' => \\Illuminate\\Auth\\Middleware\\Authorize::class,\n        'guest' => \\App\\Http\\Middleware\\RedirectIfAuthenticated::class,\n        'password.confirm' => \\Illuminate\\Auth\\Middleware\\RequirePassword::class,\n        'signed' => \\App\\Http\\Middleware\\ValidateSignature::class,\n        'throttle' => \\Illuminate\\Routing\\Middleware\\ThrottleRequests::class,\n        'verified' => \\Illuminate\\Auth\\Middleware\\EnsureEmailIsVerified::class,\n    ];\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Http/Middleware/Authenticate.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Auth\\Middleware\\Authenticate as Middleware;\n\nclass Authenticate extends Middleware\n{\n    /**\n     * Get the path the user should be redirected to when they are not authenticated.\n     *\n     * @param  \\Illuminate\\Http\\Request  $request\n     * @return string|null\n     */\n    protected function redirectTo($request)\n    {\n        if (! $request->expectsJson()) {\n            return route('login');\n        }\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Http/Middleware/EncryptCookies.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Cookie\\Middleware\\EncryptCookies as Middleware;\n\nclass EncryptCookies extends Middleware\n{\n    /**\n     * The names of the cookies that should not be encrypted.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        //\n    ];\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Http/Middleware/HandleInertiaRequests.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Http\\Request;\nuse Inertia\\Middleware;\n\nclass HandleInertiaRequests extends Middleware\n{\n    /**\n     * The root template that's loaded on the first page visit.\n     *\n     * @see https://inertiajs.com/server-side-setup#root-template\n     * @var string\n     */\n    protected $rootView = 'app';\n\n    /**\n     * Determines the current asset version.\n     *\n     * @see https://inertiajs.com/asset-versioning\n     */\n    public function version(Request $request): ?string\n    {\n        return parent::version($request);\n    }\n\n    /**\n     * Defines the props that are shared by default.\n     *\n     * @see https://inertiajs.com/shared-data\n     */\n    public function share(Request $request): array\n    {\n        return array_merge(parent::share($request), [\n            'appName' => config('app.name'),\n        ]);\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Http/Middleware/PreventRequestsDuringMaintenance.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance as Middleware;\n\nclass PreventRequestsDuringMaintenance extends Middleware\n{\n    /**\n     * The URIs that should be reachable while maintenance mode is enabled.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        //\n    ];\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Http/Middleware/RedirectIfAuthenticated.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse App\\Providers\\RouteServiceProvider;\nuse Closure;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Auth;\n\nclass RedirectIfAuthenticated\n{\n    /**\n     * Handle an incoming request.\n     *\n     * @param  \\Closure(\\Illuminate\\Http\\Request): (\\Illuminate\\Http\\Response|\\Illuminate\\Http\\RedirectResponse)  $next\n     * @param  string|null  ...$guards\n     * @return \\Illuminate\\Http\\Response|\\Illuminate\\Http\\RedirectResponse\n     */\n    public function handle(Request $request, Closure $next, ...$guards)\n    {\n        $guards = empty($guards) ? [null] : $guards;\n\n        foreach ($guards as $guard) {\n            if (Auth::guard($guard)->check()) {\n                return redirect(RouteServiceProvider::HOME);\n            }\n        }\n\n        return $next($request);\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Http/Middleware/TrimStrings.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Foundation\\Http\\Middleware\\TrimStrings as Middleware;\n\nclass TrimStrings extends Middleware\n{\n    /**\n     * The names of the attributes that should not be trimmed.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        'current_password',\n        'password',\n        'password_confirmation',\n    ];\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Http/Middleware/TrustHosts.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Http\\Middleware\\TrustHosts as Middleware;\n\nclass TrustHosts extends Middleware\n{\n    /**\n     * Get the host patterns that should be trusted.\n     *\n     * @return array<int, string|null>\n     */\n    public function hosts()\n    {\n        return [\n            $this->allSubdomainsOfApplicationUrl(),\n        ];\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Http/Middleware/TrustProxies.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Http\\Middleware\\TrustProxies as Middleware;\nuse Illuminate\\Http\\Request;\n\nclass TrustProxies extends Middleware\n{\n    /**\n     * The trusted proxies for this application.\n     *\n     * @var array<int, string>|string|null\n     */\n    protected $proxies;\n\n    /**\n     * The headers that should be used to detect proxies.\n     *\n     * @var int\n     */\n    protected $headers =\n        Request::HEADER_X_FORWARDED_FOR |\n        Request::HEADER_X_FORWARDED_HOST |\n        Request::HEADER_X_FORWARDED_PORT |\n        Request::HEADER_X_FORWARDED_PROTO |\n        Request::HEADER_X_FORWARDED_AWS_ELB;\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Http/Middleware/ValidateSignature.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Routing\\Middleware\\ValidateSignature as Middleware;\n\nclass ValidateSignature extends Middleware\n{\n    /**\n     * The names of the query string parameters that should be ignored.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        // 'fbclid',\n        // 'utm_campaign',\n        // 'utm_content',\n        // 'utm_medium',\n        // 'utm_source',\n        // 'utm_term',\n    ];\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Http/Middleware/VerifyCsrfToken.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Foundation\\Http\\Middleware\\VerifyCsrfToken as Middleware;\n\nclass VerifyCsrfToken extends Middleware\n{\n    /**\n     * The URIs that should be excluded from CSRF verification.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        //\n    ];\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Http/Requests/PrecognitionFormRequest.php",
    "content": "<?php\n\nnamespace App\\Http\\Requests;\n\nuse Illuminate\\Foundation\\Http\\FormRequest;\n\nclass PrecognitionFormRequest extends FormRequest\n{\n    /**\n     * Determine if the user is authorized to make this request.\n     */\n    public function authorize(): bool\n    {\n        return true;\n    }\n\n    /**\n     * Get the validation rules that apply to the request.\n     *\n     * @return array<string, \\Illuminate\\Contracts\\Validation\\ValidationRule|array<mixed>|string>\n     */\n    public function rules(): array\n    {\n        sleep(1);\n\n        return [\n            'name' => ['required', 'string', 'min:3', 'max:255'],\n            'email' => ['required', 'email', 'max:255'],\n            'avatar' => ['nullable', 'file', 'image'],\n        ];\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Models/User.php",
    "content": "<?php\n\nnamespace App\\Models;\n\n// use Illuminate\\Contracts\\Auth\\MustVerifyEmail;\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Foundation\\Auth\\User as Authenticatable;\nuse Illuminate\\Notifications\\Notifiable;\nuse Laravel\\Sanctum\\HasApiTokens;\n\nclass User extends Authenticatable\n{\n    use HasApiTokens, HasFactory, Notifiable;\n\n    /**\n     * The attributes that are mass assignable.\n     *\n     * @var array<int, string>\n     */\n    protected $fillable = [\n        'name',\n        'email',\n        'password',\n    ];\n\n    /**\n     * The attributes that should be hidden for serialization.\n     *\n     * @var array<int, string>\n     */\n    protected $hidden = [\n        'password',\n        'remember_token',\n    ];\n\n    /**\n     * The attributes that should be cast.\n     *\n     * @var array<string, string>\n     */\n    protected $casts = [\n        'email_verified_at' => 'datetime',\n    ];\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Providers/AppServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Support\\ServiceProvider;\n\nclass AppServiceProvider extends ServiceProvider\n{\n    /**\n     * Register any application services.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        //\n    }\n\n    /**\n     * Bootstrap any application services.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Providers/AuthServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\n// use Illuminate\\Support\\Facades\\Gate;\nuse Illuminate\\Foundation\\Support\\Providers\\AuthServiceProvider as ServiceProvider;\n\nclass AuthServiceProvider extends ServiceProvider\n{\n    /**\n     * The model to policy mappings for the application.\n     *\n     * @var array<class-string, class-string>\n     */\n    protected $policies = [\n        // 'App\\Models\\Model' => 'App\\Policies\\ModelPolicy',\n    ];\n\n    /**\n     * Register any authentication / authorization services.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        $this->registerPolicies();\n\n        //\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Providers/BroadcastServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Support\\Facades\\Broadcast;\nuse Illuminate\\Support\\ServiceProvider;\n\nclass BroadcastServiceProvider extends ServiceProvider\n{\n    /**\n     * Bootstrap any application services.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        Broadcast::routes();\n\n        require base_path('routes/channels.php');\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Providers/EventServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Auth\\Events\\Registered;\nuse Illuminate\\Auth\\Listeners\\SendEmailVerificationNotification;\nuse Illuminate\\Foundation\\Support\\Providers\\EventServiceProvider as ServiceProvider;\nuse Illuminate\\Support\\Facades\\Event;\n\nclass EventServiceProvider extends ServiceProvider\n{\n    /**\n     * The event to listener mappings for the application.\n     *\n     * @var array<class-string, array<int, class-string>>\n     */\n    protected $listen = [\n        Registered::class => [\n            SendEmailVerificationNotification::class,\n        ],\n    ];\n\n    /**\n     * Register any events for your application.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        //\n    }\n\n    /**\n     * Determine if events and listeners should be automatically discovered.\n     *\n     * @return bool\n     */\n    public function shouldDiscoverEvents()\n    {\n        return false;\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/app/Providers/RouteServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Cache\\RateLimiting\\Limit;\nuse Illuminate\\Foundation\\Support\\Providers\\RouteServiceProvider as ServiceProvider;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\RateLimiter;\nuse Illuminate\\Support\\Facades\\Route;\n\nclass RouteServiceProvider extends ServiceProvider\n{\n    /**\n     * The path to the \"home\" route for your application.\n     *\n     * Typically, users are redirected here after authentication.\n     *\n     * @var string\n     */\n    public const HOME = '/home';\n\n    /**\n     * Define your route model bindings, pattern filters, and other route configuration.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        $this->configureRateLimiting();\n\n        $this->routes(function () {\n            Route::middleware('api')\n                ->prefix('api')\n                ->group(base_path('routes/api.php'));\n\n            Route::middleware('web')\n                ->group(base_path('routes/web.php'));\n        });\n    }\n\n    /**\n     * Configure the rate limiters for the application.\n     *\n     * @return void\n     */\n    protected function configureRateLimiting()\n    {\n        RateLimiter::for('api', function (Request $request) {\n            return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());\n        });\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/artisan",
    "content": "#!/usr/bin/env php\n<?php\n\ndefine('LARAVEL_START', microtime(true));\n\n/*\n|--------------------------------------------------------------------------\n| Register The Auto Loader\n|--------------------------------------------------------------------------\n|\n| Composer provides a convenient, automatically generated class loader\n| for our application. We just need to utilize it! We'll require it\n| into the script here so that we do not have to worry about the\n| loading of any of our classes manually. It's great to relax.\n|\n*/\n\nrequire __DIR__.'/vendor/autoload.php';\n\n$app = require_once __DIR__.'/bootstrap/app.php';\n\n/*\n|--------------------------------------------------------------------------\n| Run The Artisan Application\n|--------------------------------------------------------------------------\n|\n| When we run the console application, the current CLI command will be\n| executed in this console and the response sent back to a terminal\n| or another output device for the developers. Here goes nothing!\n|\n*/\n\n$kernel = $app->make(Illuminate\\Contracts\\Console\\Kernel::class);\n\n$status = $kernel->handle(\n    $input = new Symfony\\Component\\Console\\Input\\ArgvInput,\n    new Symfony\\Component\\Console\\Output\\ConsoleOutput\n);\n\n/*\n|--------------------------------------------------------------------------\n| Shutdown The Application\n|--------------------------------------------------------------------------\n|\n| Once Artisan has finished running, we will fire off the shutdown events\n| so that any final work may be done by the application before we shut\n| down the process. This is the last thing to happen to the request.\n|\n*/\n\n$kernel->terminate($input, $status);\n\nexit($status);\n"
  },
  {
    "path": "playgrounds/svelte4/bootstrap/app.php",
    "content": "<?php\n\n/*\n|--------------------------------------------------------------------------\n| Create The Application\n|--------------------------------------------------------------------------\n|\n| The first thing we will do is create a new Laravel application instance\n| which serves as the \"glue\" for all the components of Laravel, and is\n| the IoC container for the system binding all of the various parts.\n|\n*/\n\n$app = new Illuminate\\Foundation\\Application(\n    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)\n);\n\n/*\n|--------------------------------------------------------------------------\n| Bind Important Interfaces\n|--------------------------------------------------------------------------\n|\n| Next, we need to bind some important interfaces into the container so\n| we will be able to resolve them when needed. The kernels serve the\n| incoming requests to this application from both the web and CLI.\n|\n*/\n\n$app->singleton(\n    Illuminate\\Contracts\\Http\\Kernel::class,\n    App\\Http\\Kernel::class\n);\n\n$app->singleton(\n    Illuminate\\Contracts\\Console\\Kernel::class,\n    App\\Console\\Kernel::class\n);\n\n$app->singleton(\n    Illuminate\\Contracts\\Debug\\ExceptionHandler::class,\n    App\\Exceptions\\Handler::class\n);\n\n/*\n|--------------------------------------------------------------------------\n| Return The Application\n|--------------------------------------------------------------------------\n|\n| This script returns the application instance. The instance is given to\n| the calling script so we can separate the building of the instances\n| from the actual running of the application and sending responses.\n|\n*/\n\nreturn $app;\n"
  },
  {
    "path": "playgrounds/svelte4/bootstrap/cache/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/svelte4/composer.json",
    "content": "{\n    \"name\": \"laravel/laravel\",\n    \"type\": \"project\",\n    \"description\": \"The Laravel Framework.\",\n    \"keywords\": [\n        \"framework\",\n        \"laravel\"\n    ],\n    \"license\": \"MIT\",\n    \"require\": {\n        \"php\": \"^8.2\",\n        \"guzzlehttp/guzzle\": \"^7.2\",\n        \"inertiajs/inertia-laravel\": \"^2.0.16\",\n        \"laravel/framework\": \"^11.0\",\n        \"laravel/sanctum\": \"^4.0\",\n        \"laravel/tinker\": \"^2.7\"\n    },\n    \"require-dev\": {\n        \"fakerphp/faker\": \"^1.9.1\",\n        \"laravel/pint\": \"^1.0\",\n        \"laravel/sail\": \"^1.0.1\",\n        \"mockery/mockery\": \"^1.4.4\",\n        \"nunomaduro/collision\": \"^8.1\",\n        \"phpunit/phpunit\": \"^10.0\",\n        \"spatie/laravel-ignition\": \"^2.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"App\\\\\": \"app/\",\n            \"Database\\\\Factories\\\\\": \"database/factories/\",\n            \"Database\\\\Seeders\\\\\": \"database/seeders/\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Tests\\\\\": \"tests/\"\n        }\n    },\n    \"scripts\": {\n        \"post-autoload-dump\": [\n            \"Illuminate\\\\Foundation\\\\ComposerScripts::postAutoloadDump\",\n            \"@php artisan package:discover --ansi\"\n        ],\n        \"post-update-cmd\": [\n            \"@php artisan vendor:publish --tag=laravel-assets --ansi --force\"\n        ],\n        \"post-root-package-install\": [\n            \"@php -r \\\"file_exists('.env') || copy('.env.example', '.env');\\\"\"\n        ],\n        \"post-create-project-cmd\": [\n            \"@php artisan key:generate --ansi\"\n        ],\n        \"dev\": [\n            \"Composer\\\\Config::disableProcessTimeout\",\n            \"pnpx concurrently -c \\\"#93c5fd,#c4b5fd\\\" \\\"php artisan serve\\\" \\\"pnpm run dev\\\" --names=server,vite\"\n        ]\n    },\n    \"extra\": {\n        \"laravel\": {\n            \"dont-discover\": []\n        }\n    },\n    \"config\": {\n        \"optimize-autoloader\": true,\n        \"preferred-install\": \"dist\",\n        \"sort-packages\": true,\n        \"allow-plugins\": {\n            \"pestphp/pest-plugin\": true\n        }\n    },\n    \"minimum-stability\": \"dev\",\n    \"prefer-stable\": true\n}\n"
  },
  {
    "path": "playgrounds/svelte4/config/app.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Facades\\Facade;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Name\n    |--------------------------------------------------------------------------\n    |\n    | This value is the name of your application. This value is used when the\n    | framework needs to place the application's name in a notification or\n    | any other location as required by the application or its packages.\n    |\n    */\n\n    'name' => env('APP_NAME', 'Laravel'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Environment\n    |--------------------------------------------------------------------------\n    |\n    | This value determines the \"environment\" your application is currently\n    | running in. This may determine how you prefer to configure various\n    | services the application utilizes. Set this in your \".env\" file.\n    |\n    */\n\n    'env' => env('APP_ENV', 'production'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Debug Mode\n    |--------------------------------------------------------------------------\n    |\n    | When your application is in debug mode, detailed error messages with\n    | stack traces will be shown on every error that occurs within your\n    | application. If disabled, a simple generic error page is shown.\n    |\n    */\n\n    'debug' => (bool) env('APP_DEBUG', false),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application URL\n    |--------------------------------------------------------------------------\n    |\n    | This URL is used by the console to properly generate URLs when using\n    | the Artisan command line tool. You should set this to the root of\n    | your application so that it is used when running Artisan tasks.\n    |\n    */\n\n    'url' => env('APP_URL', 'http://localhost'),\n\n    'asset_url' => env('ASSET_URL'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Timezone\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the default timezone for your application, which\n    | will be used by the PHP date and date-time functions. We have gone\n    | ahead and set this to a sensible default for you out of the box.\n    |\n    */\n\n    'timezone' => 'UTC',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Locale Configuration\n    |--------------------------------------------------------------------------\n    |\n    | The application locale determines the default locale that will be used\n    | by the translation service provider. You are free to set this value\n    | to any of the locales which will be supported by the application.\n    |\n    */\n\n    'locale' => 'en',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Fallback Locale\n    |--------------------------------------------------------------------------\n    |\n    | The fallback locale determines the locale to use when the current one\n    | is not available. You may change the value to correspond to any of\n    | the language folders that are provided through your application.\n    |\n    */\n\n    'fallback_locale' => 'en',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Faker Locale\n    |--------------------------------------------------------------------------\n    |\n    | This locale will be used by the Faker PHP library when generating fake\n    | data for your database seeds. For example, this will be used to get\n    | localized telephone numbers, street address information and more.\n    |\n    */\n\n    'faker_locale' => 'en_US',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Encryption Key\n    |--------------------------------------------------------------------------\n    |\n    | This key is used by the Illuminate encrypter service and should be set\n    | to a random, 32 character string, otherwise these encrypted strings\n    | will not be safe. Please do this before deploying an application!\n    |\n    */\n\n    'key' => env('APP_KEY'),\n\n    'cipher' => 'AES-256-CBC',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Maintenance Mode Driver\n    |--------------------------------------------------------------------------\n    |\n    | These configuration options determine the driver used to determine and\n    | manage Laravel's \"maintenance mode\" status. The \"cache\" driver will\n    | allow maintenance mode to be controlled across multiple machines.\n    |\n    | Supported drivers: \"file\", \"cache\"\n    |\n    */\n\n    'maintenance' => [\n        'driver' => 'file',\n        // 'store'  => 'redis',\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Autoloaded Service Providers\n    |--------------------------------------------------------------------------\n    |\n    | The service providers listed here will be automatically loaded on the\n    | request to your application. Feel free to add your own services to\n    | this array to grant expanded functionality to your applications.\n    |\n    */\n\n    'providers' => [\n\n        /*\n         * Laravel Framework Service Providers...\n         */\n        Illuminate\\Auth\\AuthServiceProvider::class,\n        Illuminate\\Broadcasting\\BroadcastServiceProvider::class,\n        Illuminate\\Bus\\BusServiceProvider::class,\n        Illuminate\\Cache\\CacheServiceProvider::class,\n        Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider::class,\n        Illuminate\\Cookie\\CookieServiceProvider::class,\n        Illuminate\\Database\\DatabaseServiceProvider::class,\n        Illuminate\\Encryption\\EncryptionServiceProvider::class,\n        Illuminate\\Filesystem\\FilesystemServiceProvider::class,\n        Illuminate\\Foundation\\Providers\\FoundationServiceProvider::class,\n        Illuminate\\Hashing\\HashServiceProvider::class,\n        Illuminate\\Mail\\MailServiceProvider::class,\n        Illuminate\\Notifications\\NotificationServiceProvider::class,\n        Illuminate\\Pagination\\PaginationServiceProvider::class,\n        Illuminate\\Pipeline\\PipelineServiceProvider::class,\n        Illuminate\\Queue\\QueueServiceProvider::class,\n        Illuminate\\Redis\\RedisServiceProvider::class,\n        Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider::class,\n        Illuminate\\Session\\SessionServiceProvider::class,\n        Illuminate\\Translation\\TranslationServiceProvider::class,\n        Illuminate\\Validation\\ValidationServiceProvider::class,\n        Illuminate\\View\\ViewServiceProvider::class,\n\n        /*\n         * Package Service Providers...\n         */\n\n        /*\n         * Application Service Providers...\n         */\n        App\\Providers\\AppServiceProvider::class,\n        App\\Providers\\AuthServiceProvider::class,\n        // App\\Providers\\BroadcastServiceProvider::class,\n        App\\Providers\\EventServiceProvider::class,\n        App\\Providers\\RouteServiceProvider::class,\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Class Aliases\n    |--------------------------------------------------------------------------\n    |\n    | This array of class aliases will be registered when this application\n    | is started. However, feel free to register as many as you wish as\n    | the aliases are \"lazy\" loaded so they don't hinder performance.\n    |\n    */\n\n    'aliases' => Facade::defaultAliases()->merge([\n        // 'ExampleClass' => App\\Example\\ExampleClass::class,\n    ])->toArray(),\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/config/auth.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Authentication Defaults\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default authentication \"guard\" and password\n    | reset options for your application. You may change these defaults\n    | as required, but they're a perfect start for most applications.\n    |\n    */\n\n    'defaults' => [\n        'guard' => 'web',\n        'passwords' => 'users',\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Authentication Guards\n    |--------------------------------------------------------------------------\n    |\n    | Next, you may define every authentication guard for your application.\n    | Of course, a great default configuration has been defined for you\n    | here which uses session storage and the Eloquent user provider.\n    |\n    | All authentication drivers have a user provider. This defines how the\n    | users are actually retrieved out of your database or other storage\n    | mechanisms used by this application to persist your user's data.\n    |\n    | Supported: \"session\"\n    |\n    */\n\n    'guards' => [\n        'web' => [\n            'driver' => 'session',\n            'provider' => 'users',\n        ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | User Providers\n    |--------------------------------------------------------------------------\n    |\n    | All authentication drivers have a user provider. This defines how the\n    | users are actually retrieved out of your database or other storage\n    | mechanisms used by this application to persist your user's data.\n    |\n    | If you have multiple user tables or models you may configure multiple\n    | sources which represent each model / table. These sources may then\n    | be assigned to any extra authentication guards you have defined.\n    |\n    | Supported: \"database\", \"eloquent\"\n    |\n    */\n\n    'providers' => [\n        'users' => [\n            'driver' => 'eloquent',\n            'model' => App\\Models\\User::class,\n        ],\n\n        // 'users' => [\n        //     'driver' => 'database',\n        //     'table' => 'users',\n        // ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Resetting Passwords\n    |--------------------------------------------------------------------------\n    |\n    | You may specify multiple password reset configurations if you have more\n    | than one user table or model in the application and you want to have\n    | separate password reset settings based on the specific user types.\n    |\n    | The expire time is the number of minutes that each reset token will be\n    | considered valid. This security feature keeps tokens short-lived so\n    | they have less time to be guessed. You may change this as needed.\n    |\n    */\n\n    'passwords' => [\n        'users' => [\n            'provider' => 'users',\n            'table' => 'password_resets',\n            'expire' => 60,\n            'throttle' => 60,\n        ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Password Confirmation Timeout\n    |--------------------------------------------------------------------------\n    |\n    | Here you may define the amount of seconds before a password confirmation\n    | times out and the user is prompted to re-enter their password via the\n    | confirmation screen. By default, the timeout lasts for three hours.\n    |\n    */\n\n    'password_timeout' => 10800,\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/config/broadcasting.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Broadcaster\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default broadcaster that will be used by the\n    | framework when an event needs to be broadcast. You may set this to\n    | any of the connections defined in the \"connections\" array below.\n    |\n    | Supported: \"pusher\", \"ably\", \"redis\", \"log\", \"null\"\n    |\n    */\n\n    'default' => env('BROADCAST_DRIVER', 'null'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Broadcast Connections\n    |--------------------------------------------------------------------------\n    |\n    | Here you may define all of the broadcast connections that will be used\n    | to broadcast events to other systems or over websockets. Samples of\n    | each available type of connection are provided inside this array.\n    |\n    */\n\n    'connections' => [\n\n        'pusher' => [\n            'driver' => 'pusher',\n            'key' => env('PUSHER_APP_KEY'),\n            'secret' => env('PUSHER_APP_SECRET'),\n            'app_id' => env('PUSHER_APP_ID'),\n            'options' => [\n                'host' => env('PUSHER_HOST') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com',\n                'port' => env('PUSHER_PORT', 443),\n                'scheme' => env('PUSHER_SCHEME', 'https'),\n                'encrypted' => true,\n                'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',\n            ],\n            'client_options' => [\n                // Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html\n            ],\n        ],\n\n        'ably' => [\n            'driver' => 'ably',\n            'key' => env('ABLY_KEY'),\n        ],\n\n        'redis' => [\n            'driver' => 'redis',\n            'connection' => 'default',\n        ],\n\n        'log' => [\n            'driver' => 'log',\n        ],\n\n        'null' => [\n            'driver' => 'null',\n        ],\n\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/config/cache.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Str;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Cache Store\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default cache connection that gets used while\n    | using this caching library. This connection is used when another is\n    | not explicitly specified when executing a given caching function.\n    |\n    */\n\n    'default' => env('CACHE_DRIVER', 'file'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cache Stores\n    |--------------------------------------------------------------------------\n    |\n    | Here you may define all of the cache \"stores\" for your application as\n    | well as their drivers. You may even define multiple stores for the\n    | same cache driver to group types of items stored in your caches.\n    |\n    | Supported drivers: \"apc\", \"array\", \"database\", \"file\",\n    |         \"memcached\", \"redis\", \"dynamodb\", \"octane\", \"null\"\n    |\n    */\n\n    'stores' => [\n\n        'apc' => [\n            'driver' => 'apc',\n        ],\n\n        'array' => [\n            'driver' => 'array',\n            'serialize' => false,\n        ],\n\n        'database' => [\n            'driver' => 'database',\n            'table' => 'cache',\n            'connection' => null,\n            'lock_connection' => null,\n        ],\n\n        'file' => [\n            'driver' => 'file',\n            'path' => storage_path('framework/cache/data'),\n        ],\n\n        'memcached' => [\n            'driver' => 'memcached',\n            'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),\n            'sasl' => [\n                env('MEMCACHED_USERNAME'),\n                env('MEMCACHED_PASSWORD'),\n            ],\n            'options' => [\n                // Memcached::OPT_CONNECT_TIMEOUT => 2000,\n            ],\n            'servers' => [\n                [\n                    'host' => env('MEMCACHED_HOST', '127.0.0.1'),\n                    'port' => env('MEMCACHED_PORT', 11211),\n                    'weight' => 100,\n                ],\n            ],\n        ],\n\n        'redis' => [\n            'driver' => 'redis',\n            'connection' => 'cache',\n            'lock_connection' => 'default',\n        ],\n\n        'dynamodb' => [\n            'driver' => 'dynamodb',\n            'key' => env('AWS_ACCESS_KEY_ID'),\n            'secret' => env('AWS_SECRET_ACCESS_KEY'),\n            'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),\n            'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),\n            'endpoint' => env('DYNAMODB_ENDPOINT'),\n        ],\n\n        'octane' => [\n            'driver' => 'octane',\n        ],\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cache Key Prefix\n    |--------------------------------------------------------------------------\n    |\n    | When utilizing the APC, database, memcached, Redis, or DynamoDB cache\n    | stores there might be other applications using the same cache. For\n    | that reason, you may prefix every cache key to avoid collisions.\n    |\n    */\n\n    'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'),\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/config/cors.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cross-Origin Resource Sharing (CORS) Configuration\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure your settings for cross-origin resource sharing\n    | or \"CORS\". This determines what cross-origin operations may execute\n    | in web browsers. You are free to adjust these settings as needed.\n    |\n    | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS\n    |\n    */\n\n    'paths' => ['api/*', 'sanctum/csrf-cookie'],\n\n    'allowed_methods' => ['*'],\n\n    'allowed_origins' => ['*'],\n\n    'allowed_origins_patterns' => [],\n\n    'allowed_headers' => ['*'],\n\n    'exposed_headers' => [],\n\n    'max_age' => 0,\n\n    'supports_credentials' => false,\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/config/database.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Str;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Database Connection Name\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify which of the database connections below you wish\n    | to use as your default connection for all database work. Of course\n    | you may use many connections at once using the Database library.\n    |\n    */\n\n    'default' => env('DB_CONNECTION', 'mysql'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Database Connections\n    |--------------------------------------------------------------------------\n    |\n    | Here are each of the database connections setup for your application.\n    | Of course, examples of configuring each database platform that is\n    | supported by Laravel is shown below to make development simple.\n    |\n    |\n    | All database work in Laravel is done through the PHP PDO facilities\n    | so make sure you have the driver for your particular database of\n    | choice installed on your machine before you begin development.\n    |\n    */\n\n    'connections' => [\n\n        'sqlite' => [\n            'driver' => 'sqlite',\n            'url' => env('DATABASE_URL'),\n            'database' => env('DB_DATABASE', database_path('database.sqlite')),\n            'prefix' => '',\n            'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),\n        ],\n\n        'mysql' => [\n            'driver' => 'mysql',\n            'url' => env('DATABASE_URL'),\n            'host' => env('DB_HOST', '127.0.0.1'),\n            'port' => env('DB_PORT', '3306'),\n            'database' => env('DB_DATABASE', 'forge'),\n            'username' => env('DB_USERNAME', 'forge'),\n            'password' => env('DB_PASSWORD', ''),\n            'unix_socket' => env('DB_SOCKET', ''),\n            'charset' => 'utf8mb4',\n            'collation' => 'utf8mb4_unicode_ci',\n            'prefix' => '',\n            'prefix_indexes' => true,\n            'strict' => true,\n            'engine' => null,\n            'options' => extension_loaded('pdo_mysql') ? array_filter([\n                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),\n            ]) : [],\n        ],\n\n        'pgsql' => [\n            'driver' => 'pgsql',\n            'url' => env('DATABASE_URL'),\n            'host' => env('DB_HOST', '127.0.0.1'),\n            'port' => env('DB_PORT', '5432'),\n            'database' => env('DB_DATABASE', 'forge'),\n            'username' => env('DB_USERNAME', 'forge'),\n            'password' => env('DB_PASSWORD', ''),\n            'charset' => 'utf8',\n            'prefix' => '',\n            'prefix_indexes' => true,\n            'search_path' => 'public',\n            'sslmode' => 'prefer',\n        ],\n\n        'sqlsrv' => [\n            'driver' => 'sqlsrv',\n            'url' => env('DATABASE_URL'),\n            'host' => env('DB_HOST', 'localhost'),\n            'port' => env('DB_PORT', '1433'),\n            'database' => env('DB_DATABASE', 'forge'),\n            'username' => env('DB_USERNAME', 'forge'),\n            'password' => env('DB_PASSWORD', ''),\n            'charset' => 'utf8',\n            'prefix' => '',\n            'prefix_indexes' => true,\n            // 'encrypt' => env('DB_ENCRYPT', 'yes'),\n            // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),\n        ],\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Migration Repository Table\n    |--------------------------------------------------------------------------\n    |\n    | This table keeps track of all the migrations that have already run for\n    | your application. Using this information, we can determine which of\n    | the migrations on disk haven't actually been run in the database.\n    |\n    */\n\n    'migrations' => 'migrations',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Redis Databases\n    |--------------------------------------------------------------------------\n    |\n    | Redis is an open source, fast, and advanced key-value store that also\n    | provides a richer body of commands than a typical key-value system\n    | such as APC or Memcached. Laravel makes it easy to dig right in.\n    |\n    */\n\n    'redis' => [\n\n        'client' => env('REDIS_CLIENT', 'phpredis'),\n\n        'options' => [\n            'cluster' => env('REDIS_CLUSTER', 'redis'),\n            'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),\n        ],\n\n        'default' => [\n            'url' => env('REDIS_URL'),\n            'host' => env('REDIS_HOST', '127.0.0.1'),\n            'username' => env('REDIS_USERNAME'),\n            'password' => env('REDIS_PASSWORD'),\n            'port' => env('REDIS_PORT', '6379'),\n            'database' => env('REDIS_DB', '0'),\n        ],\n\n        'cache' => [\n            'url' => env('REDIS_URL'),\n            'host' => env('REDIS_HOST', '127.0.0.1'),\n            'username' => env('REDIS_USERNAME'),\n            'password' => env('REDIS_PASSWORD'),\n            'port' => env('REDIS_PORT', '6379'),\n            'database' => env('REDIS_CACHE_DB', '1'),\n        ],\n\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/config/filesystems.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Filesystem Disk\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the default filesystem disk that should be used\n    | by the framework. The \"local\" disk, as well as a variety of cloud\n    | based disks are available to your application. Just store away!\n    |\n    */\n\n    'default' => env('FILESYSTEM_DISK', 'local'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Filesystem Disks\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure as many filesystem \"disks\" as you wish, and you\n    | may even configure multiple disks of the same driver. Defaults have\n    | been set up for each driver as an example of the required values.\n    |\n    | Supported Drivers: \"local\", \"ftp\", \"sftp\", \"s3\"\n    |\n    */\n\n    'disks' => [\n\n        'local' => [\n            'driver' => 'local',\n            'root' => storage_path('app'),\n            'throw' => false,\n        ],\n\n        'public' => [\n            'driver' => 'local',\n            'root' => storage_path('app/public'),\n            'url' => env('APP_URL').'/storage',\n            'visibility' => 'public',\n            'throw' => false,\n        ],\n\n        's3' => [\n            'driver' => 's3',\n            'key' => env('AWS_ACCESS_KEY_ID'),\n            'secret' => env('AWS_SECRET_ACCESS_KEY'),\n            'region' => env('AWS_DEFAULT_REGION'),\n            'bucket' => env('AWS_BUCKET'),\n            'url' => env('AWS_URL'),\n            'endpoint' => env('AWS_ENDPOINT'),\n            'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),\n            'throw' => false,\n        ],\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Symbolic Links\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure the symbolic links that will be created when the\n    | `storage:link` Artisan command is executed. The array keys should be\n    | the locations of the links and the values should be their targets.\n    |\n    */\n\n    'links' => [\n        public_path('storage') => storage_path('app/public'),\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/config/hashing.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Hash Driver\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default hash driver that will be used to hash\n    | passwords for your application. By default, the bcrypt algorithm is\n    | used; however, you remain free to modify this option if you wish.\n    |\n    | Supported: \"bcrypt\", \"argon\", \"argon2id\"\n    |\n    */\n\n    'driver' => 'bcrypt',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Bcrypt Options\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the configuration options that should be used when\n    | passwords are hashed using the Bcrypt algorithm. This will allow you\n    | to control the amount of time it takes to hash the given password.\n    |\n    */\n\n    'bcrypt' => [\n        'rounds' => env('BCRYPT_ROUNDS', 10),\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Argon Options\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the configuration options that should be used when\n    | passwords are hashed using the Argon algorithm. These will allow you\n    | to control the amount of time it takes to hash the given password.\n    |\n    */\n\n    'argon' => [\n        'memory' => 65536,\n        'threads' => 1,\n        'time' => 4,\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/config/inertia.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Server Side Rendering\n    |--------------------------------------------------------------------------\n    |\n    | These options configures if and how Inertia uses Server Side Rendering\n    | to pre-render the initial visits made to your application's pages.\n    |\n    | You can specify a custom SSR bundle path, or omit it to let Inertia\n    | try and automatically detect it for you.\n    |\n    | Do note that enabling these options will NOT automatically make SSR work,\n    | as a separate rendering service needs to be available. To learn more,\n    | please visit https://inertiajs.com/server-side-rendering\n    |\n    */\n\n    'ssr' => [\n\n        'enabled' => (bool) env('INERTIA_SSR_ENABLED', true),\n\n        'url' => env('INERTIA_SSR_URL', 'http://127.0.0.1:13714'),\n\n        'ensure_bundle_exists' => (bool) env('INERTIA_SSR_ENSURE_BUNDLE_EXISTS', true),\n\n        // 'bundle' => base_path('bootstrap/ssr/ssr.mjs'),\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Pages\n    |--------------------------------------------------------------------------\n    |\n    | Set `ensure_pages_exist` to true if you want to enforce that Inertia page\n    | components exist on disk when rendering a page. This is useful for\n    | catching missing or misnamed components.\n    |\n    | The `page_paths` and `page_extensions` options define where to look\n    | for page components and which file extensions to consider.\n    |\n    */\n\n    'ensure_pages_exist' => false,\n\n    'page_paths' => [\n\n        resource_path('js/Pages'),\n\n    ],\n\n    'page_extensions' => [\n\n        'js',\n        'jsx',\n        'svelte',\n        'ts',\n        'tsx',\n        'vue',\n\n    ],\n\n    'use_script_element_for_initial_page' => (bool) env('INERTIA_USE_SCRIPT_ELEMENT_FOR_INITIAL_PAGE', false),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Testing\n    |--------------------------------------------------------------------------\n    |\n    | The values described here are used to locate Inertia components on the\n    | filesystem. For instance, when using `assertInertia`, the assertion\n    | attempts to locate the component as a file relative to any of the\n    | paths AND with any of the extensions specified here.\n    |\n    | Note: In a future release, the `page_paths` and `page_extensions`\n    | options below will be removed. The root-level options above\n    | will be used for both application and testing purposes.\n    |\n    */\n\n    'testing' => [\n\n        'ensure_pages_exist' => true,\n\n        'page_paths' => [\n\n            resource_path('js/Pages'),\n\n        ],\n\n        'page_extensions' => [\n\n            'js',\n            'jsx',\n            'svelte',\n            'ts',\n            'tsx',\n            'vue',\n\n        ],\n\n    ],\n\n    'history' => [\n\n        'encrypt' => (bool) env('INERTIA_ENCRYPT_HISTORY', true),\n\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/config/logging.php",
    "content": "<?php\n\nuse Monolog\\Handler\\NullHandler;\nuse Monolog\\Handler\\StreamHandler;\nuse Monolog\\Handler\\SyslogUdpHandler;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Log Channel\n    |--------------------------------------------------------------------------\n    |\n    | This option defines the default log channel that gets used when writing\n    | messages to the logs. The name specified in this option should match\n    | one of the channels defined in the \"channels\" configuration array.\n    |\n    */\n\n    'default' => env('LOG_CHANNEL', 'stack'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Deprecations Log Channel\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the log channel that should be used to log warnings\n    | regarding deprecated PHP and library features. This allows you to get\n    | your application ready for upcoming major versions of dependencies.\n    |\n    */\n\n    'deprecations' => [\n        'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),\n        'trace' => false,\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Log Channels\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure the log channels for your application. Out of\n    | the box, Laravel uses the Monolog PHP logging library. This gives\n    | you a variety of powerful log handlers / formatters to utilize.\n    |\n    | Available Drivers: \"single\", \"daily\", \"slack\", \"syslog\",\n    |                    \"errorlog\", \"monolog\",\n    |                    \"custom\", \"stack\"\n    |\n    */\n\n    'channels' => [\n        'stack' => [\n            'driver' => 'stack',\n            'channels' => ['single'],\n            'ignore_exceptions' => false,\n        ],\n\n        'single' => [\n            'driver' => 'single',\n            'path' => storage_path('logs/laravel.log'),\n            'level' => env('LOG_LEVEL', 'debug'),\n        ],\n\n        'daily' => [\n            'driver' => 'daily',\n            'path' => storage_path('logs/laravel.log'),\n            'level' => env('LOG_LEVEL', 'debug'),\n            'days' => 14,\n        ],\n\n        'slack' => [\n            'driver' => 'slack',\n            'url' => env('LOG_SLACK_WEBHOOK_URL'),\n            'username' => 'Laravel Log',\n            'emoji' => ':boom:',\n            'level' => env('LOG_LEVEL', 'critical'),\n        ],\n\n        'papertrail' => [\n            'driver' => 'monolog',\n            'level' => env('LOG_LEVEL', 'debug'),\n            'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class),\n            'handler_with' => [\n                'host' => env('PAPERTRAIL_URL'),\n                'port' => env('PAPERTRAIL_PORT'),\n                'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),\n            ],\n        ],\n\n        'stderr' => [\n            'driver' => 'monolog',\n            'level' => env('LOG_LEVEL', 'debug'),\n            'handler' => StreamHandler::class,\n            'formatter' => env('LOG_STDERR_FORMATTER'),\n            'with' => [\n                'stream' => 'php://stderr',\n            ],\n        ],\n\n        'syslog' => [\n            'driver' => 'syslog',\n            'level' => env('LOG_LEVEL', 'debug'),\n        ],\n\n        'errorlog' => [\n            'driver' => 'errorlog',\n            'level' => env('LOG_LEVEL', 'debug'),\n        ],\n\n        'null' => [\n            'driver' => 'monolog',\n            'handler' => NullHandler::class,\n        ],\n\n        'emergency' => [\n            'path' => storage_path('logs/laravel.log'),\n        ],\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/config/mail.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Mailer\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default mailer that is used to send any email\n    | messages sent by your application. Alternative mailers may be setup\n    | and used as needed; however, this mailer will be used by default.\n    |\n    */\n\n    'default' => env('MAIL_MAILER', 'smtp'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Mailer Configurations\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure all of the mailers used by your application plus\n    | their respective settings. Several examples have been configured for\n    | you and you are free to add your own as your application requires.\n    |\n    | Laravel supports a variety of mail \"transport\" drivers to be used while\n    | sending an e-mail. You will specify which one you are using for your\n    | mailers below. You are free to add additional mailers as required.\n    |\n    | Supported: \"smtp\", \"sendmail\", \"mailgun\", \"ses\",\n    |            \"postmark\", \"log\", \"array\", \"failover\"\n    |\n    */\n\n    'mailers' => [\n        'smtp' => [\n            'transport' => 'smtp',\n            'host' => env('MAIL_HOST', 'smtp.mailgun.org'),\n            'port' => env('MAIL_PORT', 587),\n            'encryption' => env('MAIL_ENCRYPTION', 'tls'),\n            'username' => env('MAIL_USERNAME'),\n            'password' => env('MAIL_PASSWORD'),\n            'timeout' => null,\n            'local_domain' => env('MAIL_EHLO_DOMAIN'),\n        ],\n\n        'ses' => [\n            'transport' => 'ses',\n        ],\n\n        'mailgun' => [\n            'transport' => 'mailgun',\n        ],\n\n        'postmark' => [\n            'transport' => 'postmark',\n        ],\n\n        'sendmail' => [\n            'transport' => 'sendmail',\n            'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'),\n        ],\n\n        'log' => [\n            'transport' => 'log',\n            'channel' => env('MAIL_LOG_CHANNEL'),\n        ],\n\n        'array' => [\n            'transport' => 'array',\n        ],\n\n        'failover' => [\n            'transport' => 'failover',\n            'mailers' => [\n                'smtp',\n                'log',\n            ],\n        ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Global \"From\" Address\n    |--------------------------------------------------------------------------\n    |\n    | You may wish for all e-mails sent by your application to be sent from\n    | the same address. Here, you may specify a name and address that is\n    | used globally for all e-mails that are sent by your application.\n    |\n    */\n\n    'from' => [\n        'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),\n        'name' => env('MAIL_FROM_NAME', 'Example'),\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Markdown Mail Settings\n    |--------------------------------------------------------------------------\n    |\n    | If you are using Markdown based email rendering, you may configure your\n    | theme and component paths here, allowing you to customize the design\n    | of the emails. Or, you may simply stick with the Laravel defaults!\n    |\n    */\n\n    'markdown' => [\n        'theme' => 'default',\n\n        'paths' => [\n            resource_path('views/vendor/mail'),\n        ],\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/config/queue.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Queue Connection Name\n    |--------------------------------------------------------------------------\n    |\n    | Laravel's queue API supports an assortment of back-ends via a single\n    | API, giving you convenient access to each back-end using the same\n    | syntax for every one. Here you may define a default connection.\n    |\n    */\n\n    'default' => env('QUEUE_CONNECTION', 'sync'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Queue Connections\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure the connection information for each server that\n    | is used by your application. A default configuration has been added\n    | for each back-end shipped with Laravel. You are free to add more.\n    |\n    | Drivers: \"sync\", \"database\", \"beanstalkd\", \"sqs\", \"redis\", \"null\"\n    |\n    */\n\n    'connections' => [\n\n        'sync' => [\n            'driver' => 'sync',\n        ],\n\n        'database' => [\n            'driver' => 'database',\n            'table' => 'jobs',\n            'queue' => 'default',\n            'retry_after' => 90,\n            'after_commit' => false,\n        ],\n\n        'beanstalkd' => [\n            'driver' => 'beanstalkd',\n            'host' => 'localhost',\n            'queue' => 'default',\n            'retry_after' => 90,\n            'block_for' => 0,\n            'after_commit' => false,\n        ],\n\n        'sqs' => [\n            'driver' => 'sqs',\n            'key' => env('AWS_ACCESS_KEY_ID'),\n            'secret' => env('AWS_SECRET_ACCESS_KEY'),\n            'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),\n            'queue' => env('SQS_QUEUE', 'default'),\n            'suffix' => env('SQS_SUFFIX'),\n            'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),\n            'after_commit' => false,\n        ],\n\n        'redis' => [\n            'driver' => 'redis',\n            'connection' => 'default',\n            'queue' => env('REDIS_QUEUE', 'default'),\n            'retry_after' => 90,\n            'block_for' => null,\n            'after_commit' => false,\n        ],\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Failed Queue Jobs\n    |--------------------------------------------------------------------------\n    |\n    | These options configure the behavior of failed queue job logging so you\n    | can control which database and table are used to store the jobs that\n    | have failed. You may change them to any database / table you wish.\n    |\n    */\n\n    'failed' => [\n        'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),\n        'database' => env('DB_CONNECTION', 'mysql'),\n        'table' => 'failed_jobs',\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/config/sanctum.php",
    "content": "<?php\n\nuse Laravel\\Sanctum\\Sanctum;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Stateful Domains\n    |--------------------------------------------------------------------------\n    |\n    | Requests from the following domains / hosts will receive stateful API\n    | authentication cookies. Typically, these should include your local\n    | and production domains which access your API via a frontend SPA.\n    |\n    */\n\n    'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(\n        '%s%s',\n        'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',\n        Sanctum::currentApplicationUrlWithPort()\n    ))),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Sanctum Guards\n    |--------------------------------------------------------------------------\n    |\n    | This array contains the authentication guards that will be checked when\n    | Sanctum is trying to authenticate a request. If none of these guards\n    | are able to authenticate the request, Sanctum will use the bearer\n    | token that's present on an incoming request for authentication.\n    |\n    */\n\n    'guard' => ['web'],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Expiration Minutes\n    |--------------------------------------------------------------------------\n    |\n    | This value controls the number of minutes until an issued token will be\n    | considered expired. If this value is null, personal access tokens do\n    | not expire. This won't tweak the lifetime of first-party sessions.\n    |\n    */\n\n    'expiration' => null,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Sanctum Middleware\n    |--------------------------------------------------------------------------\n    |\n    | When authenticating your first-party SPA with Sanctum you may need to\n    | customize some of the middleware Sanctum uses while processing the\n    | request. You may change the middleware listed below as required.\n    |\n    */\n\n    'middleware' => [\n        'verify_csrf_token' => App\\Http\\Middleware\\VerifyCsrfToken::class,\n        'encrypt_cookies' => App\\Http\\Middleware\\EncryptCookies::class,\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/config/services.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Third Party Services\n    |--------------------------------------------------------------------------\n    |\n    | This file is for storing the credentials for third party services such\n    | as Mailgun, Postmark, AWS and more. This file provides the de facto\n    | location for this type of information, allowing packages to have\n    | a conventional file to locate the various service credentials.\n    |\n    */\n\n    'mailgun' => [\n        'domain' => env('MAILGUN_DOMAIN'),\n        'secret' => env('MAILGUN_SECRET'),\n        'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),\n        'scheme' => 'https',\n    ],\n\n    'postmark' => [\n        'token' => env('POSTMARK_TOKEN'),\n    ],\n\n    'ses' => [\n        'key' => env('AWS_ACCESS_KEY_ID'),\n        'secret' => env('AWS_SECRET_ACCESS_KEY'),\n        'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/config/session.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Str;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Session Driver\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default session \"driver\" that will be used on\n    | requests. By default, we will use the lightweight native driver but\n    | you may specify any of the other wonderful drivers provided here.\n    |\n    | Supported: \"file\", \"cookie\", \"database\", \"apc\",\n    |            \"memcached\", \"redis\", \"dynamodb\", \"array\"\n    |\n    */\n\n    'driver' => env('SESSION_DRIVER', 'file'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Lifetime\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the number of minutes that you wish the session\n    | to be allowed to remain idle before it expires. If you want them\n    | to immediately expire on the browser closing, set that option.\n    |\n    */\n\n    'lifetime' => env('SESSION_LIFETIME', 120),\n\n    'expire_on_close' => false,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Encryption\n    |--------------------------------------------------------------------------\n    |\n    | This option allows you to easily specify that all of your session data\n    | should be encrypted before it is stored. All encryption will be run\n    | automatically by Laravel and you can use the Session like normal.\n    |\n    */\n\n    'encrypt' => false,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session File Location\n    |--------------------------------------------------------------------------\n    |\n    | When using the native session driver, we need a location where session\n    | files may be stored. A default has been set for you but a different\n    | location may be specified. This is only needed for file sessions.\n    |\n    */\n\n    'files' => storage_path('framework/sessions'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Database Connection\n    |--------------------------------------------------------------------------\n    |\n    | When using the \"database\" or \"redis\" session drivers, you may specify a\n    | connection that should be used to manage these sessions. This should\n    | correspond to a connection in your database configuration options.\n    |\n    */\n\n    'connection' => env('SESSION_CONNECTION'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Database Table\n    |--------------------------------------------------------------------------\n    |\n    | When using the \"database\" session driver, you may specify the table we\n    | should use to manage the sessions. Of course, a sensible default is\n    | provided for you; however, you are free to change this as needed.\n    |\n    */\n\n    'table' => 'sessions',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Cache Store\n    |--------------------------------------------------------------------------\n    |\n    | While using one of the framework's cache driven session backends you may\n    | list a cache store that should be used for these sessions. This value\n    | must match with one of the application's configured cache \"stores\".\n    |\n    | Affects: \"apc\", \"dynamodb\", \"memcached\", \"redis\"\n    |\n    */\n\n    'store' => env('SESSION_STORE'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Sweeping Lottery\n    |--------------------------------------------------------------------------\n    |\n    | Some session drivers must manually sweep their storage location to get\n    | rid of old sessions from storage. Here are the chances that it will\n    | happen on a given request. By default, the odds are 2 out of 100.\n    |\n    */\n\n    'lottery' => [2, 100],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Cookie Name\n    |--------------------------------------------------------------------------\n    |\n    | Here you may change the name of the cookie used to identify a session\n    | instance by ID. The name specified here will get used every time a\n    | new session cookie is created by the framework for every driver.\n    |\n    */\n\n    'cookie' => env(\n        'SESSION_COOKIE',\n        Str::slug(env('APP_NAME', 'laravel'), '_').'_session'\n    ),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Cookie Path\n    |--------------------------------------------------------------------------\n    |\n    | The session cookie path determines the path for which the cookie will\n    | be regarded as available. Typically, this will be the root path of\n    | your application but you are free to change this when necessary.\n    |\n    */\n\n    'path' => '/',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Cookie Domain\n    |--------------------------------------------------------------------------\n    |\n    | Here you may change the domain of the cookie used to identify a session\n    | in your application. This will determine which domains the cookie is\n    | available to in your application. A sensible default has been set.\n    |\n    */\n\n    'domain' => env('SESSION_DOMAIN'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | HTTPS Only Cookies\n    |--------------------------------------------------------------------------\n    |\n    | By setting this option to true, session cookies will only be sent back\n    | to the server if the browser has a HTTPS connection. This will keep\n    | the cookie from being sent to you when it can't be done securely.\n    |\n    */\n\n    'secure' => env('SESSION_SECURE_COOKIE'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | HTTP Access Only\n    |--------------------------------------------------------------------------\n    |\n    | Setting this value to true will prevent JavaScript from accessing the\n    | value of the cookie and the cookie will only be accessible through\n    | the HTTP protocol. You are free to modify this option if needed.\n    |\n    */\n\n    'http_only' => true,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Same-Site Cookies\n    |--------------------------------------------------------------------------\n    |\n    | This option determines how your cookies behave when cross-site requests\n    | take place, and can be used to mitigate CSRF attacks. By default, we\n    | will set this value to \"lax\" since this is a secure default value.\n    |\n    | Supported: \"lax\", \"strict\", \"none\", null\n    |\n    */\n\n    'same_site' => 'lax',\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/config/view.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | View Storage Paths\n    |--------------------------------------------------------------------------\n    |\n    | Most templating systems load templates from disk. Here you may specify\n    | an array of paths that should be checked for your views. Of course\n    | the usual Laravel view path has already been registered for you.\n    |\n    */\n\n    'paths' => [\n        resource_path('views'),\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Compiled View Path\n    |--------------------------------------------------------------------------\n    |\n    | This option determines where all the compiled Blade templates will be\n    | stored for your application. Typically, this is within the storage\n    | directory. However, as usual, you are free to change this value.\n    |\n    */\n\n    'compiled' => env(\n        'VIEW_COMPILED_PATH',\n        realpath(storage_path('framework/views'))\n    ),\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/database/.gitignore",
    "content": "*.sqlite*\n"
  },
  {
    "path": "playgrounds/svelte4/database/factories/UserFactory.php",
    "content": "<?php\n\nnamespace Database\\Factories;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\nuse Illuminate\\Support\\Str;\n\n/**\n * @extends \\Illuminate\\Database\\Eloquent\\Factories\\Factory<\\App\\Models\\User>\n */\nclass UserFactory extends Factory\n{\n    /**\n     * Define the model's default state.\n     *\n     * @return array<string, mixed>\n     */\n    public function definition()\n    {\n        return [\n            'name' => fake()->name(),\n            'email' => fake()->unique()->safeEmail(),\n            'email_verified_at' => now(),\n            'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password\n            'remember_token' => Str::random(10),\n        ];\n    }\n\n    /**\n     * Indicate that the model's email address should be unverified.\n     *\n     * @return static\n     */\n    public function unverified()\n    {\n        return $this->state(fn (array $attributes) => [\n            'email_verified_at' => null,\n        ]);\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/database/migrations/2014_10_12_000000_create_users_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('users', function (Blueprint $table) {\n            $table->id();\n            $table->string('name');\n            $table->string('email')->unique();\n            $table->timestamp('email_verified_at')->nullable();\n            $table->string('password');\n            $table->rememberToken();\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('users');\n    }\n};\n"
  },
  {
    "path": "playgrounds/svelte4/database/migrations/2014_10_12_100000_create_password_resets_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('password_resets', function (Blueprint $table) {\n            $table->string('email')->index();\n            $table->string('token');\n            $table->timestamp('created_at')->nullable();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('password_resets');\n    }\n};\n"
  },
  {
    "path": "playgrounds/svelte4/database/migrations/2019_08_19_000000_create_failed_jobs_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('failed_jobs', function (Blueprint $table) {\n            $table->id();\n            $table->string('uuid')->unique();\n            $table->text('connection');\n            $table->text('queue');\n            $table->longText('payload');\n            $table->longText('exception');\n            $table->timestamp('failed_at')->useCurrent();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('failed_jobs');\n    }\n};\n"
  },
  {
    "path": "playgrounds/svelte4/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('personal_access_tokens', function (Blueprint $table) {\n            $table->id();\n            $table->morphs('tokenable');\n            $table->string('name');\n            $table->string('token', 64)->unique();\n            $table->text('abilities')->nullable();\n            $table->timestamp('last_used_at')->nullable();\n            $table->timestamp('expires_at')->nullable();\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('personal_access_tokens');\n    }\n};\n"
  },
  {
    "path": "playgrounds/svelte4/database/seeders/DatabaseSeeder.php",
    "content": "<?php\n\nnamespace Database\\Seeders;\n\n// use Illuminate\\Database\\Console\\Seeds\\WithoutModelEvents;\nuse Illuminate\\Database\\Seeder;\n\nclass DatabaseSeeder extends Seeder\n{\n    /**\n     * Seed the application's database.\n     *\n     * @return void\n     */\n    public function run()\n    {\n        // \\App\\Models\\User::factory(10)->create();\n\n        // \\App\\Models\\User::factory()->create([\n        //     'name' => 'Test User',\n        //     'email' => 'test@example.com',\n        // ]);\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/init.sh",
    "content": "#!/bin/bash\nset -e\n\n# Install PHP dependencies via Composer\nif [ ! -d \"vendor\" ]; then\n    echo \"Installing PHP dependencies...\"\n    composer install\nelse\n    echo \"PHP dependencies already installed\"\nfi\n\n# Install Node.js dependencies via pnpm\nif [ ! -d \"node_modules\" ]; then\n    echo \"Installing Node.js dependencies...\"\n    pnpm install\nelse\n    echo \"Node.js dependencies already installed\"\nfi\n\n# Set up environment configuration\nif [ ! -f \".env\" ]; then\n    echo \"Creating environment configuration...\"\n    cp .env.example .env\n    php artisan key:generate\nelse\n    echo \"Environment configuration already exists\"\nfi\n\n# Set up SQLite database\nif [ ! -f \"database/database.sqlite\" ]; then\n    echo \"Creating SQLite database...\"\n    touch database/database.sqlite\n    echo \"Running fresh migrations with seed data...\"\n    php artisan migrate:fresh --seed\nelse\n    echo \"Database already exists\"\nfi\n\n# Ensure database is up to date\necho \"Running any pending migrations...\"\nphp artisan migrate\n"
  },
  {
    "path": "playgrounds/svelte4/lang/en/auth.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Authentication Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines are used during authentication for various\n    | messages that we need to display to the user. You are free to modify\n    | these language lines according to your application's requirements.\n    |\n    */\n\n    'failed' => 'These credentials do not match our records.',\n    'password' => 'The provided password is incorrect.',\n    'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/lang/en/pagination.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Pagination Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines are used by the paginator library to build\n    | the simple pagination links. You are free to change them to anything\n    | you want to customize your views to better match your application.\n    |\n    */\n\n    'previous' => '&laquo; Previous',\n    'next' => 'Next &raquo;',\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/lang/en/passwords.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Password Reset Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines are the default lines which match reasons\n    | that are given by the password broker for a password update attempt\n    | has failed, such as for an invalid token or invalid new password.\n    |\n    */\n\n    'reset' => 'Your password has been reset!',\n    'sent' => 'We have emailed your password reset link!',\n    'throttled' => 'Please wait before retrying.',\n    'token' => 'This password reset token is invalid.',\n    'user' => \"We can't find a user with that email address.\",\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/lang/en/validation.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Validation Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines contain the default error messages used by\n    | the validator class. Some of these rules have multiple versions such\n    | as the size rules. Feel free to tweak each of these messages here.\n    |\n    */\n\n    'accepted' => 'The :attribute must be accepted.',\n    'accepted_if' => 'The :attribute must be accepted when :other is :value.',\n    'active_url' => 'The :attribute is not a valid URL.',\n    'after' => 'The :attribute must be a date after :date.',\n    'after_or_equal' => 'The :attribute must be a date after or equal to :date.',\n    'alpha' => 'The :attribute must only contain letters.',\n    'alpha_dash' => 'The :attribute must only contain letters, numbers, dashes and underscores.',\n    'alpha_num' => 'The :attribute must only contain letters and numbers.',\n    'array' => 'The :attribute must be an array.',\n    'ascii' => 'The :attribute must only contain single-byte alphanumeric characters and symbols.',\n    'before' => 'The :attribute must be a date before :date.',\n    'before_or_equal' => 'The :attribute must be a date before or equal to :date.',\n    'between' => [\n        'array' => 'The :attribute must have between :min and :max items.',\n        'file' => 'The :attribute must be between :min and :max kilobytes.',\n        'numeric' => 'The :attribute must be between :min and :max.',\n        'string' => 'The :attribute must be between :min and :max characters.',\n    ],\n    'boolean' => 'The :attribute field must be true or false.',\n    'confirmed' => 'The :attribute confirmation does not match.',\n    'current_password' => 'The password is incorrect.',\n    'date' => 'The :attribute is not a valid date.',\n    'date_equals' => 'The :attribute must be a date equal to :date.',\n    'date_format' => 'The :attribute does not match the format :format.',\n    'decimal' => 'The :attribute must have :decimal decimal places.',\n    'declined' => 'The :attribute must be declined.',\n    'declined_if' => 'The :attribute must be declined when :other is :value.',\n    'different' => 'The :attribute and :other must be different.',\n    'digits' => 'The :attribute must be :digits digits.',\n    'digits_between' => 'The :attribute must be between :min and :max digits.',\n    'dimensions' => 'The :attribute has invalid image dimensions.',\n    'distinct' => 'The :attribute field has a duplicate value.',\n    'doesnt_end_with' => 'The :attribute may not end with one of the following: :values.',\n    'doesnt_start_with' => 'The :attribute may not start with one of the following: :values.',\n    'email' => 'The :attribute must be a valid email address.',\n    'ends_with' => 'The :attribute must end with one of the following: :values.',\n    'enum' => 'The selected :attribute is invalid.',\n    'exists' => 'The selected :attribute is invalid.',\n    'file' => 'The :attribute must be a file.',\n    'filled' => 'The :attribute field must have a value.',\n    'gt' => [\n        'array' => 'The :attribute must have more than :value items.',\n        'file' => 'The :attribute must be greater than :value kilobytes.',\n        'numeric' => 'The :attribute must be greater than :value.',\n        'string' => 'The :attribute must be greater than :value characters.',\n    ],\n    'gte' => [\n        'array' => 'The :attribute must have :value items or more.',\n        'file' => 'The :attribute must be greater than or equal to :value kilobytes.',\n        'numeric' => 'The :attribute must be greater than or equal to :value.',\n        'string' => 'The :attribute must be greater than or equal to :value characters.',\n    ],\n    'image' => 'The :attribute must be an image.',\n    'in' => 'The selected :attribute is invalid.',\n    'in_array' => 'The :attribute field does not exist in :other.',\n    'integer' => 'The :attribute must be an integer.',\n    'ip' => 'The :attribute must be a valid IP address.',\n    'ipv4' => 'The :attribute must be a valid IPv4 address.',\n    'ipv6' => 'The :attribute must be a valid IPv6 address.',\n    'json' => 'The :attribute must be a valid JSON string.',\n    'lowercase' => 'The :attribute must be lowercase.',\n    'lt' => [\n        'array' => 'The :attribute must have less than :value items.',\n        'file' => 'The :attribute must be less than :value kilobytes.',\n        'numeric' => 'The :attribute must be less than :value.',\n        'string' => 'The :attribute must be less than :value characters.',\n    ],\n    'lte' => [\n        'array' => 'The :attribute must not have more than :value items.',\n        'file' => 'The :attribute must be less than or equal to :value kilobytes.',\n        'numeric' => 'The :attribute must be less than or equal to :value.',\n        'string' => 'The :attribute must be less than or equal to :value characters.',\n    ],\n    'mac_address' => 'The :attribute must be a valid MAC address.',\n    'max' => [\n        'array' => 'The :attribute must not have more than :max items.',\n        'file' => 'The :attribute must not be greater than :max kilobytes.',\n        'numeric' => 'The :attribute must not be greater than :max.',\n        'string' => 'The :attribute must not be greater than :max characters.',\n    ],\n    'max_digits' => 'The :attribute must not have more than :max digits.',\n    'mimes' => 'The :attribute must be a file of type: :values.',\n    'mimetypes' => 'The :attribute must be a file of type: :values.',\n    'min' => [\n        'array' => 'The :attribute must have at least :min items.',\n        'file' => 'The :attribute must be at least :min kilobytes.',\n        'numeric' => 'The :attribute must be at least :min.',\n        'string' => 'The :attribute must be at least :min characters.',\n    ],\n    'min_digits' => 'The :attribute must have at least :min digits.',\n    'multiple_of' => 'The :attribute must be a multiple of :value.',\n    'not_in' => 'The selected :attribute is invalid.',\n    'not_regex' => 'The :attribute format is invalid.',\n    'numeric' => 'The :attribute must be a number.',\n    'password' => [\n        'letters' => 'The :attribute must contain at least one letter.',\n        'mixed' => 'The :attribute must contain at least one uppercase and one lowercase letter.',\n        'numbers' => 'The :attribute must contain at least one number.',\n        'symbols' => 'The :attribute must contain at least one symbol.',\n        'uncompromised' => 'The given :attribute has appeared in a data leak. Please choose a different :attribute.',\n    ],\n    'present' => 'The :attribute field must be present.',\n    'prohibited' => 'The :attribute field is prohibited.',\n    'prohibited_if' => 'The :attribute field is prohibited when :other is :value.',\n    'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.',\n    'prohibits' => 'The :attribute field prohibits :other from being present.',\n    'regex' => 'The :attribute format is invalid.',\n    'required' => 'The :attribute field is required.',\n    'required_array_keys' => 'The :attribute field must contain entries for: :values.',\n    'required_if' => 'The :attribute field is required when :other is :value.',\n    'required_if_accepted' => 'The :attribute field is required when :other is accepted.',\n    'required_unless' => 'The :attribute field is required unless :other is in :values.',\n    'required_with' => 'The :attribute field is required when :values is present.',\n    'required_with_all' => 'The :attribute field is required when :values are present.',\n    'required_without' => 'The :attribute field is required when :values is not present.',\n    'required_without_all' => 'The :attribute field is required when none of :values are present.',\n    'same' => 'The :attribute and :other must match.',\n    'size' => [\n        'array' => 'The :attribute must contain :size items.',\n        'file' => 'The :attribute must be :size kilobytes.',\n        'numeric' => 'The :attribute must be :size.',\n        'string' => 'The :attribute must be :size characters.',\n    ],\n    'starts_with' => 'The :attribute must start with one of the following: :values.',\n    'string' => 'The :attribute must be a string.',\n    'timezone' => 'The :attribute must be a valid timezone.',\n    'unique' => 'The :attribute has already been taken.',\n    'uploaded' => 'The :attribute failed to upload.',\n    'uppercase' => 'The :attribute must be uppercase.',\n    'url' => 'The :attribute must be a valid URL.',\n    'ulid' => 'The :attribute must be a valid ULID.',\n    'uuid' => 'The :attribute must be a valid UUID.',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Custom Validation Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify custom validation messages for attributes using the\n    | convention \"attribute.rule\" to name the lines. This makes it quick to\n    | specify a specific custom language line for a given attribute rule.\n    |\n    */\n\n    'custom' => [\n        'attribute-name' => [\n            'rule-name' => 'custom-message',\n        ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Custom Validation Attributes\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines are used to swap our attribute placeholder\n    | with something more reader friendly such as \"E-Mail Address\" instead\n    | of \"email\". This simply helps us make our message more expressive.\n    |\n    */\n\n    'attributes' => [],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte4/package.json",
    "content": "{\n  \"name\": \"@inertiajs/svelte4-playground\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"vite build && vite build --ssr\",\n    \"check\": \"svelte-check --tsconfig ./tsconfig.json\",\n    \"check:watch\": \"svelte-check --tsconfig ./tsconfig.json --watch\"\n  },\n  \"devDependencies\": {\n    \"@inertiajs/core\": \"workspace:*\",\n    \"@inertiajs/svelte\": \"workspace:*\",\n    \"@sveltejs/vite-plugin-svelte\": \"^3.1.2\",\n    \"@tailwindcss/vite\": \"^4.2.1\",\n    \"@tsconfig/svelte\": \"^5.0.8\",\n    \"axios\": \"^1.13.5\",\n    \"laravel-vite-plugin\": \"^1.3.0\",\n    \"lodash\": \"^4.17.23\",\n    \"svelte\": \"^4.2.20\",\n    \"svelte-check\": \"^4.4.4\",\n    \"tailwindcss\": \"^4.2.1\",\n    \"typescript\": \"^5.9.3\",\n    \"vite\": \"^5.4.21\"\n  }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/phpunit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:noNamespaceSchemaLocation=\"./vendor/phpunit/phpunit/phpunit.xsd\"\n         bootstrap=\"vendor/autoload.php\"\n         colors=\"true\"\n>\n    <testsuites>\n        <testsuite name=\"Unit\">\n            <directory suffix=\"Test.php\">./tests/Unit</directory>\n        </testsuite>\n        <testsuite name=\"Feature\">\n            <directory suffix=\"Test.php\">./tests/Feature</directory>\n        </testsuite>\n    </testsuites>\n    <coverage processUncoveredFiles=\"true\">\n        <include>\n            <directory suffix=\".php\">./app</directory>\n        </include>\n    </coverage>\n    <php>\n        <env name=\"APP_ENV\" value=\"testing\"/>\n        <env name=\"BCRYPT_ROUNDS\" value=\"4\"/>\n        <env name=\"CACHE_DRIVER\" value=\"array\"/>\n        <!-- <env name=\"DB_CONNECTION\" value=\"sqlite\"/> -->\n        <!-- <env name=\"DB_DATABASE\" value=\":memory:\"/> -->\n        <env name=\"MAIL_MAILER\" value=\"array\"/>\n        <env name=\"QUEUE_CONNECTION\" value=\"sync\"/>\n        <env name=\"SESSION_DRIVER\" value=\"array\"/>\n        <env name=\"TELESCOPE_ENABLED\" value=\"false\"/>\n    </php>\n</phpunit>\n"
  },
  {
    "path": "playgrounds/svelte4/public/.htaccess",
    "content": "<IfModule mod_rewrite.c>\n    <IfModule mod_negotiation.c>\n        Options -MultiViews -Indexes\n    </IfModule>\n\n    RewriteEngine On\n\n    # Handle Authorization Header\n    RewriteCond %{HTTP:Authorization} .\n    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]\n\n    # Redirect Trailing Slashes If Not A Folder...\n    RewriteCond %{REQUEST_FILENAME} !-d\n    RewriteCond %{REQUEST_URI} (.+)/$\n    RewriteRule ^ %1 [L,R=301]\n\n    # Send Requests To Front Controller...\n    RewriteCond %{REQUEST_FILENAME} !-d\n    RewriteCond %{REQUEST_FILENAME} !-f\n    RewriteRule ^ index.php [L]\n</IfModule>\n"
  },
  {
    "path": "playgrounds/svelte4/public/index.php",
    "content": "<?php\n\nuse Illuminate\\Contracts\\Http\\Kernel;\nuse Illuminate\\Http\\Request;\n\ndefine('LARAVEL_START', microtime(true));\n\n/*\n|--------------------------------------------------------------------------\n| Check If The Application Is Under Maintenance\n|--------------------------------------------------------------------------\n|\n| If the application is in maintenance / demo mode via the \"down\" command\n| we will load this file so that any pre-rendered content can be shown\n| instead of starting the framework, which could cause an exception.\n|\n*/\n\nif (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {\n    require $maintenance;\n}\n\n/*\n|--------------------------------------------------------------------------\n| Register The Auto Loader\n|--------------------------------------------------------------------------\n|\n| Composer provides a convenient, automatically generated class loader for\n| this application. We just need to utilize it! We'll simply require it\n| into the script here so we don't need to manually load our classes.\n|\n*/\n\nrequire __DIR__.'/../vendor/autoload.php';\n\n/*\n|--------------------------------------------------------------------------\n| Run The Application\n|--------------------------------------------------------------------------\n|\n| Once we have the application, we can handle the incoming request using\n| the application's HTTP kernel. Then, we will send the response back\n| to this client's browser, allowing them to enjoy our application.\n|\n*/\n\n$app = require_once __DIR__.'/../bootstrap/app.php';\n\n$kernel = $app->make(Kernel::class);\n\n$response = $kernel->handle(\n    $request = Request::capture()\n)->send();\n\n$kernel->terminate($request, $response);\n"
  },
  {
    "path": "playgrounds/svelte4/public/robots.txt",
    "content": "User-agent: *\nDisallow:\n"
  },
  {
    "path": "playgrounds/svelte4/resources/css/app.css",
    "content": "@import 'tailwindcss';\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Components/Image.svelte",
    "content": "<script>\n  import { onMount } from 'svelte'\n\n  export let id\n  export let url\n\n  let loaded = false\n  let imageElement\n\n  onMount(() => {\n    if (imageElement?.complete) {\n      loaded = true\n    }\n  })\n\n  function handleLoad() {\n    loaded = true\n  }\n</script>\n\n<div class=\"relative aspect-square overflow-hidden rounded-lg bg-gray-200\">\n  {#if !loaded}\n    <div class=\"absolute inset-0 animate-pulse bg-gray-300\" aria-hidden=\"true\" />\n  {/if}\n\n  <img\n    bind:this={imageElement}\n    src={url}\n    loading=\"lazy\"\n    decoding=\"async\"\n    class={`h-full w-full object-cover transition duration-500 ease-out ${\n      loaded ? 'blur-0 scale-100 opacity-100' : 'scale-105 opacity-0 blur-sm'\n    }`}\n    on:load={handleLoad}\n    alt=\"\"\n  />\n\n  <span class=\"pointer-events-none absolute bottom-2 left-2 rounded bg-black/50 px-2 py-1 text-sm text-white\">\n    {id}\n  </span>\n</div>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Components/Layout.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia } from '@inertiajs/svelte'\n\n  export let appName\n</script>\n\n<nav class=\"flex items-center space-x-6 bg-slate-800 px-10 py-6 text-white\">\n  <div class=\"rounded-lg bg-slate-700 px-4 py-1\">{appName}</div>\n  <!-- <Link href=\"/\" prefetch class=\"hover:underline\">Home</Link> -->\n  <!-- <Link href=\"/users\" prefetch cacheFor={['2s', '1m']} class=\"hover:underline\">Users</Link> -->\n  <!-- <Link href=\"/article\" prefetch=\"click\" class=\"hover:underline\">Article</Link> -->\n  <a href=\"/\" use:inertia={{ prefetch: true }} class=\"hover:underline\">Home</a>\n  <a href=\"/users\" use:inertia={{ prefetch: true, cacheFor: ['2s', '1m'] }} class=\"hover:underline\">Users</a>\n  <a href=\"/article\" use:inertia={{ prefetch: 'click' }} class=\"hover:underline\">Article</a>\n  <a href=\"/form\" use:inertia={{ prefetch: ['mount', 'click'] }} class=\"hover:underline\">useForm</a>\n  <a href=\"/form-component\" use:inertia class=\"hover:underline\">{'<Form>'}</a>\n  <a href=\"/form-component/precognition\" use:inertia class=\"hover:underline\">Precognition</a>\n  <button use:inertia={{ method: 'post', href: '/logout' }} type=\"button\" class=\"hover:underline\">Logout</button>\n  <a href=\"/goodbye\" use:inertia class=\"hover:underline\">External</a>\n  <a href=\"/async\" use:inertia class=\"hover:underline\">Async</a>\n  <a href=\"/defer\" use:inertia class=\"hover:underline\">Defer</a>\n  <a href=\"/poll\" use:inertia class=\"hover:underline\">Poll</a>\n  <a href=\"/photo-grid\" use:inertia class=\"hover:underline\">Photo Grid</a>\n  <a href=\"/photo-grid/horizontal\" use:inertia class=\"hover:underline\">Photo Row</a>\n  <a href=\"/data-table\" use:inertia class=\"hover:underline\">Table</a>\n  <a href=\"/once/1\" use:inertia class=\"hover:underline\">Once</a>\n  <a href=\"/flash\" use:inertia class=\"hover:underline\">Flash</a>\n</nav>\n\n<main class=\"px-10 py-8\">\n  <slot />\n</main>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Components/Spinner.svelte",
    "content": "<script>\n  let className = ''\n  export { className as class }\n</script>\n\n<svg class={`animate-spin text-black ${className}`} xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n  <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n  <path\n    class=\"opacity-75\"\n    fill=\"currentColor\"\n    d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n  ></path>\n</svg>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Components/TestGrid.svelte",
    "content": "<script>\n  let className = ''\n  export { className as class }\n</script>\n\n<div {...$$restProps} class=\"mt-6 grid grid-cols-3 gap-4 {className}\">\n  <slot />\n</div>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Components/TestGridItem.svelte",
    "content": "<script>\n  let className\n  export { className as class }\n</script>\n\n<div {...$$restProps} class=\"rounded-sm border border-gray-300 p-4 text-sm text-gray-500 {className}\">\n  {#if $$slots.title}\n    <div class=\"mb-2 font-bold\">\n      <slot name=\"title\" />\n    </div>\n  {/if}\n\n  <slot />\n</div>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/Article.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  export let appName\n</script>\n\n<svelte:head>\n  <title>Article - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Article</h1>\n\n<article class=\"max-w-3xl\">\n  <p class=\"my-6\">\n    Sunt culpa sit sunt enim aliquip. Esse ea ea quis voluptate. Enim consectetur aliqua ex ex magna cupidatat id minim\n    sit elit. Amet pariatur occaecat pariatur duis eiusmod dolore magna. Et commodo cupidatat in commodo elit cupidatat\n    minim qui id non enim ad. Culpa aliquip ad Lorem sit consectetur ullamco culpa duis nisi et fugiat mollit eiusmod.\n    Laboris voluptate veniam consequat proident in nulla irure velit.\n  </p>\n  <p class=\"my-6\">\n    Sit sint laboris sunt eiusmod ipsum laborum eiusmod amet commodo exercitation in duis magna. Proident sunt minim in\n    elit qui. Id pariatur commodo fugiat excepteur in deserunt Lorem ipsum occaecat est. Excepteur sit tempor ipsum ex\n    officia veniam enim amet velit fugiat mollit cillum. Incididunt aliqua nulla id occaecat nulla. Non ea ad est\n    occaecat deserunt officia qui commodo exercitation.\n  </p>\n  <p class=\"my-6\">\n    Voluptate laborum quis aliqua ullamco magna amet ullamco laborum qui cillum eu. Dolore dolore aliqua proident\n    proident sunt ipsum in. Enim velit dolore labore dolor quis incididunt duis culpa Lorem. Eu adipisicing non elit\n    fugiat voluptate labore ipsum dolore consectetur commodo. Et in et cillum duis consequat quis ex eu commodo. Eiusmod\n    aliqua excepteur consectetur eiusmod aute et consectetur sit pariatur dolore qui officia pariatur.\n  </p>\n  <p class=\"my-6\">\n    Non sunt eu mollit qui reprehenderit. Aute culpa anim voluptate do in esse duis laborum ad dolore. Ullamco nisi in\n    nostrud officia do. Duis pariatur officia id duis. Deserunt ad incididunt est sint consectetur reprehenderit mollit\n    est Lorem ea pariatur anim dolor adipisicing. Nostrud irure magna nostrud laboris aute sunt veniam laboris veniam\n    incididunt sit. Nulla proident ad aliqua fugiat culpa sunt est in dolor velit ad irure nulla.\n  </p>\n  <p class=\"my-6\">\n    Do aute laborum deserunt non laborum voluptate voluptate. Anim ut laborum magna sunt cupidatat irure. Cupidatat\n    fugiat minim sint cillum laborum excepteur irure id est irure ad occaecat adipisicing enim. Deserunt nulla anim\n    proident velit irure nostrud est est reprehenderit consequat pariatur qui. Fugiat Lorem sint eu laborum minim\n    pariatur cillum mollit nulla consequat ullamco ex. Ex consectetur ad ut irure fugiat occaecat aliqua exercitation\n    cillum ipsum anim dolore tempor.\n  </p>\n  <p class=\"my-6\">\n    Adipisicing consequat irure fugiat Lorem deserunt aliquip do cupidatat. Lorem labore elit ex qui nostrud qui cillum\n    sunt adipisicing occaecat. Sunt nostrud amet amet cupidatat fugiat Lorem quis nulla id cillum esse eu. Ullamco\n    aliqua dolore irure amet mollit anim velit dolore.\n  </p>\n  <p class=\"my-6\">\n    Veniam cupidatat ipsum ea officia ipsum nisi laborum culpa qui dolore. Aliqua Lorem nisi labore ea velit aliquip\n    irure excepteur eu. Laboris proident duis non labore sunt quis aute tempor laboris enim anim eiusmod.\n  </p>\n  <p class=\"my-6\">\n    Minim proident ut aliqua ea ut culpa fugiat ullamco nisi esse nostrud reprehenderit id. Id id ullamco velit anim\n    nisi magna Lorem tempor. Et veniam occaecat ut labore consequat fugiat duis.\n  </p>\n  <p class=\"my-6\">\n    Adipisicing ea consectetur adipisicing aute eu pariatur enim labore consequat occaecat consectetur minim nisi.\n    Cillum commodo sunt labore reprehenderit. Duis esse excepteur magna tempor eiusmod exercitation Lorem reprehenderit\n    excepteur pariatur. Esse cupidatat occaecat magna do aliquip Lorem. Consectetur adipisicing consequat dolore nostrud\n    esse eu cillum id commodo duis. Aliquip dolor cillum cupidatat fugiat.\n  </p>\n  <h2 id=\"far-down\" class=\"mt-8 text-2xl\">Far down</h2>\n  <p class=\"my-6\">\n    Ex eiusmod id est laborum sunt ex ea aute adipisicing ad magna deserunt duis. Nostrud velit dolore id commodo quis\n    enim fugiat. Sint non quis consectetur voluptate aliqua dolore ad voluptate nulla. Irure sit reprehenderit sint\n    laboris non elit. Duis minim nisi esse dolor. Sit ex in consequat non occaecat commodo irure et. Commodo qui ipsum\n    Lorem magna consequat consequat et minim eiusmod Lorem eiusmod cupidatat voluptate.\n  </p>\n</article>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/Async.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script lang=\"ts\">\n  import { router, useForm } from '@inertiajs/svelte'\n  import TestGrid from '../Components/TestGrid.svelte'\n  import TestGridItem from '../Components/TestGridItem.svelte'\n\n  export let appName\n  export let jonathan: boolean\n  export let taylor: boolean\n  export let joe: boolean\n\n  let reloadCount = 0\n  const form = useForm({ jonathan, taylor, joe })\n\n  $: console.log('watched reload count value', reloadCount)\n\n  function submit() {\n    router.post(\n      '/async/checkbox',\n      {\n        jonathan: $form.jonathan,\n        taylor: $form.taylor,\n        joe: $form.joe,\n      },\n      {\n        async: true,\n      },\n    )\n  }\n\n  function simulateConflict() {\n    router.reload({\n      only: ['sleep'],\n    })\n    router.visit('/sleepy/2')\n  }\n\n  function triggerVisitThenReload() {\n    router.visit('/sleepy/1')\n    router.reload({\n      only: ['sleep'],\n    })\n  }\n\n  function triggerLongReload() {\n    router.reload({\n      only: ['sleep'],\n      onFinish() {\n        console.log('finished reload')\n        reloadCount++\n        console.log('incremented reload count')\n      },\n    })\n  }\n\n  function triggerCancel() {\n    router.post(\n      '/sleepy/3',\n      {},\n      {\n        onCancelToken: (token) => {\n          console.log('onCancelToken')\n\n          setTimeout(() => {\n            console.log('CANCELLING!')\n            token.cancel()\n          }, 1000)\n        },\n      },\n    )\n  }\n\n  function triggerCancelAfterFinish() {\n    let cancelToken\n\n    router.post(\n      '/sleepy/1',\n      {},\n      {\n        onCancelToken: (token) => {\n          console.log('onCancelToken')\n\n          cancelToken = token\n        },\n        onFinish: () => {\n          console.log('onFinish')\n          console.log('CANCELLING!')\n          cancelToken.cancel()\n        },\n      },\n    )\n  }\n</script>\n\n<svelte:head>\n  <title>Async Request - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Async Request</h1>\n<p class=\"mt-6\">Reload Count: {reloadCount}</p>\n\n<TestGrid>\n  <TestGridItem class=\"space-y-4\">\n    <p>Trigger an async reload that takes a moment and immediately programmatically visit another page</p>\n    <button class=\"rounded-sm bg-green-600 px-4 py-2 text-white\" on:click={simulateConflict}>Reload → Visit</button>\n  </TestGridItem>\n\n  <TestGridItem class=\"space-y-4\">\n    <form on:change={submit}>\n      <label class=\"block\">\n        <input bind:checked={$form.jonathan} type=\"checkbox\" class=\"mr-2\" />\n        Jonathan\n      </label>\n      <label class=\"block\">\n        <input bind:checked={$form.taylor} type=\"checkbox\" class=\"mr-2\" />\n        Taylor\n      </label>\n      <label class=\"block\">\n        <input bind:checked={$form.joe} type=\"checkbox\" class=\"mr-2\" />\n        Joe\n      </label>\n    </form>\n    <p>You can check these on and off and then navigate to another page and the requests should still complete.</p>\n    <p>Toggling \"Joe\" on will cause a redirect to \"Article\", simulating an authorized action e.g.</p>\n  </TestGridItem>\n\n  <TestGridItem class=\"space-y-4\">\n    <p>Trigger programmatic visit and an async reload one after another</p>\n\n    <p>Reload should still happen but won't re-direct back to the reloaded component, we should respect the visit</p>\n\n    <button on:click={triggerVisitThenReload} class=\"rounded-sm bg-green-600 px-4 py-2 text-white\"\n      >Visit → Reload</button\n    >\n  </TestGridItem>\n\n  <TestGridItem class=\"space-y-4\">\n    <p>Simply trigger a 4 second reload so you can navigate or do whatever you'd like during it.</p>\n    <button on:click={triggerLongReload} class=\"rounded-sm bg-green-600 px-4 py-2 text-white\"\n      >Trigger Long Reload</button\n    >\n  </TestGridItem>\n\n  <TestGridItem class=\"space-y-4\">\n    <p>Trigger an automatic cancellation from the token.</p>\n    <button on:click={triggerCancel} class=\"rounded-sm bg-green-600 px-4 py-2 text-white\">Trigger Cancel</button>\n  </TestGridItem>\n\n  <TestGridItem class=\"space-y-4\">\n    <p>Trigger an automatic cancellation from the token after finishing request.</p>\n    <button on:click={triggerCancelAfterFinish} class=\"rounded-sm bg-green-600 px-4 py-2 text-white\">\n      Trigger Cancel After Finish\n    </button>\n  </TestGridItem>\n</TestGrid>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/DataTable.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import Spinner from '../Components/Spinner.svelte'\n\n  export let appName\n  export let users\n</script>\n\n<svelte:head>\n  <title>Data Table - {appName}</title>\n</svelte:head>\n\n<InfiniteScroll data=\"users\" class=\"mx-auto max-w-7xl px-8\" buffer={3000} itemsElement=\"tbody\">\n  <div slot=\"loading\">\n    <div class=\"flex justify-center py-16\">\n      <Spinner class=\"size-6 text-gray-400\" />\n    </div>\n  </div>\n\n  <div class=\"overflow-hidden rounded-2xl shadow ring-1 ring-gray-200\">\n    <table class=\"min-w-full\">\n      <thead class=\"bg-gray-50\">\n        <tr>\n          <th class=\"px-6 py-4 text-left text-sm font-semibold text-gray-900\">ID</th>\n          <th class=\"px-6 py-4 text-left text-sm font-semibold text-gray-900\">Name</th>\n        </tr>\n      </thead>\n      <tbody class=\"divide-y divide-gray-200 bg-white\">\n        {#each users.data as user (user.id)}\n          <tr class=\"transition-colors hover:bg-gray-50\">\n            <td class=\"px-6 py-4 text-sm text-gray-700\">{user.id}</td>\n            <td class=\"px-6 py-4 text-sm text-gray-700\">{user.name}</td>\n          </tr>\n        {/each}\n      </tbody>\n    </table>\n  </div>\n</InfiniteScroll>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/Defer.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script lang=\"ts\">\n  import { Deferred, WhenVisible } from '@inertiajs/svelte'\n  import Spinner from '../Components/Spinner.svelte'\n  import TestGrid from '../Components/TestGrid.svelte'\n  import TestGridItem from '../Components/TestGridItem.svelte'\n\n  type Users = {\n    id: number\n    name: string\n    email: string\n  }\n\n  type Organizations = {\n    id: number\n    name: string\n    url: string\n  }\n\n  type Foods = {\n    id: number\n    name: string\n  }\n\n  type Surprise = {\n    id: number\n    name: string\n  }\n\n  type Dogs = {\n    id: number\n    name: string\n  }\n\n  type Lunch = {\n    id: number\n    name: string\n  }\n\n  export let appName\n  export let users: Users[] = []\n  export let organizations: Organizations[] = []\n  export let foods: Foods[] = []\n  export let surprise: Surprise[] = []\n  export let dogs: Dogs[] = []\n  export let lunch: Lunch[] = []\n</script>\n\n<svelte:head>\n  <title>Async Request - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Deferred Props</h1>\n\n<div class=\"mt-6 rounded-sm border border-yellow-500 bg-yellow-200 p-4\">\n  <p>Page is loaded!</p>\n</div>\n\n<TestGrid>\n  <TestGridItem>\n    <Deferred data=\"users\">\n      <svelte:fragment slot=\"fallback\">\n        <p>Loading Users...</p>\n      </svelte:fragment>\n\n      <div>\n        {#each users as user (user.id)}\n          <p>#{user.id}: {user.name} ({user.email})</p>\n        {/each}\n      </div>\n    </Deferred>\n  </TestGridItem>\n\n  <TestGridItem>\n    <Deferred data=\"foods\">\n      <svelte:fragment slot=\"fallback\">\n        <p>Loading Foods...</p>\n      </svelte:fragment>\n\n      <div>\n        {#each foods as food (food.id)}\n          <p>#{food.id}: {food.name}</p>\n        {/each}\n      </div>\n    </Deferred>\n  </TestGridItem>\n\n  <TestGridItem>\n    <Deferred data=\"organizations\">\n      <svelte:fragment slot=\"fallback\">\n        <p>Loading Organizations...</p>\n      </svelte:fragment>\n\n      <div>\n        {#each organizations as org (org.id)}\n          <p>#{org.id}: {org.name} ({org.url})</p>\n        {/each}\n      </div>\n    </Deferred>\n  </TestGridItem>\n</TestGrid>\n\n<div class=\"mt-72\">\n  <WhenVisible data=\"surprise\">\n    <svelte:fragment slot=\"fallback\">\n      <div class=\"h-24\">\n        <div class=\"flex items-center\"><Spinner class=\"mr-2 size-5\" /> Loading Surprise...</div>\n      </div>\n    </svelte:fragment>\n\n    <div>\n      {#each surprise as s (s.id)}\n        <p>#{s.id}: {s.name}</p>\n      {/each}\n    </div>\n  </WhenVisible>\n</div>\n\n<div class=\"mt-72\">\n  <WhenVisible data={['dogs', 'lunch']} buffer={200}>\n    <svelte:fragment slot=\"fallback\">\n      <div class=\"h-24\">\n        <div class=\"flex items-center\"><Spinner class=\"mr-2 size-5\" /> Loading Dogs and Lunch...</div>\n      </div>\n    </svelte:fragment>\n\n    <div class=\"flex space-x-6\">\n      <div>\n        {#each dogs as dog (dog.id)}\n          <p>#{dog.id}: {dog.name}</p>\n        {/each}\n      </div>\n\n      <div>\n        {#each lunch as item (item.id)}\n          <p>#{item.id}: {item.name}</p>\n        {/each}\n      </div>\n    </div>\n  </WhenVisible>\n</div>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/Flash.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  import { Link, page, router } from '@inertiajs/svelte'\n\n  export let appName\n\n  let flashLog = []\n\n  router.on('flash', ({ detail: { flash } }) => {\n    flashLog = [...flashLog, flash]\n  })\n\n  const triggerFrontendFlash = () => {\n    router.flash('message', 'Hello from the frontend!')\n  }\n\n  const triggerMultipleFlash = () => {\n    router.flash({\n      message: 'Multiple items',\n      count: 42,\n    })\n  }\n\n  const clearLog = () => {\n    flashLog = []\n  }\n</script>\n\n<svelte:head>\n  <title>Flash - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Flash</h1>\n\n<div class=\"mt-6 space-y-6\">\n  <div>\n    <h2 class=\"text-lg font-semibold\">Current page.flash</h2>\n    <pre class=\"mt-2 rounded-sm bg-gray-100 p-3 text-sm\">{JSON.stringify($page.flash ?? 'null', null, 2)}</pre>\n  </div>\n\n  <div>\n    <h2 class=\"text-lg font-semibold\">Flash Event Log</h2>\n    <pre class=\"mt-2 rounded-sm bg-gray-100 p-3 text-sm\">{JSON.stringify(\n        flashLog.length ? flashLog : 'No flash events yet',\n        null,\n        2,\n      )}</pre>\n    {#if flashLog.length}\n      <button on:click={clearLog} class=\"mt-2 text-sm text-gray-500 underline\">Clear log</button>\n    {/if}\n  </div>\n\n  <div class=\"space-y-3\">\n    <h2 class=\"text-lg font-semibold\">Server-side Flash</h2>\n    <div>\n      <Link href=\"/flash/direct\" class=\"rounded-sm bg-slate-800 px-4 py-2 text-white\">Flash with render</Link>\n    </div>\n    <form on:submit|preventDefault={() => router.post('/flash/form')}>\n      <button type=\"submit\" class=\"rounded-sm bg-slate-800 px-4 py-2 text-white\">Flash with redirect</button>\n    </form>\n  </div>\n\n  <div class=\"space-y-3\">\n    <h2 class=\"text-lg font-semibold\">Frontend Flash</h2>\n    <div class=\"flex gap-3\">\n      <button on:click={triggerFrontendFlash} class=\"rounded-sm bg-slate-800 px-4 py-2 text-white\">\n        router.flash(key, value)\n      </button>\n      <button on:click={triggerMultipleFlash} class=\"rounded-sm bg-slate-800 px-4 py-2 text-white\">\n        router.flash(object)\n      </button>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/Form.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  import { useForm } from '@inertiajs/svelte'\n\n  export let appName\n\n  const form = useForm('NewUser', {\n    name: '',\n    company: '',\n    role: '',\n  })\n\n  function submit() {\n    $form.post('/user')\n  }\n</script>\n\n<svelte:head>\n  <title>Form - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Form</h1>\n\n<form on:submit|preventDefault={submit} class=\"mt-6 max-w-md space-y-4\">\n  {#if $form.isDirty}\n    <div class=\"my-5 rounded-sm border border-amber-100 bg-amber-50 p-3 text-amber-800\">There are unsaved changes!</div>\n  {/if}\n  <div>\n    <label class=\"block\" for=\"name\">Name:</label>\n    <input\n      type=\"text\"\n      bind:value={$form.name}\n      id=\"name\"\n      class=\"mt-1 w-full appearance-none rounded-sm border border-gray-200 px-2 py-1 shadow-xs\"\n    />\n    {#if $form.errors.name}\n      <div class=\"mt-2 text-sm text-red-600\">{$form.errors.name}</div>\n    {/if}\n  </div>\n  <div>\n    <label class=\"block\" for=\"company\">Company:</label>\n    <input\n      type=\"text\"\n      bind:value={$form.company}\n      id=\"company\"\n      class=\"mt-1 w-full appearance-none rounded-sm border border-gray-200 px-2 py-1 shadow-xs\"\n    />\n    {#if $form.errors.company}\n      <div class=\"mt-2 text-sm text-red-600\">{$form.errors.company}</div>\n    {/if}\n  </div>\n  <div>\n    <label class=\"block\" for=\"role\">Role:</label>\n    <select\n      bind:value={$form.role}\n      id=\"role\"\n      class=\"mt-1 w-full appearance-none rounded-sm border border-gray-200 px-2 py-1 shadow-xs\"\n    >\n      <option />\n      <option>User</option>\n      <option>Admin</option>\n      <option>Super</option>\n    </select>\n    {#if $form.errors.role}\n      <div class=\"mt-2 text-sm text-red-600\">{$form.errors.role}</div>\n    {/if}\n  </div>\n  <div class=\"flex gap-4\">\n    <button type=\"submit\" disabled={$form.processing} class=\"rounded-sm bg-slate-800 px-6 py-2 text-white\">\n      Submit\n    </button>\n    <button type=\"button\" on:click={() => $form.reset()}>Reset</button>\n  </div>\n</form>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/FormComponent.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script lang=\"ts\">\n  import { Form } from '@inertiajs/svelte'\n\n  export let appName\n  export let foo\n  export let bar\n  export let quux\n\n  let customHeaders = { 'X-Custom-Header': 'Demo-Value' }\n  let errorBag = 'custom-bag'\n</script>\n\n<svelte:head>\n  <title>Form Component - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Form Component</h1>\n\n<!-- Main Demo Form -->\n<Form\n  action=\"/form-component\"\n  method=\"post\"\n  headers={customHeaders}\n  {errorBag}\n  options={{\n    only: ['foo'],\n    reset: ['bar'],\n  }}\n  transform={(data) => ({ ...data, demo: 'data' })}\n  class=\"mt-6 max-w-2xl space-y-6\"\n  let:errors\n  let:hasErrors\n  let:processing\n  let:progress\n  let:wasSuccessful\n  let:recentlySuccessful\n  let:setError\n  let:clearErrors\n  let:isDirty\n  let:reset\n  let:submit\n>\n  <!-- Status Display -->\n  <div class=\"rounded border border-gray-200 bg-gray-50 p-4\">\n    <h3 class=\"mb-3 text-lg font-medium\">Form Status</h3>\n    <div class=\"grid grid-cols-2 gap-4 text-sm\">\n      <div>\n        isDirty: <span class=\"font-mono\" class:text-orange-600={isDirty} class:text-gray-500={!isDirty}>{isDirty}</span>\n      </div>\n      <div>\n        hasErrors: <span class=\"font-mono\" class:text-red-600={hasErrors} class:text-gray-500={!hasErrors}\n          >{hasErrors}</span\n        >\n      </div>\n      <div>\n        processing: <span class=\"font-mono\" class:text-blue-600={processing} class:text-gray-500={!processing}\n          >{processing}</span\n        >\n      </div>\n      <div>\n        wasSuccessful: <span class=\"font-mono\" class:text-green-600={wasSuccessful} class:text-gray-500={!wasSuccessful}\n          >{wasSuccessful}</span\n        >\n      </div>\n      <div>\n        recentlySuccessful: <span\n          class=\"font-mono\"\n          class:text-green-600={recentlySuccessful}\n          class:text-gray-500={!recentlySuccessful}>{recentlySuccessful}</span\n        >\n      </div>\n      {#if progress}\n        <div>\n          progress: <span class=\"font-mono text-blue-600\">{Math.round(progress.percentage)}%</span>\n        </div>\n      {/if}\n    </div>\n  </div>\n\n  {#if isDirty}\n    <div class=\"rounded border border-amber-100 bg-amber-50 p-3 text-amber-800\">There are unsaved changes!</div>\n  {/if}\n\n  <!-- Form Fields -->\n  <div class=\"space-y-4\">\n    <!-- Text Input -->\n    <div>\n      <label class=\"block font-medium\" for=\"name\">Name</label>\n      <input\n        type=\"text\"\n        name=\"name\"\n        id=\"name\"\n        placeholder=\"Enter your name\"\n        class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n        class:border-red-500={errors.name}\n      />\n      {#if errors.name}\n        <div class=\"mt-1 text-sm text-red-600\">{errors.name}</div>\n      {/if}\n    </div>\n\n    <!-- File Input -->\n    <div>\n      <label class=\"block font-medium\" for=\"avatar\">Avatar</label>\n      <input\n        type=\"file\"\n        name=\"avatar\"\n        id=\"avatar\"\n        class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n      />\n      {#if errors.avatar}\n        <div class=\"mt-1 text-sm text-red-600\">{errors.avatar}</div>\n      {/if}\n    </div>\n\n    <!-- Multiple Select -->\n    <div>\n      <label class=\"block font-medium\" for=\"skills\">Skills (Multiple)</label>\n      <select\n        name=\"skills[]\"\n        id=\"skills\"\n        multiple\n        class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n      >\n        <option value=\"vue\">Vue.js</option>\n        <option value=\"react\">React</option>\n        <option value=\"laravel\">Laravel</option>\n        <option value=\"tailwind\">Tailwind CSS</option>\n      </select>\n      {#if errors.skills}\n        <div class=\"mt-1 text-sm text-red-600\">{errors.skills}</div>\n      {/if}\n    </div>\n\n    <!-- Array Input (Tags) -->\n    <div>\n      <label class=\"block font-medium\">Tags</label>\n      <div class=\"mt-1 space-y-2\">\n        <input\n          type=\"text\"\n          name=\"tags[]\"\n          placeholder=\"Tag 1\"\n          class=\"w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n        />\n        {#if errors['tags.0']}\n          <div class=\"text-sm text-red-600\">{errors['tags.0']}</div>\n        {/if}\n        <input\n          type=\"text\"\n          name=\"tags[]\"\n          placeholder=\"Tag 2\"\n          class=\"w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n        />\n        {#if errors['tags.1']}\n          <div class=\"text-sm text-red-600\">{errors['tags.1']}</div>\n        {/if}\n      </div>\n    </div>\n\n    <!-- Nested Object Input -->\n    <div>\n      <label class=\"block font-medium\">Address</label>\n      <div class=\"mt-1 grid grid-cols-2 gap-2\">\n        <input\n          type=\"text\"\n          name=\"user[address][street]\"\n          placeholder=\"Street\"\n          class=\"appearance-none rounded border px-2 py-1 shadow-sm\"\n        />\n        <input\n          type=\"text\"\n          name=\"user[address][city]\"\n          placeholder=\"City\"\n          class=\"appearance-none rounded border px-2 py-1 shadow-sm\"\n        />\n      </div>\n    </div>\n  </div>\n\n  <!-- Action Buttons -->\n  <div class=\"flex flex-wrap gap-2\">\n    <button type=\"submit\" disabled={processing} class=\"rounded bg-slate-800 px-4 py-2 text-white disabled:opacity-50\">\n      Submit\n    </button>\n\n    <button type=\"button\" on:click={reset} class=\"rounded bg-gray-500 px-4 py-2 text-white\"> Reset </button>\n\n    <button\n      type=\"button\"\n      on:click={() => setError({ name: 'Name is required', avatar: 'Please select a file' })}\n      class=\"rounded bg-red-500 px-4 py-2 text-white\"\n    >\n      Set Errors\n    </button>\n\n    <button type=\"button\" on:click={() => clearErrors()} class=\"rounded bg-green-500 px-4 py-2 text-white\">\n      Clear Errors\n    </button>\n  </div>\n</Form>\n\n<!-- Form Configuration -->\n<div class=\"mt-8 max-w-2xl space-y-4\">\n  <h2 class=\"text-2xl\">Form Configuration</h2>\n\n  <div class=\"grid grid-cols-1 gap-6 md:grid-cols-2\">\n    <div class=\"rounded border border-gray-200 bg-gray-50 p-4\">\n      <div class=\"space-y-1 text-sm\">\n        <div>\n          <strong>Headers:</strong> <code class=\"text-xs\">{JSON.stringify(customHeaders)}</code>\n        </div>\n        <div>\n          <strong>Error Bag:</strong> <code>{errorBag}</code>\n        </div>\n        <div><strong>Only:</strong> <code>['foo']</code></div>\n        <div><strong>Reset:</strong> <code>['bar']</code></div>\n        <div><strong>Method:</strong> <code>POST</code></div>\n      </div>\n    </div>\n\n    <div class=\"space-y-3\">\n      <div>\n        <label class=\"block text-sm font-medium\">Error Bag</label>\n        <input\n          type=\"text\"\n          bind:value={errorBag}\n          class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n          placeholder=\"Error bag name\"\n        />\n      </div>\n\n      <div>\n        <label class=\"block text-sm font-medium\">Custom Header Value</label>\n        <input\n          type=\"text\"\n          bind:value={customHeaders['X-Custom-Header']}\n          class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n          placeholder=\"Header value\"\n        />\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/FormComponentPrecognition.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script lang=\"ts\">\n  import type { FormComponentMethods } from '@inertiajs/core'\n  import { Form } from '@inertiajs/svelte'\n\n  export let appName\n\n  let validateFiles = false\n  let validationTimeout = 1500\n\n  let callbacks = {\n    success: false,\n    error: false,\n    finish: false,\n  }\n\n  const validateWithCallbacks = (validate: FormComponentMethods['validate']) => {\n    callbacks = { success: false, error: false, finish: false }\n\n    validate({\n      onPrecognitionSuccess: () => (callbacks.success = true),\n      onValidationError: () => (callbacks.error = true),\n      onFinish: () => (callbacks.finish = true),\n      onBeforeValidation: (newReq) => {\n        if (newReq.data?.name === 'block') {\n          alert('Validation blocked by onBeforeValidation!')\n          return false\n        }\n      },\n    })\n  }\n</script>\n\n<svelte:head>\n  <title>Form Component Precognition - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Form Component Precognition</h1>\n\n<Form\n  action=\"/form-component/precognition\"\n  method=\"post\"\n  {validateFiles}\n  {validationTimeout}\n  class=\"mt-6 max-w-2xl space-y-6\"\n  let:errors\n  let:invalid\n  let:valid\n  let:validate\n  let:validating\n  let:touch\n  let:touched\n  let:processing\n>\n  <!-- Status Display -->\n  <div class=\"rounded border border-gray-200 bg-gray-50 p-4\">\n    <h3 class=\"mb-3 text-lg font-medium\">Validation Status (slot props)</h3>\n    <div class=\"grid grid-cols-2 gap-4 text-sm\">\n      <div>\n        validating:\n        <span class=\"font-mono\" class:text-blue-600={validating} class:text-gray-500={!validating}>{validating}</span>\n      </div>\n      <div>\n        processing:\n        <span class=\"font-mono\" class:text-blue-600={processing} class:text-gray-500={!processing}>{processing}</span>\n      </div>\n      <div>\n        touched():\n        <span class=\"font-mono\" class:text-orange-600={touched()} class:text-gray-500={!touched()}>{touched()}</span>\n      </div>\n      <div>\n        touched('name'):\n        <span class=\"font-mono\" class:text-orange-600={touched('name')} class:text-gray-500={!touched('name')}\n          >{touched('name')}</span\n        >\n      </div>\n      <div>\n        touched('email'):\n        <span class=\"font-mono\" class:text-orange-600={touched('email')} class:text-gray-500={!touched('email')}\n          >{touched('email')}</span\n        >\n      </div>\n    </div>\n  </div>\n\n  <!-- Form Fields -->\n  <div class=\"space-y-4\">\n    <!-- Name Input -->\n    <div>\n      <label class=\"block font-medium\" for=\"name\">Name</label>\n      <input\n        type=\"text\"\n        name=\"name\"\n        id=\"name\"\n        placeholder=\"Enter your name (min 3 chars)\"\n        on:blur={() => validate('name')}\n        class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n        class:border-red-500={invalid('name')}\n        class:border-green-500={valid('name')}\n      />\n      {#if invalid('name')}\n        <div class=\"mt-1 text-sm text-red-600\">{errors.name}</div>\n      {/if}\n      {#if valid('name')}\n        <div class=\"mt-1 text-sm text-green-600\">Valid!</div>\n      {/if}\n    </div>\n\n    <!-- Email Input -->\n    <div>\n      <label class=\"block font-medium\" for=\"email\">Email</label>\n      <input\n        type=\"email\"\n        name=\"email\"\n        id=\"email\"\n        placeholder=\"Enter your email\"\n        on:blur={() => validate('email')}\n        class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n        class:border-red-500={invalid('email')}\n        class:border-green-500={valid('email')}\n      />\n      {#if invalid('email')}\n        <div class=\"mt-1 text-sm text-red-600\">{errors.email}</div>\n      {/if}\n      {#if valid('email')}\n        <div class=\"mt-1 text-sm text-green-600\">Valid!</div>\n      {/if}\n    </div>\n\n    <!-- File Input -->\n    <div>\n      <label class=\"block font-medium\" for=\"avatar\">Avatar</label>\n      <input\n        type=\"file\"\n        name=\"avatar\"\n        id=\"avatar\"\n        on:change={() => validate('avatar')}\n        class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n        class:border-red-500={invalid('avatar')}\n        class:border-green-500={valid('avatar')}\n      />\n      {#if invalid('avatar')}\n        <div class=\"mt-1 text-sm text-red-600\">{errors.avatar}</div>\n      {/if}\n      {#if valid('avatar')}\n        <div class=\"mt-1 text-sm text-green-600\">Valid!</div>\n      {/if}\n    </div>\n  </div>\n\n  <!-- Action Buttons -->\n  <div class=\"flex flex-wrap gap-2\">\n    <button type=\"submit\" disabled={processing} class=\"rounded bg-slate-800 px-4 py-2 text-white disabled:opacity-50\">\n      Submit\n    </button>\n\n    <button\n      type=\"button\"\n      on:click={() => validate()}\n      class=\"rounded border border-slate-300 px-4 py-2 hover:bg-slate-50\"\n    >\n      Validate Touched\n    </button>\n\n    <button\n      type=\"button\"\n      on:click={() => touch('name')}\n      class=\"rounded border border-slate-300 px-4 py-2 hover:bg-slate-50\"\n    >\n      Touch Name\n    </button>\n\n    <button\n      type=\"button\"\n      on:click={() => validateWithCallbacks(validate)}\n      class=\"rounded border border-slate-300 px-4 py-2 hover:bg-slate-50\"\n    >\n      Validate with Callbacks\n    </button>\n  </div>\n\n  <!-- Callbacks Display -->\n  <div class=\"rounded border border-gray-200 bg-gray-50 p-4\">\n    <h3 class=\"mb-3 text-lg font-medium\">Validation Callbacks</h3>\n    <p class=\"mb-3 text-sm text-gray-600\">Enter \"block\" in the name field to test onBeforeValidation blocking.</p>\n    <div class=\"grid grid-cols-3 gap-4 text-sm\">\n      <div>\n        onPrecognitionSuccess:\n        <span class=\"font-mono\" class:text-green-600={callbacks.success} class:text-gray-500={!callbacks.success}\n          >{callbacks.success}</span\n        >\n      </div>\n      <div>\n        onValidationError:\n        <span class=\"font-mono\" class:text-red-600={callbacks.error} class:text-gray-500={!callbacks.error}\n          >{callbacks.error}</span\n        >\n      </div>\n      <div>\n        onFinish:\n        <span class=\"font-mono\" class:text-blue-600={callbacks.finish} class:text-gray-500={!callbacks.finish}\n          >{callbacks.finish}</span\n        >\n      </div>\n    </div>\n  </div>\n</Form>\n\n<!-- Configuration -->\n<div class=\"mt-8 max-w-2xl space-y-4\">\n  <h2 class=\"text-2xl\">Configuration</h2>\n\n  <div class=\"grid grid-cols-1 gap-6 md:grid-cols-2\">\n    <div class=\"rounded border border-gray-200 bg-gray-50 p-4\">\n      <div class=\"space-y-1 text-sm\">\n        <div>\n          <strong>Validate Files:</strong> <code>{validateFiles}</code>\n        </div>\n        <div>\n          <strong>Validation Timeout:</strong> <code>{validationTimeout}ms</code>\n        </div>\n        <div><strong>Method:</strong> <code>POST</code></div>\n      </div>\n    </div>\n\n    <div class=\"space-y-3\">\n      <div>\n        <label class=\"flex items-center gap-2\">\n          <input type=\"checkbox\" bind:checked={validateFiles} class=\"rounded\" />\n          <span class=\"text-sm\">Enable file validation</span>\n        </label>\n      </div>\n\n      <div>\n        <label class=\"block text-sm font-medium\">Validation Timeout</label>\n        <select bind:value={validationTimeout} class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\">\n          <option value={500}>500ms</option>\n          <option value={1000}>1000ms</option>\n          <option value={1500}>1500ms</option>\n          <option value={2000}>2000ms</option>\n        </select>\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/Home.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  import { inertia, router } from '@inertiajs/svelte'\n  export let appName\n</script>\n\n<svelte:head>\n  <title>Home - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Home</h1>\n\n<div class=\"mt-6 space-y-4\">\n  <div>\n    <a href=\"/article#far-down\" use:inertia class=\"text-blue-700 underline\">Link to bottom of article page</a>\n  </div>\n\n  <div>\n    <button type=\"button\" class=\"rounded-lg bg-blue-500 px-4 py-2 text-white\" on:click={() => router.clearHistory()}>\n      Clear history\n    </button>\n  </div>\n</div>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/InfiniteScroll.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script lang=\"ts\">\n  import { router, WhenVisible } from '@inertiajs/svelte'\n\n  export let appName\n  export let items: {\n    id: number\n    name: string\n  }[] = []\n  export let page: number\n  export let item_types: string[]\n  export let item_type: string\n\n  let currentItemType = item_type\n\n  function setItemType(type: string) {\n    currentItemType = type\n\n    router.reload({\n      data: {\n        item_type: type,\n        page: 1,\n      },\n      reset: ['items', 'page'],\n      preserveUrl: true,\n    })\n  }\n</script>\n\n<svelte:head>\n  <title>Infinite Scroll - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">And Beyond</h1>\n\n<div class=\"my-6 space-x-4\">\n  {#each item_types as type (type)}\n    <button class=\"rounded-lg bg-gray-200 px-4 py-1 hover:bg-gray-300\" on:click={() => setItemType(type)}>\n      {type}\n    </button>\n  {/each}\n</div>\n\n<div class=\"mt-6 w-full max-w-2xl overflow-hidden rounded-sm border border-gray-200 shadow-xs\">\n  <table class=\"w-full text-left\">\n    <thead>\n      <tr>\n        <th class=\"px-4 py-2\">Id</th>\n        <th class=\"px-4 py-2\">Name</th>\n      </tr>\n    </thead>\n    <tbody>\n      {#each items as item (item.id)}\n        <tr class=\"border-t border-gray-200\">\n          <td class=\"px-4 py-2\">{item.id}</td>\n          <td class=\"px-4 py-2\">{item.name}</td>\n        </tr>\n      {:else}\n        <tr>\n          <td colspan=\"2\" class=\"bg-gray-100 p-4 text-center\">Loading items...</td>\n        </tr>\n      {/each}\n    </tbody>\n  </table>\n\n  {#if items.length > 0}\n    <WhenVisible\n      always\n      buffer={200}\n      params={{\n        data: {\n          item_type: currentItemType,\n          page: page + 1,\n        },\n        only: ['items', 'page'],\n        preserveUrl: true,\n      }}\n    >\n      <div slot=\"fallback\" class=\"bg-gray-100 p-4 text-center\">Fetching more items...</div>\n      <div class=\"bg-gray-100 p-4 text-center\">Fetching more items...</div>\n    </WhenVisible>\n  {/if}\n</div>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/Login.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  export let appName\n</script>\n\n<svelte:head>\n  <title>Login - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Login</h1>\n\n<p class=\"mt-6\">You made a <code>POST</code> request to the logout endpoint and were redirected to the login page.</p>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/Once/First.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from './Layout.svelte'\n</script>\n\n<script lang=\"ts\">\n  export let foo: string\n  export let bar: string\n  export let baz1: string\n  export let qux: string | undefined\n</script>\n\n<svelte:head>\n  <title>Once Props: First Page</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Once Props: First Page</h1>\n<p>Foo: {foo}</p>\n<p>Bar: {bar}</p>\n<p>Baz: {baz1}</p>\n<p>Qux: {qux ?? 'Loading...'}</p>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/Once/Fourth.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from './Layout.svelte'\n</script>\n\n<script lang=\"ts\">\n  export let foo: string\n  export let bar: string\n  export let baz4: string\n  export let qux: string | undefined\n</script>\n\n<svelte:head>\n  <title>Once Props: Fourth Page</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Once Props: Fourth Page</h1>\n<p>Foo: {foo}</p>\n<p>Bar: {bar}</p>\n<p>Baz: {baz4}</p>\n<p>Qux: {qux ?? 'Loading...'}</p>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/Once/Layout.svelte",
    "content": "<script lang=\"ts\">\n  import { inertia, router } from '@inertiajs/svelte'\n  import MainLayout from '../../Components/Layout.svelte'\n\n  export let appName\n</script>\n\n<MainLayout {appName}>\n  <slot />\n  <a href=\"/once/1\" use:inertia class=\"text-blue-500 underline\">Go to First Page</a>\n  <a href=\"/once/2\" use:inertia class=\"ml-4 text-blue-500 underline\">Go to Second Page</a>\n  <a href=\"/once/3\" use:inertia class=\"ml-4 text-blue-500 underline\">Go to Third Page</a>\n  <a href=\"/once/4\" use:inertia={{ prefetch: 'mount' }} class=\"ml-4 text-blue-500 underline\">Go to Fourth Page</a>\n  <button on:click={() => router.reload({ only: ['foo'] })} class=\"ml-4 text-blue-500 underline\">Reload Foo</button>\n  <button on:click={() => router.reload({ only: ['bar'] })} class=\"ml-4 text-blue-500 underline\">Reload Bar</button>\n  <button\n    on:click={() => router.reload({ only: ['baz1', 'baz2', 'baz3', 'baz4'] })}\n    class=\"ml-4 text-blue-500 underline\"\n  >\n    Reload Baz\n  </button>\n  <button on:click={() => router.reload({ only: ['qux'] })} class=\"ml-4 text-blue-500 underline\">Reload Qux</button>\n</MainLayout>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/Once/Second.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from './Layout.svelte'\n</script>\n\n<script lang=\"ts\">\n  export let foo: string\n  export let bar: string\n  export let baz2: string\n  export let qux: string | undefined\n</script>\n\n<svelte:head>\n  <title>Once Props: Second Page</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Once Props: Second Page</h1>\n<p>Foo: {foo}</p>\n<p>Bar: {bar}</p>\n<p>Baz: {baz2}</p>\n<p>Qux: {qux ?? 'Loading...'}</p>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/Once/Third.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from './Layout.svelte'\n</script>\n\n<script lang=\"ts\">\n  export let foo: string\n  export let bar: string\n  export let baz3: string\n  export let qux: string | undefined\n</script>\n\n<svelte:head>\n  <title>Once Props: Third Page</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Once Props: Third Page</h1>\n<p>Foo: {foo}</p>\n<p>Bar: {bar}</p>\n<p>Baz: {baz3}</p>\n<p>Qux: {qux ?? 'Loading...'}</p>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/PhotoGrid.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import Image from '../Components/Image.svelte'\n  import Spinner from '../Components/Spinner.svelte'\n\n  export let appName\n  export let photos\n</script>\n\n<svelte:head>\n  <title>Photo Grid - {appName}</title>\n</svelte:head>\n\n<InfiniteScroll\n  data=\"photos\"\n  class=\"mx-auto grid max-w-7xl grid-cols-1 gap-6 px-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\"\n  buffer={1000}\n>\n  <div slot=\"loading\">\n    <div class=\"flex justify-center py-16\">\n      <Spinner class=\"size-6 text-gray-400\" />\n    </div>\n  </div>\n\n  {#each photos.data as photo (photo.id)}\n    <Image id={photo.id} url={photo.url} />\n  {/each}\n</InfiniteScroll>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/PhotoHorizontal.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import Image from '../Components/Image.svelte'\n  import Spinner from '../Components/Spinner.svelte'\n\n  export let appName\n  export let photos\n</script>\n\n<svelte:head>\n  <title>Photo Grid (Horizontal) - {appName}</title>\n</svelte:head>\n\n<div class=\"flex h-[200px] w-full overflow-x-scroll\">\n  <InfiniteScroll data=\"photos\" buffer={1000} class=\"flex h-[200px] gap-6\" preserveUrl onlyNext>\n    <div slot=\"loading\">\n      <div class=\"flex size-[200px] items-center justify-center\">\n        <Spinner class=\"size-6 text-gray-400\" />\n      </div>\n    </div>\n\n    {#each photos.data as photo (photo.id)}\n      <Image id={photo.id} url={photo.url} />\n    {/each}\n  </InfiniteScroll>\n</div>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/Poll.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  import { onMount } from 'svelte'\n  import { router, usePoll } from '@inertiajs/svelte'\n  import TestGrid from '../Components/TestGrid.svelte'\n  import TestGridItem from '../Components/TestGridItem.svelte'\n\n  export let appName\n  export let users = []\n  export let companies = []\n\n  let userPollCount = 0\n  let hookPollCount = 0\n  let companyPollCount = 0\n\n  const triggerAsyncRedirect = () => {\n    router.get(\n      '/elsewhere',\n      {},\n      {\n        only: ['something'],\n        async: true,\n      },\n    )\n  }\n\n  const { start: startHookPolling, stop } = usePoll(\n    2000,\n    {\n      only: ['asdf'],\n      onFinish() {\n        hookPollCount++\n      },\n    },\n    {\n      keepAlive: true,\n      autoStart: false,\n    },\n  )\n\n  onMount(() => {\n    setTimeout(() => {\n      startHookPolling()\n    }, 2000)\n\n    const { stop: stopUserPolling } = router.poll(\n      1000,\n      {\n        only: ['users'],\n        onFinish() {\n          userPollCount++\n        },\n      },\n      { keepAlive: true },\n    )\n\n    setTimeout(() => {\n      console.log('stopping user polling')\n      stopUserPolling()\n    }, 3000)\n  })\n</script>\n\n<svelte:head>\n  <title>Async Request - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Poll</h1>\n\n<TestGrid>\n  <TestGridItem>\n    <svelte:fragment slot=\"title\">\n      User Poll Request Count: {userPollCount}\n    </svelte:fragment>\n    <div>\n      {#each users as user}\n        <div>{user}</div>\n      {/each}\n    </div>\n  </TestGridItem>\n  <TestGridItem>\n    <svelte:fragment slot=\"title\">\n      Companies Poll Request Count: {companyPollCount}\n    </svelte:fragment>\n    <div>\n      {#each companies as company}\n        <div>{company}</div>\n      {/each}\n    </div>\n  </TestGridItem>\n  <TestGridItem>\n    <svelte:fragment slot=\"title\">\n      Hook Poll Request Count: {hookPollCount}\n    </svelte:fragment>\n  </TestGridItem>\n  <TestGridItem>\n    <button on:click={() => triggerAsyncRedirect()}>Trigger Async Redirect</button>\n  </TestGridItem>\n</TestGrid>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/User.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  export let appName\n  export let user\n</script>\n\n<svelte:head>\n  <title>User - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">User</h1>\n\n<p class=\"mt-6\">You successfully created a new user! Well not really, there is no persistence in this app.</p>\n\n<ul class=\"mt-6 space-y-2\">\n  <li><strong>Name:</strong> {user.name}</li>\n  <li><strong>Company:</strong> {user.company}</li>\n  <li><strong>Role:</strong> {user.role}</li>\n</ul>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/Pages/Users.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script lang=\"ts\">\n  import { usePrefetch } from '@inertiajs/svelte'\n\n  export let appName\n  export let users = []\n\n  const { lastUpdatedAt, isPrefetched, isPrefetching } = usePrefetch()\n</script>\n\n<svelte:head>\n  <title>Users - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Users</h1>\n\n<div class=\"my-6\">\n  Data last refreshed at:\n  {#if $lastUpdatedAt}\n    <span>{new Date($lastUpdatedAt)}</span>\n  {:else}\n    <span>N/A</span>\n  {/if}\n  {#if $isPrefetched}\n    <span> (Page is prefetched!)</span>\n  {/if}\n  {#if $isPrefetching}\n    <span class=\"text-red-500\">refreshing...</span>\n  {/if}\n</div>\n\n<div class=\"mt-6 w-full max-w-2xl overflow-hidden rounded-sm border border-gray-200 shadow-xs\">\n  <table class=\"w-full text-left\">\n    <thead>\n      <tr>\n        <th class=\"px-4 py-2\">Id</th>\n        <th class=\"px-4 py-2\">Name</th>\n        <th class=\"px-4 py-2\">Email</th>\n      </tr>\n    </thead>\n    <tbody>\n      {#each users as user (user.id)}\n        <tr class=\"border-t border-gray-200\">\n          <td class=\"px-4 py-2\">{user.id}</td>\n          <td class=\"px-4 py-2\">{user.name}</td>\n          <td class=\"px-4 py-2\">{user.email}</td>\n        </tr>\n      {/each}\n    </tbody>\n  </table>\n</div>\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/app.ts",
    "content": "import { createInertiaApp, type ResolvedComponent } from '@inertiajs/svelte'\n\ncreateInertiaApp({\n  resolve: (name) => {\n    const pages = import.meta.glob<ResolvedComponent>('./Pages/**/*.svelte', { eager: true })\n    return pages[`./Pages/${name}.svelte`]\n  },\n  setup({ el, App, props }) {\n    new App({ target: el, props, hydrate: true })\n  },\n})\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/ssr.ts",
    "content": "import { createInertiaApp, type ResolvedComponent } from '@inertiajs/svelte'\nimport createServer from '@inertiajs/svelte/server'\n\ncreateServer((page) =>\n  createInertiaApp({\n    page,\n    resolve: (name) => {\n      const pages = import.meta.glob<ResolvedComponent>('./Pages/**/*.svelte', { eager: true })\n      return pages[`./Pages/${name}.svelte`]\n    },\n    setup({ App, props }) {\n      return App.render(props)\n    },\n  }),\n)\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/types/globals.d.ts",
    "content": "import '@inertiajs/core'\n\ndeclare module '@inertiajs/core' {\n  export interface InertiaConfig {\n    sharedPageProps: {\n      appName: string\n    }\n  }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/resources/js/vite-env.d.ts",
    "content": "/// <reference types=\"svelte\" />\n/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "playgrounds/svelte4/resources/views/app.blade.php",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\" />\n    <meta name=\"csrf-token\" content=\"{{ csrf_token() }}\">\n    @vite(['resources/css/app.css', 'resources/js/app.ts'])\n    @inertiaHead\n  </head>\n  <body>\n    @inertia\n  </body>\n</html>\n"
  },
  {
    "path": "playgrounds/svelte4/routes/api.php",
    "content": "<?php\n\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Route;\n\n/*\n|--------------------------------------------------------------------------\n| API Routes\n|--------------------------------------------------------------------------\n|\n| Here is where you can register API routes for your application. These\n| routes are loaded by the RouteServiceProvider within a group which\n| is assigned the \"api\" middleware group. Enjoy building your API!\n|\n*/\n\nRoute::middleware('auth:sanctum')->get('/user', function (Request $request) {\n    return $request->user();\n});\n"
  },
  {
    "path": "playgrounds/svelte4/routes/channels.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Facades\\Broadcast;\n\n/*\n|--------------------------------------------------------------------------\n| Broadcast Channels\n|--------------------------------------------------------------------------\n|\n| Here you may register all of the event broadcasting channels that your\n| application supports. The given channel authorization callbacks are\n| used to check if an authenticated user can listen to the channel.\n|\n*/\n\nBroadcast::channel('App.Models.User.{id}', function ($user, $id) {\n    return (int) $user->id === (int) $id;\n});\n"
  },
  {
    "path": "playgrounds/svelte4/routes/console.php",
    "content": "<?php\n\nuse Illuminate\\Foundation\\Inspiring;\nuse Illuminate\\Support\\Facades\\Artisan;\n\n/*\n|--------------------------------------------------------------------------\n| Console Routes\n|--------------------------------------------------------------------------\n|\n| This file is where you may define all of your Closure based console\n| commands. Each Closure is bound to a command instance allowing a\n| simple approach to interacting with each command's IO methods.\n|\n*/\n\nArtisan::command('inspire', function () {\n    $this->comment(Inspiring::quote());\n})->purpose('Display an inspiring quote');\n"
  },
  {
    "path": "playgrounds/svelte4/routes/web.php",
    "content": "<?php\n\nuse App\\Http\\Requests\\PrecognitionFormRequest;\nuse Illuminate\\Foundation\\Http\\Middleware\\HandlePrecognitiveRequests;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Pagination\\LengthAwarePaginator;\nuse Illuminate\\Support\\Facades\\Cache;\nuse Illuminate\\Support\\Facades\\Route;\nuse Inertia\\Inertia;\n\n/*\n|--------------------------------------------------------------------------\n| Web Routes\n|--------------------------------------------------------------------------\n|\n| Here is where you can register web routes for your application. These\n| routes are loaded by the RouteServiceProvider within a group which\n| contains the \"web\" middleware group. Now create something great!\n|\n*/\n\nRoute::get('/', function () {\n    return inertia('Home');\n});\n\nRoute::get('/users', function () {\n    sleep(2);\n\n    return inertia('Users', [\n        'date' => now()->toDateTimeString(),\n        'users' => collect([\n            [\n                'id' => 1,\n                'name' => 'Jonathan Reinink',\n                'email' => 'jonathan@example.com',\n            ],\n            [\n                'id' => 2,\n                'name' => 'Adam Wathan',\n                'email' => 'adam@example.com',\n            ],\n            [\n                'id' => 3,\n                'name' => 'Taylor Otwell',\n                'email' => 'taylor@example.com',\n            ],\n            [\n                'id' => 4,\n                'name' => 'Jordan Pittman',\n                'email' => 'jordan@example.com',\n            ],\n            [\n                'id' => 5,\n                'name' => 'Jess Archer',\n                'email' => 'jess@example.com',\n            ],\n            [\n                'id' => 6,\n                'name' => 'Claudio Dekker',\n                'email' => 'claudio@example.com',\n            ],\n            [\n                'id' => 7,\n                'name' => 'Sebastian De Deyne',\n                'email' => 'sebastian@example.com',\n            ],\n            [\n                'id' => 8,\n                'name' => 'Pedro Borges',\n                'email' => 'pedro@example.com',\n            ],\n        ])->shuffle()->values(),\n    ]);\n});\n\nRoute::get('/users/2', function () {\n    sleep(2);\n\n    return inertia('Users', [\n        'date' => now()->toDateTimeString(),\n        'users' => [\n            [\n                'id' => 1,\n                'name' => 'Jonathan Reinink',\n                'email' => 'jonathan@example.com',\n            ],\n            [\n                'id' => 2,\n                'name' => 'Adam Wathan',\n                'email' => 'adam@example.com',\n            ],\n            [\n                'id' => 3,\n                'name' => 'Taylor Otwell',\n                'email' => 'taylor@example.com',\n            ],\n            [\n                'id' => 4,\n                'name' => 'Jordan Pittman',\n                'email' => 'jordan@example.com',\n            ],\n            [\n                'id' => 5,\n                'name' => 'Jess Archer',\n                'email' => 'jess@example.com',\n            ],\n            [\n                'id' => 6,\n                'name' => 'Claudio Dekker',\n                'email' => 'claudio@example.com',\n            ],\n            [\n                'id' => 7,\n                'name' => 'Sebastian De Deyne',\n                'email' => 'sebastian@example.com',\n            ],\n            [\n                'id' => 8,\n                'name' => 'Pedro Borges',\n                'email' => 'pedro@example.com',\n            ],\n        ],\n    ]);\n});\n\nRoute::get('/article', function () {\n    Inertia::encryptHistory();\n\n    return inertia('Article');\n});\n\nRoute::get('/form', function () {\n    return inertia('Form');\n});\n\nRoute::post('/user', function () {\n    return inertia('User', [\n        'user' => request()->validate([\n            'name' => ['required'],\n            'company' => ['required'],\n            'role' => ['required', 'in:User,Admin,Super'],\n        ]),\n    ]);\n});\n\nRoute::get('/login', function () {\n    return inertia('Login');\n});\n\nRoute::get('/async', function () {\n    return inertia('Async', [\n        'sleep' => Inertia::lazy(function () {\n            sleep(4);\n        }),\n        'jonathan' => Cache::get('jonathan', false),\n        'taylor' => Cache::get('taylor', false),\n        'joe' => Cache::get('joe', false),\n    ]);\n});\n\n// @deprecated - We now have a InfiniteScroll component and Inertia::scroll() method...\nRoute::get('/infinite-scroll', function () {\n    $page = request()->integer('page', 1);\n    $perPage = 25;\n    $start = ($page - 1) * $perPage;\n    $end = $start + $perPage - 1;\n    $itemTypes = ['user', 'food', 'animal', 'plant'];\n    $itemType = request()->input('item_type', $itemTypes[0]);\n\n    return inertia('InfiniteScroll', [\n        'items' => Inertia::defer(\n            function () use ($start, $end, $itemType) {\n                sleep(1);\n\n                return collect(range($start, $end))->map(fn ($i) => [\n                    'id' => $i,\n                    'name' => ucwords($itemType).' '.$i,\n                ])->toArray();\n            }\n        )->merge(),\n        'page' => $page,\n        'item_type' => $itemType,\n        'item_types' => $itemTypes,\n    ]);\n});\n\nRoute::post('/async/checkbox', function () {\n    sleep(2);\n    $previousJoe = Cache::get('joe', false);\n\n    Cache::put('jonathan', request('jonathan'), 10);\n    Cache::put('taylor', request('taylor'), 10);\n    Cache::put('joe', request('joe'), 10);\n\n    if (! $previousJoe && request()->boolean('joe')) {\n        return redirect('article');\n    }\n\n    return redirect('/async');\n});\n\nRoute::get('/defer', function () {\n    info('defer route');\n\n    return inertia('Defer', [\n        'users' => Inertia::defer(function () {\n            sleep(1);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => 'Jonathan Reinink',\n                    'email' => 'hello@reinink.com',\n                ],\n                [\n                    'id' => 2,\n                    'name' => 'Taylor Otwell',\n                    'email' => 'howdy@otwell.biz',\n                ],\n                [\n                    'id' => 3,\n                    'name' => 'Joe Tannenbaum',\n                    'email' => 'yo@tannenbaum.edu',\n                ],\n            ];\n        }, 'u'),\n        'foods' => Inertia::defer(function () {\n            sleep(3);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => 'Pizza',\n                ],\n                [\n                    'id' => 2,\n                    'name' => 'Tacos',\n                ],\n                [\n                    'id' => 3,\n                    'name' => 'Sushi',\n                ],\n            ];\n        }, 'f'),\n        'organizations' => Inertia::defer(function () {\n            sleep(2);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => 'InertiaJS',\n                    'url' => 'https://inertiajs.com',\n                ],\n                [\n                    'id' => 2,\n                    'name' => 'Laravel',\n                    'url' => 'https://laravel.com',\n                ],\n                [\n                    'id' => 3,\n                    'name' => 'VueJS',\n                    'url' => 'https://vuejs.org',\n                ],\n            ];\n        }, 'o'),\n        'surprise' => Inertia::optional(function () {\n            sleep(2);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => 'Surprise!',\n                ],\n                [\n                    'id' => 2,\n                    'name' => 'Aha!',\n                ],\n                [\n                    'id' => 3,\n                    'name' => 'Gotcha!',\n                ],\n                [\n                    'id' => 4,\n                    'name' => '👋!',\n                ],\n            ];\n        }),\n        'dogs' => Inertia::optional(function () {\n            sleep(1);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => '🐕',\n                ],\n                [\n                    'id' => 2,\n                    'name' => '🐩',\n                ],\n                [\n                    'id' => 3,\n                    'name' => '🐶',\n                ],\n            ];\n        }),\n        'lunch' => Inertia::optional(function () {\n            sleep(1);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => '🍔',\n                ],\n                [\n                    'id' => 2,\n                    'name' => '🍟',\n                ],\n                [\n                    'id' => 3,\n                    'name' => '🥤',\n                ],\n            ];\n        }),\n    ]);\n});\n\nRoute::get('/goodbye', function () {\n    return Inertia::location('https://inertiajs.com/redirects');\n});\n\nRoute::get('/poll', function () {\n    return inertia('Poll', [\n        'users' => collect([\n            'Jonathan Reinink',\n            'Taylor Otwell',\n            'Joe Tannenbaum',\n            'Jess Archer',\n            'Claudio Dekker',\n            'Sebastian De Deyne',\n            'Pedro Borges',\n        ])->shuffle()->take(3)->values(),\n        'companies' => collect([\n            'InertiaJS',\n            'Laravel',\n            'VueJS',\n            'Tailwind CSS',\n            'AlpineJS',\n            'Livewire',\n            'Spatie',\n        ])->shuffle()->take(3)->values(),\n    ]);\n});\n\nRoute::get('/elsewhere', function () {\n    return inertia('Users');\n});\n\nRoute::get('/sleepy/{duration}', function ($duration) {\n    sleep($duration);\n\n    return inertia('Users');\n});\n\nRoute::post('/sleepy/{duration}', function ($duration) {\n    sleep($duration);\n\n    return inertia('Article');\n});\n\nRoute::post('/logout', function () {\n    return redirect('/login');\n});\n\nRoute::get('/form-component', function () {\n    return inertia('FormComponent', [\n        'foo' => fn () => now()->getTimestampMs(),\n        'bar' => fn () => now()->getTimestampMs(),\n        'quux' => fn () => now()->getTimestampMs(),\n    ]);\n});\n\nRoute::post('/form-component', function () {\n    $data = request()->validateWithBag('custom-bag', [\n        'name' => ['required', 'string', 'max:255'],\n        'avatar' => ['nullable', 'file', 'image', 'max:2048'],\n        'skills' => ['nullable', 'array', 'min:2'],\n        'skills.*' => ['string', 'in:vue,react,laravel,tailwind'],\n        'tags' => ['nullable', 'array'],\n        'tags.*' => ['string', 'max:50'],\n        'user.address.street' => ['nullable', 'string', 'max:255'],\n        'user.address.city' => ['nullable', 'string', 'max:255'],\n    ]);\n\n    // Simulate file upload progress\n    if (request()->hasFile('avatar')) {\n        sleep(1);\n    }\n\n    return back();\n});\n\nRoute::get('/form-component/precognition', function () {\n    return inertia('FormComponentPrecognition');\n});\n\nRoute::post('/form-component/precognition', function (PrecognitionFormRequest $request) {\n    $data = $request->validated();\n\n    // dd($data);\n\n    return back();\n})->middleware([HandlePrecognitiveRequests::class]);\n\nRoute::get('/photo-grid/{horizontal?}', function ($horizontal = null) {\n    if (request()->header('X-Inertia-Partial-Component')) {\n        // Simulate latency for partial reloads\n        usleep(250_000);\n    }\n\n    $perPage = 24;\n    $pages = 30;\n    $total = $perPage * $pages;\n    $page = request()->integer('page', 1);\n\n    $photos = collect()\n        ->range(1, $total)\n        ->forPage($page, $perPage)\n        ->map(fn ($i) => [\n            'id' => $i,\n            'url' => \"https://picsum.photos/id/{$i}/300/300\",\n        ])\n        ->pipe(fn ($photos) => new LengthAwarePaginator(\n            $photos->values(),\n            $total,\n            $perPage,\n            $page,\n        ));\n\n    return inertia($horizontal ? 'PhotoHorizontal' : 'PhotoGrid', [\n        'photos' => Inertia::scroll($photos),\n    ]);\n});\n\nRoute::get('/data-table', function () {\n    if (request()->header('X-Inertia-Partial-Component')) {\n        // Simulate latency for partial reloads\n        usleep(500_000);\n    }\n\n    $perPage = 200;\n    $pages = 30;\n    $total = $perPage * $pages;\n    $page = request()->integer('page', 1);\n\n    $users = collect()\n        ->range(1, $total)\n        ->forPage($page, $perPage)\n        ->map(fn ($i) => [\n            'id' => $i,\n            'name' => \"User {$i}\",\n        ])\n        ->pipe(fn ($photos) => new LengthAwarePaginator(\n            $photos->values(),\n            $total,\n            $perPage,\n            $page,\n        ));\n\n    return inertia('DataTable', [\n        'users' => Inertia::scroll($users),\n    ]);\n});\n\nRoute::get('/once/{page}', function (int $page) {\n    $component = match ($page) {\n        1 => 'Once/First',\n        2 => 'Once/Second',\n        3 => 'Once/Third',\n        4 => 'Once/Fourth',\n        default => abort(404),\n    };\n\n    return inertia($component, [\n        'foo' => Inertia::once(fn () => 'foo value: '.now()->getTimestampMs())->fresh($page === 3),\n        'bar' => Inertia::once(fn () => 'bar value: '.now()->getTimestampMs())->until(10),\n        'baz' . $page => Inertia::once(fn () => 'baz value: '.now()->getTimestampMs())->as('baz'),\n        'qux' => Inertia::defer(fn () => 'qux value: '.now()->getTimestampMs())->once(),\n    ]);\n});\n\nRoute::get('/flash', function () {\n    return inertia('Flash');\n});\n\nRoute::get('/flash/direct', function () {\n    return Inertia::flash('message', 'Sent with render!')->render('Flash');\n});\n\nRoute::post('/flash/form', function () {\n    return Inertia::flash('message', 'Sent with redirect!')->back();\n});\n"
  },
  {
    "path": "playgrounds/svelte4/storage/app/.gitignore",
    "content": "*\n!public/\n!.gitignore\n"
  },
  {
    "path": "playgrounds/svelte4/storage/framework/.gitignore",
    "content": "compiled.php\nconfig.php\ndown\nevents.scanned.php\nmaintenance.php\nroutes.php\nroutes.scanned.php\nschedule-*\nservices.json\n"
  },
  {
    "path": "playgrounds/svelte4/storage/framework/cache/.gitignore",
    "content": "*\n!data/\n!.gitignore\n"
  },
  {
    "path": "playgrounds/svelte4/storage/framework/sessions/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/svelte4/storage/framework/testing/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/svelte4/storage/framework/views/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/svelte4/storage/logs/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/svelte4/svelte.config.js",
    "content": "import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'\n\nconst config = {\n  // Consult https://kit.svelte.dev/docs/integrations#preprocessors\n  // for more information about preprocessors\n  preprocess: vitePreprocess(),\n}\n\nexport default config\n"
  },
  {
    "path": "playgrounds/svelte4/tests/CreatesApplication.php",
    "content": "<?php\n\nnamespace Tests;\n\nuse Illuminate\\Contracts\\Console\\Kernel;\n\ntrait CreatesApplication\n{\n    /**\n     * Creates the application.\n     *\n     * @return \\Illuminate\\Foundation\\Application\n     */\n    public function createApplication()\n    {\n        $app = require __DIR__.'/../bootstrap/app.php';\n\n        $app->make(Kernel::class)->bootstrap();\n\n        return $app;\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/tests/Feature/ExampleTest.php",
    "content": "<?php\n\nnamespace Tests\\Feature;\n\n// use Illuminate\\Foundation\\Testing\\RefreshDatabase;\nuse Tests\\TestCase;\n\nclass ExampleTest extends TestCase\n{\n    /**\n     * A basic test example.\n     *\n     * @return void\n     */\n    public function test_the_application_returns_a_successful_response()\n    {\n        $response = $this->get('/');\n\n        $response->assertStatus(200);\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/tests/TestCase.php",
    "content": "<?php\n\nnamespace Tests;\n\nuse Illuminate\\Foundation\\Testing\\TestCase as BaseTestCase;\n\nabstract class TestCase extends BaseTestCase\n{\n    use CreatesApplication;\n}\n"
  },
  {
    "path": "playgrounds/svelte4/tests/Unit/ExampleTest.php",
    "content": "<?php\n\nnamespace Tests\\Unit;\n\nuse PHPUnit\\Framework\\TestCase;\n\nclass ExampleTest extends TestCase\n{\n    /**\n     * A basic test example.\n     *\n     * @return void\n     */\n    public function test_that_true_is_true()\n    {\n        $this->assertTrue(true);\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte4/tsconfig.json",
    "content": "{\n  \"extends\": \"@tsconfig/svelte/tsconfig.json\",\n  \"compilerOptions\": {\n    \"allowJs\": true,\n    \"checkJs\": true,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"resolveJsonModule\": true,\n    \"skipLibCheck\": true,\n    \"sourceMap\": true,\n    \"strict\": true,\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"node\",\n    \"paths\": {\n      \"@inertiajs/svelte/server\": [\"../../node_modules/@inertiajs/svelte/dist/server\"]\n    }\n  },\n  \"include\": [\n    \"resources/**/*.d.ts\",\n    \"resources/**/*.ts\",\n    \"resources/**/*.js\",\n    \"resources/**/*.svelte\",\n    \"*.config.js\",\n    \"*.config.cjs\"\n  ]\n}\n"
  },
  {
    "path": "playgrounds/svelte4/vite.config.js",
    "content": "import { svelte } from '@sveltejs/vite-plugin-svelte'\nimport tailwindcss from '@tailwindcss/vite'\nimport laravel from 'laravel-vite-plugin'\nimport { defineConfig } from 'vite'\n\nexport default defineConfig({\n  build: {\n    minify: false,\n  },\n  plugins: [\n    laravel({\n      input: ['resources/css/app.css', 'resources/js/app.ts'],\n      ssr: 'resources/js/ssr.ts',\n      refresh: true,\n    }),\n    svelte({\n      compilerOptions: {\n        hydratable: true,\n      },\n    }),\n    tailwindcss(),\n  ],\n})\n"
  },
  {
    "path": "playgrounds/svelte5/.gitattributes",
    "content": "* text=auto\n\n*.blade.php diff=html\n*.css diff=css\n*.html diff=html\n*.md diff=markdown\n*.php diff=php\n\n/.github export-ignore\nCHANGELOG.md export-ignore\n.styleci.yml export-ignore\n"
  },
  {
    "path": "playgrounds/svelte5/.gitignore",
    "content": "/node_modules\n/bootstrap/ssr\n/public/build\n/public/hot\n/public/storage\n/storage/*.key\n/vendor\n.env\n.env.backup\n.env.production\n.phpunit.result.cache\nHomestead.json\nHomestead.yaml\nauth.json\nnpm-debug.log\nyarn-error.log\n/.fleet\n/.idea\n/.vscode\n"
  },
  {
    "path": "playgrounds/svelte5/README.md",
    "content": "<p align=\"center\"><a href=\"https://laravel.com\" target=\"_blank\"><img src=\"https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg\" width=\"400\" alt=\"Laravel Logo\"></a></p>\n\n<p align=\"center\">\n<a href=\"https://travis-ci.org/laravel/framework\"><img src=\"https://travis-ci.org/laravel/framework.svg\" alt=\"Build Status\"></a>\n<a href=\"https://packagist.org/packages/laravel/framework\"><img src=\"https://img.shields.io/packagist/dt/laravel/framework\" alt=\"Total Downloads\"></a>\n<a href=\"https://packagist.org/packages/laravel/framework\"><img src=\"https://img.shields.io/packagist/v/laravel/framework\" alt=\"Latest Stable Version\"></a>\n<a href=\"https://packagist.org/packages/laravel/framework\"><img src=\"https://img.shields.io/packagist/l/laravel/framework\" alt=\"License\"></a>\n</p>\n\n## About Laravel\n\nLaravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:\n\n- [Simple, fast routing engine](https://laravel.com/docs/routing).\n- [Powerful dependency injection container](https://laravel.com/docs/container).\n- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.\n- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).\n- Database agnostic [schema migrations](https://laravel.com/docs/migrations).\n- [Robust background job processing](https://laravel.com/docs/queues).\n- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).\n\nLaravel is accessible, powerful, and provides tools required for large, robust applications.\n\n## Learning Laravel\n\nLaravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.\n\nYou may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.\n\nIf you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 2000 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.\n\n## Laravel Sponsors\n\nWe would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell).\n\n### Premium Partners\n\n- **[Vehikl](https://vehikl.com/)**\n- **[Tighten Co.](https://tighten.co)**\n- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**\n- **[64 Robots](https://64robots.com)**\n- **[Cubet Techno Labs](https://cubettech.com)**\n- **[Cyber-Duck](https://cyber-duck.co.uk)**\n- **[Many](https://www.many.co.uk)**\n- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**\n- **[DevSquad](https://devsquad.com)**\n- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**\n- **[OP.GG](https://op.gg)**\n- **[WebReinvent](https://webreinvent.com/?utm_source=laravel&utm_medium=github&utm_campaign=patreon-sponsors)**\n- **[Lendio](https://lendio.com)**\n\n## Contributing\n\nThank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).\n\n## Code of Conduct\n\nIn order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).\n\n## Security Vulnerabilities\n\nIf you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.\n\n## License\n\nThe Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).\n"
  },
  {
    "path": "playgrounds/svelte5/app/Console/Kernel.php",
    "content": "<?php\n\nnamespace App\\Console;\n\nuse Illuminate\\Console\\Scheduling\\Schedule;\nuse Illuminate\\Foundation\\Console\\Kernel as ConsoleKernel;\n\nclass Kernel extends ConsoleKernel\n{\n    /**\n     * Define the application's command schedule.\n     *\n     * @return void\n     */\n    protected function schedule(Schedule $schedule)\n    {\n        // $schedule->command('inspire')->hourly();\n    }\n\n    /**\n     * Register the commands for the application.\n     *\n     * @return void\n     */\n    protected function commands()\n    {\n        $this->load(__DIR__.'/Commands');\n\n        require base_path('routes/console.php');\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Exceptions/Handler.php",
    "content": "<?php\n\nnamespace App\\Exceptions;\n\nuse Illuminate\\Foundation\\Exceptions\\Handler as ExceptionHandler;\nuse Throwable;\n\nclass Handler extends ExceptionHandler\n{\n    /**\n     * A list of exception types with their corresponding custom log levels.\n     *\n     * @var array<class-string<\\Throwable>, \\Psr\\Log\\LogLevel::*>\n     */\n    protected $levels = [\n        //\n    ];\n\n    /**\n     * A list of the exception types that are not reported.\n     *\n     * @var array<int, class-string<\\Throwable>>\n     */\n    protected $dontReport = [\n        //\n    ];\n\n    /**\n     * A list of the inputs that are never flashed to the session on validation exceptions.\n     *\n     * @var array<int, string>\n     */\n    protected $dontFlash = [\n        'current_password',\n        'password',\n        'password_confirmation',\n    ];\n\n    /**\n     * Register the exception handling callbacks for the application.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        $this->reportable(function (Throwable $e) {\n            //\n        });\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Http/Controllers/Controller.php",
    "content": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Foundation\\Auth\\Access\\AuthorizesRequests;\nuse Illuminate\\Foundation\\Bus\\DispatchesJobs;\nuse Illuminate\\Foundation\\Validation\\ValidatesRequests;\nuse Illuminate\\Routing\\Controller as BaseController;\n\nclass Controller extends BaseController\n{\n    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Http/Kernel.php",
    "content": "<?php\n\nnamespace App\\Http;\n\nuse Illuminate\\Foundation\\Http\\Kernel as HttpKernel;\n\nclass Kernel extends HttpKernel\n{\n    /**\n     * The application's global HTTP middleware stack.\n     *\n     * These middleware are run during every request to your application.\n     *\n     * @var array<int, class-string|string>\n     */\n    protected $middleware = [\n        // \\App\\Http\\Middleware\\TrustHosts::class,\n        \\App\\Http\\Middleware\\TrustProxies::class,\n        \\Illuminate\\Http\\Middleware\\HandleCors::class,\n        \\App\\Http\\Middleware\\PreventRequestsDuringMaintenance::class,\n        \\Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize::class,\n        \\App\\Http\\Middleware\\TrimStrings::class,\n        \\Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull::class,\n    ];\n\n    /**\n     * The application's route middleware groups.\n     *\n     * @var array<string, array<int, class-string|string>>\n     */\n    protected $middlewareGroups = [\n        'web' => [\n            \\App\\Http\\Middleware\\EncryptCookies::class,\n            \\Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse::class,\n            \\Illuminate\\Session\\Middleware\\StartSession::class,\n            \\Illuminate\\View\\Middleware\\ShareErrorsFromSession::class,\n            \\App\\Http\\Middleware\\VerifyCsrfToken::class,\n            \\Illuminate\\Routing\\Middleware\\SubstituteBindings::class,\n            \\App\\Http\\Middleware\\HandleInertiaRequests::class,\n        ],\n\n        'api' => [\n            // \\Laravel\\Sanctum\\Http\\Middleware\\EnsureFrontendRequestsAreStateful::class,\n            'throttle:api',\n            \\Illuminate\\Routing\\Middleware\\SubstituteBindings::class,\n        ],\n    ];\n\n    /**\n     * The application's route middleware.\n     *\n     * These middleware may be assigned to groups or used individually.\n     *\n     * @var array<string, class-string|string>\n     */\n    protected $routeMiddleware = [\n        'auth' => \\App\\Http\\Middleware\\Authenticate::class,\n        'auth.basic' => \\Illuminate\\Auth\\Middleware\\AuthenticateWithBasicAuth::class,\n        'auth.session' => \\Illuminate\\Session\\Middleware\\AuthenticateSession::class,\n        'cache.headers' => \\Illuminate\\Http\\Middleware\\SetCacheHeaders::class,\n        'can' => \\Illuminate\\Auth\\Middleware\\Authorize::class,\n        'guest' => \\App\\Http\\Middleware\\RedirectIfAuthenticated::class,\n        'password.confirm' => \\Illuminate\\Auth\\Middleware\\RequirePassword::class,\n        'signed' => \\App\\Http\\Middleware\\ValidateSignature::class,\n        'throttle' => \\Illuminate\\Routing\\Middleware\\ThrottleRequests::class,\n        'verified' => \\Illuminate\\Auth\\Middleware\\EnsureEmailIsVerified::class,\n    ];\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Http/Middleware/Authenticate.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Auth\\Middleware\\Authenticate as Middleware;\n\nclass Authenticate extends Middleware\n{\n    /**\n     * Get the path the user should be redirected to when they are not authenticated.\n     *\n     * @param  \\Illuminate\\Http\\Request  $request\n     * @return string|null\n     */\n    protected function redirectTo($request)\n    {\n        if (! $request->expectsJson()) {\n            return route('login');\n        }\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Http/Middleware/EncryptCookies.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Cookie\\Middleware\\EncryptCookies as Middleware;\n\nclass EncryptCookies extends Middleware\n{\n    /**\n     * The names of the cookies that should not be encrypted.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        //\n    ];\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Http/Middleware/HandleInertiaRequests.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Http\\Request;\nuse Inertia\\Middleware;\n\nclass HandleInertiaRequests extends Middleware\n{\n    /**\n     * The root template that's loaded on the first page visit.\n     *\n     * @see https://inertiajs.com/server-side-setup#root-template\n     * @var string\n     */\n    protected $rootView = 'app';\n\n    /**\n     * Determines the current asset version.\n     *\n     * @see https://inertiajs.com/asset-versioning\n     */\n    public function version(Request $request): ?string\n    {\n        return parent::version($request);\n    }\n\n    /**\n     * Defines the props that are shared by default.\n     *\n     * @see https://inertiajs.com/shared-data\n     */\n    public function share(Request $request): array\n    {\n        return array_merge(parent::share($request), [\n            'appName' => config('app.name'),\n        ]);\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Http/Middleware/PreventRequestsDuringMaintenance.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance as Middleware;\n\nclass PreventRequestsDuringMaintenance extends Middleware\n{\n    /**\n     * The URIs that should be reachable while maintenance mode is enabled.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        //\n    ];\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Http/Middleware/RedirectIfAuthenticated.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse App\\Providers\\RouteServiceProvider;\nuse Closure;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Auth;\n\nclass RedirectIfAuthenticated\n{\n    /**\n     * Handle an incoming request.\n     *\n     * @param  \\Closure(\\Illuminate\\Http\\Request): (\\Illuminate\\Http\\Response|\\Illuminate\\Http\\RedirectResponse)  $next\n     * @param  string|null  ...$guards\n     * @return \\Illuminate\\Http\\Response|\\Illuminate\\Http\\RedirectResponse\n     */\n    public function handle(Request $request, Closure $next, ...$guards)\n    {\n        $guards = empty($guards) ? [null] : $guards;\n\n        foreach ($guards as $guard) {\n            if (Auth::guard($guard)->check()) {\n                return redirect(RouteServiceProvider::HOME);\n            }\n        }\n\n        return $next($request);\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Http/Middleware/TrimStrings.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Foundation\\Http\\Middleware\\TrimStrings as Middleware;\n\nclass TrimStrings extends Middleware\n{\n    /**\n     * The names of the attributes that should not be trimmed.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        'current_password',\n        'password',\n        'password_confirmation',\n    ];\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Http/Middleware/TrustHosts.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Http\\Middleware\\TrustHosts as Middleware;\n\nclass TrustHosts extends Middleware\n{\n    /**\n     * Get the host patterns that should be trusted.\n     *\n     * @return array<int, string|null>\n     */\n    public function hosts()\n    {\n        return [\n            $this->allSubdomainsOfApplicationUrl(),\n        ];\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Http/Middleware/TrustProxies.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Http\\Middleware\\TrustProxies as Middleware;\nuse Illuminate\\Http\\Request;\n\nclass TrustProxies extends Middleware\n{\n    /**\n     * The trusted proxies for this application.\n     *\n     * @var array<int, string>|string|null\n     */\n    protected $proxies;\n\n    /**\n     * The headers that should be used to detect proxies.\n     *\n     * @var int\n     */\n    protected $headers =\n        Request::HEADER_X_FORWARDED_FOR |\n        Request::HEADER_X_FORWARDED_HOST |\n        Request::HEADER_X_FORWARDED_PORT |\n        Request::HEADER_X_FORWARDED_PROTO |\n        Request::HEADER_X_FORWARDED_AWS_ELB;\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Http/Middleware/ValidateSignature.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Routing\\Middleware\\ValidateSignature as Middleware;\n\nclass ValidateSignature extends Middleware\n{\n    /**\n     * The names of the query string parameters that should be ignored.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        // 'fbclid',\n        // 'utm_campaign',\n        // 'utm_content',\n        // 'utm_medium',\n        // 'utm_source',\n        // 'utm_term',\n    ];\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Http/Middleware/VerifyCsrfToken.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Foundation\\Http\\Middleware\\VerifyCsrfToken as Middleware;\n\nclass VerifyCsrfToken extends Middleware\n{\n    /**\n     * The URIs that should be excluded from CSRF verification.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        //\n    ];\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Http/Requests/PrecognitionFormRequest.php",
    "content": "<?php\n\nnamespace App\\Http\\Requests;\n\nuse Illuminate\\Foundation\\Http\\FormRequest;\n\nclass PrecognitionFormRequest extends FormRequest\n{\n    /**\n     * Determine if the user is authorized to make this request.\n     */\n    public function authorize(): bool\n    {\n        return true;\n    }\n\n    /**\n     * Get the validation rules that apply to the request.\n     *\n     * @return array<string, \\Illuminate\\Contracts\\Validation\\ValidationRule|array<mixed>|string>\n     */\n    public function rules(): array\n    {\n        sleep(1);\n\n        return [\n            'name' => ['required', 'string', 'min:3', 'max:255'],\n            'email' => ['required', 'email', 'max:255'],\n            'avatar' => ['nullable', 'file', 'image'],\n        ];\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Models/User.php",
    "content": "<?php\n\nnamespace App\\Models;\n\n// use Illuminate\\Contracts\\Auth\\MustVerifyEmail;\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Foundation\\Auth\\User as Authenticatable;\nuse Illuminate\\Notifications\\Notifiable;\nuse Laravel\\Sanctum\\HasApiTokens;\n\nclass User extends Authenticatable\n{\n    use HasApiTokens, HasFactory, Notifiable;\n\n    /**\n     * The attributes that are mass assignable.\n     *\n     * @var array<int, string>\n     */\n    protected $fillable = [\n        'name',\n        'email',\n        'password',\n    ];\n\n    /**\n     * The attributes that should be hidden for serialization.\n     *\n     * @var array<int, string>\n     */\n    protected $hidden = [\n        'password',\n        'remember_token',\n    ];\n\n    /**\n     * The attributes that should be cast.\n     *\n     * @var array<string, string>\n     */\n    protected $casts = [\n        'email_verified_at' => 'datetime',\n    ];\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Providers/AppServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Support\\ServiceProvider;\n\nclass AppServiceProvider extends ServiceProvider\n{\n    /**\n     * Register any application services.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        //\n    }\n\n    /**\n     * Bootstrap any application services.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Providers/AuthServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\n// use Illuminate\\Support\\Facades\\Gate;\nuse Illuminate\\Foundation\\Support\\Providers\\AuthServiceProvider as ServiceProvider;\n\nclass AuthServiceProvider extends ServiceProvider\n{\n    /**\n     * The model to policy mappings for the application.\n     *\n     * @var array<class-string, class-string>\n     */\n    protected $policies = [\n        // 'App\\Models\\Model' => 'App\\Policies\\ModelPolicy',\n    ];\n\n    /**\n     * Register any authentication / authorization services.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        $this->registerPolicies();\n\n        //\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Providers/BroadcastServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Support\\Facades\\Broadcast;\nuse Illuminate\\Support\\ServiceProvider;\n\nclass BroadcastServiceProvider extends ServiceProvider\n{\n    /**\n     * Bootstrap any application services.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        Broadcast::routes();\n\n        require base_path('routes/channels.php');\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Providers/EventServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Auth\\Events\\Registered;\nuse Illuminate\\Auth\\Listeners\\SendEmailVerificationNotification;\nuse Illuminate\\Foundation\\Support\\Providers\\EventServiceProvider as ServiceProvider;\nuse Illuminate\\Support\\Facades\\Event;\n\nclass EventServiceProvider extends ServiceProvider\n{\n    /**\n     * The event to listener mappings for the application.\n     *\n     * @var array<class-string, array<int, class-string>>\n     */\n    protected $listen = [\n        Registered::class => [\n            SendEmailVerificationNotification::class,\n        ],\n    ];\n\n    /**\n     * Register any events for your application.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        //\n    }\n\n    /**\n     * Determine if events and listeners should be automatically discovered.\n     *\n     * @return bool\n     */\n    public function shouldDiscoverEvents()\n    {\n        return false;\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/app/Providers/RouteServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Cache\\RateLimiting\\Limit;\nuse Illuminate\\Foundation\\Support\\Providers\\RouteServiceProvider as ServiceProvider;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\RateLimiter;\nuse Illuminate\\Support\\Facades\\Route;\n\nclass RouteServiceProvider extends ServiceProvider\n{\n    /**\n     * The path to the \"home\" route for your application.\n     *\n     * Typically, users are redirected here after authentication.\n     *\n     * @var string\n     */\n    public const HOME = '/home';\n\n    /**\n     * Define your route model bindings, pattern filters, and other route configuration.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        $this->configureRateLimiting();\n\n        $this->routes(function () {\n            Route::middleware('api')\n                ->prefix('api')\n                ->group(base_path('routes/api.php'));\n\n            Route::middleware('web')\n                ->group(base_path('routes/web.php'));\n        });\n    }\n\n    /**\n     * Configure the rate limiters for the application.\n     *\n     * @return void\n     */\n    protected function configureRateLimiting()\n    {\n        RateLimiter::for('api', function (Request $request) {\n            return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());\n        });\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/artisan",
    "content": "#!/usr/bin/env php\n<?php\n\ndefine('LARAVEL_START', microtime(true));\n\n/*\n|--------------------------------------------------------------------------\n| Register The Auto Loader\n|--------------------------------------------------------------------------\n|\n| Composer provides a convenient, automatically generated class loader\n| for our application. We just need to utilize it! We'll require it\n| into the script here so that we do not have to worry about the\n| loading of any of our classes manually. It's great to relax.\n|\n*/\n\nrequire __DIR__.'/vendor/autoload.php';\n\n$app = require_once __DIR__.'/bootstrap/app.php';\n\n/*\n|--------------------------------------------------------------------------\n| Run The Artisan Application\n|--------------------------------------------------------------------------\n|\n| When we run the console application, the current CLI command will be\n| executed in this console and the response sent back to a terminal\n| or another output device for the developers. Here goes nothing!\n|\n*/\n\n$kernel = $app->make(Illuminate\\Contracts\\Console\\Kernel::class);\n\n$status = $kernel->handle(\n    $input = new Symfony\\Component\\Console\\Input\\ArgvInput,\n    new Symfony\\Component\\Console\\Output\\ConsoleOutput\n);\n\n/*\n|--------------------------------------------------------------------------\n| Shutdown The Application\n|--------------------------------------------------------------------------\n|\n| Once Artisan has finished running, we will fire off the shutdown events\n| so that any final work may be done by the application before we shut\n| down the process. This is the last thing to happen to the request.\n|\n*/\n\n$kernel->terminate($input, $status);\n\nexit($status);\n"
  },
  {
    "path": "playgrounds/svelte5/bootstrap/app.php",
    "content": "<?php\n\n/*\n|--------------------------------------------------------------------------\n| Create The Application\n|--------------------------------------------------------------------------\n|\n| The first thing we will do is create a new Laravel application instance\n| which serves as the \"glue\" for all the components of Laravel, and is\n| the IoC container for the system binding all of the various parts.\n|\n*/\n\n$app = new Illuminate\\Foundation\\Application(\n    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)\n);\n\n/*\n|--------------------------------------------------------------------------\n| Bind Important Interfaces\n|--------------------------------------------------------------------------\n|\n| Next, we need to bind some important interfaces into the container so\n| we will be able to resolve them when needed. The kernels serve the\n| incoming requests to this application from both the web and CLI.\n|\n*/\n\n$app->singleton(\n    Illuminate\\Contracts\\Http\\Kernel::class,\n    App\\Http\\Kernel::class\n);\n\n$app->singleton(\n    Illuminate\\Contracts\\Console\\Kernel::class,\n    App\\Console\\Kernel::class\n);\n\n$app->singleton(\n    Illuminate\\Contracts\\Debug\\ExceptionHandler::class,\n    App\\Exceptions\\Handler::class\n);\n\n/*\n|--------------------------------------------------------------------------\n| Return The Application\n|--------------------------------------------------------------------------\n|\n| This script returns the application instance. The instance is given to\n| the calling script so we can separate the building of the instances\n| from the actual running of the application and sending responses.\n|\n*/\n\nreturn $app;\n"
  },
  {
    "path": "playgrounds/svelte5/bootstrap/cache/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/svelte5/composer.json",
    "content": "{\n    \"name\": \"laravel/laravel\",\n    \"type\": \"project\",\n    \"description\": \"The Laravel Framework.\",\n    \"keywords\": [\n        \"framework\",\n        \"laravel\"\n    ],\n    \"license\": \"MIT\",\n    \"require\": {\n        \"php\": \"^8.2\",\n        \"guzzlehttp/guzzle\": \"^7.2\",\n        \"inertiajs/inertia-laravel\": \"^2.0.16\",\n        \"laravel/framework\": \"^11.0\",\n        \"laravel/sanctum\": \"^4.0\",\n        \"laravel/tinker\": \"^2.7\"\n    },\n    \"require-dev\": {\n        \"fakerphp/faker\": \"^1.9.1\",\n        \"laravel/pint\": \"^1.0\",\n        \"laravel/sail\": \"^1.0.1\",\n        \"mockery/mockery\": \"^1.4.4\",\n        \"nunomaduro/collision\": \"^8.1\",\n        \"phpunit/phpunit\": \"^10.0\",\n        \"spatie/laravel-ignition\": \"^2.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"App\\\\\": \"app/\",\n            \"Database\\\\Factories\\\\\": \"database/factories/\",\n            \"Database\\\\Seeders\\\\\": \"database/seeders/\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Tests\\\\\": \"tests/\"\n        }\n    },\n    \"scripts\": {\n        \"post-autoload-dump\": [\n            \"Illuminate\\\\Foundation\\\\ComposerScripts::postAutoloadDump\",\n            \"@php artisan package:discover --ansi\"\n        ],\n        \"post-update-cmd\": [\n            \"@php artisan vendor:publish --tag=laravel-assets --ansi --force\"\n        ],\n        \"post-root-package-install\": [\n            \"@php -r \\\"file_exists('.env') || copy('.env.example', '.env');\\\"\"\n        ],\n        \"post-create-project-cmd\": [\n            \"@php artisan key:generate --ansi\"\n        ],\n        \"dev\": [\n            \"Composer\\\\Config::disableProcessTimeout\",\n            \"pnpx concurrently -c \\\"#93c5fd,#c4b5fd\\\" \\\"php artisan serve\\\" \\\"pnpm run dev\\\" --names=server,vite\"\n        ]\n    },\n    \"extra\": {\n        \"laravel\": {\n            \"dont-discover\": []\n        }\n    },\n    \"config\": {\n        \"optimize-autoloader\": true,\n        \"preferred-install\": \"dist\",\n        \"sort-packages\": true,\n        \"allow-plugins\": {\n            \"pestphp/pest-plugin\": true\n        }\n    },\n    \"minimum-stability\": \"dev\",\n    \"prefer-stable\": true\n}\n"
  },
  {
    "path": "playgrounds/svelte5/config/app.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Facades\\Facade;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Name\n    |--------------------------------------------------------------------------\n    |\n    | This value is the name of your application. This value is used when the\n    | framework needs to place the application's name in a notification or\n    | any other location as required by the application or its packages.\n    |\n    */\n\n    'name' => env('APP_NAME', 'Laravel'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Environment\n    |--------------------------------------------------------------------------\n    |\n    | This value determines the \"environment\" your application is currently\n    | running in. This may determine how you prefer to configure various\n    | services the application utilizes. Set this in your \".env\" file.\n    |\n    */\n\n    'env' => env('APP_ENV', 'production'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Debug Mode\n    |--------------------------------------------------------------------------\n    |\n    | When your application is in debug mode, detailed error messages with\n    | stack traces will be shown on every error that occurs within your\n    | application. If disabled, a simple generic error page is shown.\n    |\n    */\n\n    'debug' => (bool) env('APP_DEBUG', false),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application URL\n    |--------------------------------------------------------------------------\n    |\n    | This URL is used by the console to properly generate URLs when using\n    | the Artisan command line tool. You should set this to the root of\n    | your application so that it is used when running Artisan tasks.\n    |\n    */\n\n    'url' => env('APP_URL', 'http://localhost'),\n\n    'asset_url' => env('ASSET_URL'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Timezone\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the default timezone for your application, which\n    | will be used by the PHP date and date-time functions. We have gone\n    | ahead and set this to a sensible default for you out of the box.\n    |\n    */\n\n    'timezone' => 'UTC',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Locale Configuration\n    |--------------------------------------------------------------------------\n    |\n    | The application locale determines the default locale that will be used\n    | by the translation service provider. You are free to set this value\n    | to any of the locales which will be supported by the application.\n    |\n    */\n\n    'locale' => 'en',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Fallback Locale\n    |--------------------------------------------------------------------------\n    |\n    | The fallback locale determines the locale to use when the current one\n    | is not available. You may change the value to correspond to any of\n    | the language folders that are provided through your application.\n    |\n    */\n\n    'fallback_locale' => 'en',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Faker Locale\n    |--------------------------------------------------------------------------\n    |\n    | This locale will be used by the Faker PHP library when generating fake\n    | data for your database seeds. For example, this will be used to get\n    | localized telephone numbers, street address information and more.\n    |\n    */\n\n    'faker_locale' => 'en_US',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Encryption Key\n    |--------------------------------------------------------------------------\n    |\n    | This key is used by the Illuminate encrypter service and should be set\n    | to a random, 32 character string, otherwise these encrypted strings\n    | will not be safe. Please do this before deploying an application!\n    |\n    */\n\n    'key' => env('APP_KEY'),\n\n    'cipher' => 'AES-256-CBC',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Maintenance Mode Driver\n    |--------------------------------------------------------------------------\n    |\n    | These configuration options determine the driver used to determine and\n    | manage Laravel's \"maintenance mode\" status. The \"cache\" driver will\n    | allow maintenance mode to be controlled across multiple machines.\n    |\n    | Supported drivers: \"file\", \"cache\"\n    |\n    */\n\n    'maintenance' => [\n        'driver' => 'file',\n        // 'store'  => 'redis',\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Autoloaded Service Providers\n    |--------------------------------------------------------------------------\n    |\n    | The service providers listed here will be automatically loaded on the\n    | request to your application. Feel free to add your own services to\n    | this array to grant expanded functionality to your applications.\n    |\n    */\n\n    'providers' => [\n\n        /*\n         * Laravel Framework Service Providers...\n         */\n        Illuminate\\Auth\\AuthServiceProvider::class,\n        Illuminate\\Broadcasting\\BroadcastServiceProvider::class,\n        Illuminate\\Bus\\BusServiceProvider::class,\n        Illuminate\\Cache\\CacheServiceProvider::class,\n        Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider::class,\n        Illuminate\\Cookie\\CookieServiceProvider::class,\n        Illuminate\\Database\\DatabaseServiceProvider::class,\n        Illuminate\\Encryption\\EncryptionServiceProvider::class,\n        Illuminate\\Filesystem\\FilesystemServiceProvider::class,\n        Illuminate\\Foundation\\Providers\\FoundationServiceProvider::class,\n        Illuminate\\Hashing\\HashServiceProvider::class,\n        Illuminate\\Mail\\MailServiceProvider::class,\n        Illuminate\\Notifications\\NotificationServiceProvider::class,\n        Illuminate\\Pagination\\PaginationServiceProvider::class,\n        Illuminate\\Pipeline\\PipelineServiceProvider::class,\n        Illuminate\\Queue\\QueueServiceProvider::class,\n        Illuminate\\Redis\\RedisServiceProvider::class,\n        Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider::class,\n        Illuminate\\Session\\SessionServiceProvider::class,\n        Illuminate\\Translation\\TranslationServiceProvider::class,\n        Illuminate\\Validation\\ValidationServiceProvider::class,\n        Illuminate\\View\\ViewServiceProvider::class,\n\n        /*\n         * Package Service Providers...\n         */\n\n        /*\n         * Application Service Providers...\n         */\n        App\\Providers\\AppServiceProvider::class,\n        App\\Providers\\AuthServiceProvider::class,\n        // App\\Providers\\BroadcastServiceProvider::class,\n        App\\Providers\\EventServiceProvider::class,\n        App\\Providers\\RouteServiceProvider::class,\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Class Aliases\n    |--------------------------------------------------------------------------\n    |\n    | This array of class aliases will be registered when this application\n    | is started. However, feel free to register as many as you wish as\n    | the aliases are \"lazy\" loaded so they don't hinder performance.\n    |\n    */\n\n    'aliases' => Facade::defaultAliases()->merge([\n        // 'ExampleClass' => App\\Example\\ExampleClass::class,\n    ])->toArray(),\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/config/auth.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Authentication Defaults\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default authentication \"guard\" and password\n    | reset options for your application. You may change these defaults\n    | as required, but they're a perfect start for most applications.\n    |\n    */\n\n    'defaults' => [\n        'guard' => 'web',\n        'passwords' => 'users',\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Authentication Guards\n    |--------------------------------------------------------------------------\n    |\n    | Next, you may define every authentication guard for your application.\n    | Of course, a great default configuration has been defined for you\n    | here which uses session storage and the Eloquent user provider.\n    |\n    | All authentication drivers have a user provider. This defines how the\n    | users are actually retrieved out of your database or other storage\n    | mechanisms used by this application to persist your user's data.\n    |\n    | Supported: \"session\"\n    |\n    */\n\n    'guards' => [\n        'web' => [\n            'driver' => 'session',\n            'provider' => 'users',\n        ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | User Providers\n    |--------------------------------------------------------------------------\n    |\n    | All authentication drivers have a user provider. This defines how the\n    | users are actually retrieved out of your database or other storage\n    | mechanisms used by this application to persist your user's data.\n    |\n    | If you have multiple user tables or models you may configure multiple\n    | sources which represent each model / table. These sources may then\n    | be assigned to any extra authentication guards you have defined.\n    |\n    | Supported: \"database\", \"eloquent\"\n    |\n    */\n\n    'providers' => [\n        'users' => [\n            'driver' => 'eloquent',\n            'model' => App\\Models\\User::class,\n        ],\n\n        // 'users' => [\n        //     'driver' => 'database',\n        //     'table' => 'users',\n        // ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Resetting Passwords\n    |--------------------------------------------------------------------------\n    |\n    | You may specify multiple password reset configurations if you have more\n    | than one user table or model in the application and you want to have\n    | separate password reset settings based on the specific user types.\n    |\n    | The expire time is the number of minutes that each reset token will be\n    | considered valid. This security feature keeps tokens short-lived so\n    | they have less time to be guessed. You may change this as needed.\n    |\n    */\n\n    'passwords' => [\n        'users' => [\n            'provider' => 'users',\n            'table' => 'password_resets',\n            'expire' => 60,\n            'throttle' => 60,\n        ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Password Confirmation Timeout\n    |--------------------------------------------------------------------------\n    |\n    | Here you may define the amount of seconds before a password confirmation\n    | times out and the user is prompted to re-enter their password via the\n    | confirmation screen. By default, the timeout lasts for three hours.\n    |\n    */\n\n    'password_timeout' => 10800,\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/config/broadcasting.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Broadcaster\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default broadcaster that will be used by the\n    | framework when an event needs to be broadcast. You may set this to\n    | any of the connections defined in the \"connections\" array below.\n    |\n    | Supported: \"pusher\", \"ably\", \"redis\", \"log\", \"null\"\n    |\n    */\n\n    'default' => env('BROADCAST_DRIVER', 'null'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Broadcast Connections\n    |--------------------------------------------------------------------------\n    |\n    | Here you may define all of the broadcast connections that will be used\n    | to broadcast events to other systems or over websockets. Samples of\n    | each available type of connection are provided inside this array.\n    |\n    */\n\n    'connections' => [\n\n        'pusher' => [\n            'driver' => 'pusher',\n            'key' => env('PUSHER_APP_KEY'),\n            'secret' => env('PUSHER_APP_SECRET'),\n            'app_id' => env('PUSHER_APP_ID'),\n            'options' => [\n                'host' => env('PUSHER_HOST') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com',\n                'port' => env('PUSHER_PORT', 443),\n                'scheme' => env('PUSHER_SCHEME', 'https'),\n                'encrypted' => true,\n                'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',\n            ],\n            'client_options' => [\n                // Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html\n            ],\n        ],\n\n        'ably' => [\n            'driver' => 'ably',\n            'key' => env('ABLY_KEY'),\n        ],\n\n        'redis' => [\n            'driver' => 'redis',\n            'connection' => 'default',\n        ],\n\n        'log' => [\n            'driver' => 'log',\n        ],\n\n        'null' => [\n            'driver' => 'null',\n        ],\n\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/config/cache.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Str;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Cache Store\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default cache connection that gets used while\n    | using this caching library. This connection is used when another is\n    | not explicitly specified when executing a given caching function.\n    |\n    */\n\n    'default' => env('CACHE_DRIVER', 'file'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cache Stores\n    |--------------------------------------------------------------------------\n    |\n    | Here you may define all of the cache \"stores\" for your application as\n    | well as their drivers. You may even define multiple stores for the\n    | same cache driver to group types of items stored in your caches.\n    |\n    | Supported drivers: \"apc\", \"array\", \"database\", \"file\",\n    |         \"memcached\", \"redis\", \"dynamodb\", \"octane\", \"null\"\n    |\n    */\n\n    'stores' => [\n\n        'apc' => [\n            'driver' => 'apc',\n        ],\n\n        'array' => [\n            'driver' => 'array',\n            'serialize' => false,\n        ],\n\n        'database' => [\n            'driver' => 'database',\n            'table' => 'cache',\n            'connection' => null,\n            'lock_connection' => null,\n        ],\n\n        'file' => [\n            'driver' => 'file',\n            'path' => storage_path('framework/cache/data'),\n        ],\n\n        'memcached' => [\n            'driver' => 'memcached',\n            'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),\n            'sasl' => [\n                env('MEMCACHED_USERNAME'),\n                env('MEMCACHED_PASSWORD'),\n            ],\n            'options' => [\n                // Memcached::OPT_CONNECT_TIMEOUT => 2000,\n            ],\n            'servers' => [\n                [\n                    'host' => env('MEMCACHED_HOST', '127.0.0.1'),\n                    'port' => env('MEMCACHED_PORT', 11211),\n                    'weight' => 100,\n                ],\n            ],\n        ],\n\n        'redis' => [\n            'driver' => 'redis',\n            'connection' => 'cache',\n            'lock_connection' => 'default',\n        ],\n\n        'dynamodb' => [\n            'driver' => 'dynamodb',\n            'key' => env('AWS_ACCESS_KEY_ID'),\n            'secret' => env('AWS_SECRET_ACCESS_KEY'),\n            'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),\n            'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),\n            'endpoint' => env('DYNAMODB_ENDPOINT'),\n        ],\n\n        'octane' => [\n            'driver' => 'octane',\n        ],\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cache Key Prefix\n    |--------------------------------------------------------------------------\n    |\n    | When utilizing the APC, database, memcached, Redis, or DynamoDB cache\n    | stores there might be other applications using the same cache. For\n    | that reason, you may prefix every cache key to avoid collisions.\n    |\n    */\n\n    'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'),\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/config/cors.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cross-Origin Resource Sharing (CORS) Configuration\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure your settings for cross-origin resource sharing\n    | or \"CORS\". This determines what cross-origin operations may execute\n    | in web browsers. You are free to adjust these settings as needed.\n    |\n    | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS\n    |\n    */\n\n    'paths' => ['api/*', 'sanctum/csrf-cookie'],\n\n    'allowed_methods' => ['*'],\n\n    'allowed_origins' => ['*'],\n\n    'allowed_origins_patterns' => [],\n\n    'allowed_headers' => ['*'],\n\n    'exposed_headers' => [],\n\n    'max_age' => 0,\n\n    'supports_credentials' => false,\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/config/database.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Str;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Database Connection Name\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify which of the database connections below you wish\n    | to use as your default connection for all database work. Of course\n    | you may use many connections at once using the Database library.\n    |\n    */\n\n    'default' => env('DB_CONNECTION', 'mysql'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Database Connections\n    |--------------------------------------------------------------------------\n    |\n    | Here are each of the database connections setup for your application.\n    | Of course, examples of configuring each database platform that is\n    | supported by Laravel is shown below to make development simple.\n    |\n    |\n    | All database work in Laravel is done through the PHP PDO facilities\n    | so make sure you have the driver for your particular database of\n    | choice installed on your machine before you begin development.\n    |\n    */\n\n    'connections' => [\n\n        'sqlite' => [\n            'driver' => 'sqlite',\n            'url' => env('DATABASE_URL'),\n            'database' => env('DB_DATABASE', database_path('database.sqlite')),\n            'prefix' => '',\n            'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),\n        ],\n\n        'mysql' => [\n            'driver' => 'mysql',\n            'url' => env('DATABASE_URL'),\n            'host' => env('DB_HOST', '127.0.0.1'),\n            'port' => env('DB_PORT', '3306'),\n            'database' => env('DB_DATABASE', 'forge'),\n            'username' => env('DB_USERNAME', 'forge'),\n            'password' => env('DB_PASSWORD', ''),\n            'unix_socket' => env('DB_SOCKET', ''),\n            'charset' => 'utf8mb4',\n            'collation' => 'utf8mb4_unicode_ci',\n            'prefix' => '',\n            'prefix_indexes' => true,\n            'strict' => true,\n            'engine' => null,\n            'options' => extension_loaded('pdo_mysql') ? array_filter([\n                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),\n            ]) : [],\n        ],\n\n        'pgsql' => [\n            'driver' => 'pgsql',\n            'url' => env('DATABASE_URL'),\n            'host' => env('DB_HOST', '127.0.0.1'),\n            'port' => env('DB_PORT', '5432'),\n            'database' => env('DB_DATABASE', 'forge'),\n            'username' => env('DB_USERNAME', 'forge'),\n            'password' => env('DB_PASSWORD', ''),\n            'charset' => 'utf8',\n            'prefix' => '',\n            'prefix_indexes' => true,\n            'search_path' => 'public',\n            'sslmode' => 'prefer',\n        ],\n\n        'sqlsrv' => [\n            'driver' => 'sqlsrv',\n            'url' => env('DATABASE_URL'),\n            'host' => env('DB_HOST', 'localhost'),\n            'port' => env('DB_PORT', '1433'),\n            'database' => env('DB_DATABASE', 'forge'),\n            'username' => env('DB_USERNAME', 'forge'),\n            'password' => env('DB_PASSWORD', ''),\n            'charset' => 'utf8',\n            'prefix' => '',\n            'prefix_indexes' => true,\n            // 'encrypt' => env('DB_ENCRYPT', 'yes'),\n            // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),\n        ],\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Migration Repository Table\n    |--------------------------------------------------------------------------\n    |\n    | This table keeps track of all the migrations that have already run for\n    | your application. Using this information, we can determine which of\n    | the migrations on disk haven't actually been run in the database.\n    |\n    */\n\n    'migrations' => 'migrations',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Redis Databases\n    |--------------------------------------------------------------------------\n    |\n    | Redis is an open source, fast, and advanced key-value store that also\n    | provides a richer body of commands than a typical key-value system\n    | such as APC or Memcached. Laravel makes it easy to dig right in.\n    |\n    */\n\n    'redis' => [\n\n        'client' => env('REDIS_CLIENT', 'phpredis'),\n\n        'options' => [\n            'cluster' => env('REDIS_CLUSTER', 'redis'),\n            'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),\n        ],\n\n        'default' => [\n            'url' => env('REDIS_URL'),\n            'host' => env('REDIS_HOST', '127.0.0.1'),\n            'username' => env('REDIS_USERNAME'),\n            'password' => env('REDIS_PASSWORD'),\n            'port' => env('REDIS_PORT', '6379'),\n            'database' => env('REDIS_DB', '0'),\n        ],\n\n        'cache' => [\n            'url' => env('REDIS_URL'),\n            'host' => env('REDIS_HOST', '127.0.0.1'),\n            'username' => env('REDIS_USERNAME'),\n            'password' => env('REDIS_PASSWORD'),\n            'port' => env('REDIS_PORT', '6379'),\n            'database' => env('REDIS_CACHE_DB', '1'),\n        ],\n\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/config/filesystems.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Filesystem Disk\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the default filesystem disk that should be used\n    | by the framework. The \"local\" disk, as well as a variety of cloud\n    | based disks are available to your application. Just store away!\n    |\n    */\n\n    'default' => env('FILESYSTEM_DISK', 'local'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Filesystem Disks\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure as many filesystem \"disks\" as you wish, and you\n    | may even configure multiple disks of the same driver. Defaults have\n    | been set up for each driver as an example of the required values.\n    |\n    | Supported Drivers: \"local\", \"ftp\", \"sftp\", \"s3\"\n    |\n    */\n\n    'disks' => [\n\n        'local' => [\n            'driver' => 'local',\n            'root' => storage_path('app'),\n            'throw' => false,\n        ],\n\n        'public' => [\n            'driver' => 'local',\n            'root' => storage_path('app/public'),\n            'url' => env('APP_URL').'/storage',\n            'visibility' => 'public',\n            'throw' => false,\n        ],\n\n        's3' => [\n            'driver' => 's3',\n            'key' => env('AWS_ACCESS_KEY_ID'),\n            'secret' => env('AWS_SECRET_ACCESS_KEY'),\n            'region' => env('AWS_DEFAULT_REGION'),\n            'bucket' => env('AWS_BUCKET'),\n            'url' => env('AWS_URL'),\n            'endpoint' => env('AWS_ENDPOINT'),\n            'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),\n            'throw' => false,\n        ],\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Symbolic Links\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure the symbolic links that will be created when the\n    | `storage:link` Artisan command is executed. The array keys should be\n    | the locations of the links and the values should be their targets.\n    |\n    */\n\n    'links' => [\n        public_path('storage') => storage_path('app/public'),\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/config/hashing.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Hash Driver\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default hash driver that will be used to hash\n    | passwords for your application. By default, the bcrypt algorithm is\n    | used; however, you remain free to modify this option if you wish.\n    |\n    | Supported: \"bcrypt\", \"argon\", \"argon2id\"\n    |\n    */\n\n    'driver' => 'bcrypt',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Bcrypt Options\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the configuration options that should be used when\n    | passwords are hashed using the Bcrypt algorithm. This will allow you\n    | to control the amount of time it takes to hash the given password.\n    |\n    */\n\n    'bcrypt' => [\n        'rounds' => env('BCRYPT_ROUNDS', 10),\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Argon Options\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the configuration options that should be used when\n    | passwords are hashed using the Argon algorithm. These will allow you\n    | to control the amount of time it takes to hash the given password.\n    |\n    */\n\n    'argon' => [\n        'memory' => 65536,\n        'threads' => 1,\n        'time' => 4,\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/config/inertia.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Server Side Rendering\n    |--------------------------------------------------------------------------\n    |\n    | These options configures if and how Inertia uses Server Side Rendering\n    | to pre-render the initial visits made to your application's pages.\n    |\n    | You can specify a custom SSR bundle path, or omit it to let Inertia\n    | try and automatically detect it for you.\n    |\n    | Do note that enabling these options will NOT automatically make SSR work,\n    | as a separate rendering service needs to be available. To learn more,\n    | please visit https://inertiajs.com/server-side-rendering\n    |\n    */\n\n    'ssr' => [\n\n        'enabled' => (bool) env('INERTIA_SSR_ENABLED', true),\n\n        'url' => env('INERTIA_SSR_URL', 'http://127.0.0.1:13714'),\n\n        'ensure_bundle_exists' => (bool) env('INERTIA_SSR_ENSURE_BUNDLE_EXISTS', true),\n\n        // 'bundle' => base_path('bootstrap/ssr/ssr.mjs'),\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Pages\n    |--------------------------------------------------------------------------\n    |\n    | Set `ensure_pages_exist` to true if you want to enforce that Inertia page\n    | components exist on disk when rendering a page. This is useful for\n    | catching missing or misnamed components.\n    |\n    | The `page_paths` and `page_extensions` options define where to look\n    | for page components and which file extensions to consider.\n    |\n    */\n\n    'ensure_pages_exist' => false,\n\n    'page_paths' => [\n\n        resource_path('js/Pages'),\n\n    ],\n\n    'page_extensions' => [\n\n        'js',\n        'jsx',\n        'svelte',\n        'ts',\n        'tsx',\n        'vue',\n\n    ],\n\n    'use_script_element_for_initial_page' => (bool) env('INERTIA_USE_SCRIPT_ELEMENT_FOR_INITIAL_PAGE', false),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Testing\n    |--------------------------------------------------------------------------\n    |\n    | The values described here are used to locate Inertia components on the\n    | filesystem. For instance, when using `assertInertia`, the assertion\n    | attempts to locate the component as a file relative to any of the\n    | paths AND with any of the extensions specified here.\n    |\n    | Note: In a future release, the `page_paths` and `page_extensions`\n    | options below will be removed. The root-level options above\n    | will be used for both application and testing purposes.\n    |\n    */\n\n    'testing' => [\n\n        'ensure_pages_exist' => true,\n\n        'page_paths' => [\n\n            resource_path('js/Pages'),\n\n        ],\n\n        'page_extensions' => [\n\n            'js',\n            'jsx',\n            'svelte',\n            'ts',\n            'tsx',\n            'vue',\n\n        ],\n\n    ],\n\n    'history' => [\n\n        'encrypt' => (bool) env('INERTIA_ENCRYPT_HISTORY', true),\n\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/config/logging.php",
    "content": "<?php\n\nuse Monolog\\Handler\\NullHandler;\nuse Monolog\\Handler\\StreamHandler;\nuse Monolog\\Handler\\SyslogUdpHandler;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Log Channel\n    |--------------------------------------------------------------------------\n    |\n    | This option defines the default log channel that gets used when writing\n    | messages to the logs. The name specified in this option should match\n    | one of the channels defined in the \"channels\" configuration array.\n    |\n    */\n\n    'default' => env('LOG_CHANNEL', 'stack'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Deprecations Log Channel\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the log channel that should be used to log warnings\n    | regarding deprecated PHP and library features. This allows you to get\n    | your application ready for upcoming major versions of dependencies.\n    |\n    */\n\n    'deprecations' => [\n        'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),\n        'trace' => false,\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Log Channels\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure the log channels for your application. Out of\n    | the box, Laravel uses the Monolog PHP logging library. This gives\n    | you a variety of powerful log handlers / formatters to utilize.\n    |\n    | Available Drivers: \"single\", \"daily\", \"slack\", \"syslog\",\n    |                    \"errorlog\", \"monolog\",\n    |                    \"custom\", \"stack\"\n    |\n    */\n\n    'channels' => [\n        'stack' => [\n            'driver' => 'stack',\n            'channels' => ['single'],\n            'ignore_exceptions' => false,\n        ],\n\n        'single' => [\n            'driver' => 'single',\n            'path' => storage_path('logs/laravel.log'),\n            'level' => env('LOG_LEVEL', 'debug'),\n        ],\n\n        'daily' => [\n            'driver' => 'daily',\n            'path' => storage_path('logs/laravel.log'),\n            'level' => env('LOG_LEVEL', 'debug'),\n            'days' => 14,\n        ],\n\n        'slack' => [\n            'driver' => 'slack',\n            'url' => env('LOG_SLACK_WEBHOOK_URL'),\n            'username' => 'Laravel Log',\n            'emoji' => ':boom:',\n            'level' => env('LOG_LEVEL', 'critical'),\n        ],\n\n        'papertrail' => [\n            'driver' => 'monolog',\n            'level' => env('LOG_LEVEL', 'debug'),\n            'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class),\n            'handler_with' => [\n                'host' => env('PAPERTRAIL_URL'),\n                'port' => env('PAPERTRAIL_PORT'),\n                'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),\n            ],\n        ],\n\n        'stderr' => [\n            'driver' => 'monolog',\n            'level' => env('LOG_LEVEL', 'debug'),\n            'handler' => StreamHandler::class,\n            'formatter' => env('LOG_STDERR_FORMATTER'),\n            'with' => [\n                'stream' => 'php://stderr',\n            ],\n        ],\n\n        'syslog' => [\n            'driver' => 'syslog',\n            'level' => env('LOG_LEVEL', 'debug'),\n        ],\n\n        'errorlog' => [\n            'driver' => 'errorlog',\n            'level' => env('LOG_LEVEL', 'debug'),\n        ],\n\n        'null' => [\n            'driver' => 'monolog',\n            'handler' => NullHandler::class,\n        ],\n\n        'emergency' => [\n            'path' => storage_path('logs/laravel.log'),\n        ],\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/config/mail.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Mailer\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default mailer that is used to send any email\n    | messages sent by your application. Alternative mailers may be setup\n    | and used as needed; however, this mailer will be used by default.\n    |\n    */\n\n    'default' => env('MAIL_MAILER', 'smtp'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Mailer Configurations\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure all of the mailers used by your application plus\n    | their respective settings. Several examples have been configured for\n    | you and you are free to add your own as your application requires.\n    |\n    | Laravel supports a variety of mail \"transport\" drivers to be used while\n    | sending an e-mail. You will specify which one you are using for your\n    | mailers below. You are free to add additional mailers as required.\n    |\n    | Supported: \"smtp\", \"sendmail\", \"mailgun\", \"ses\",\n    |            \"postmark\", \"log\", \"array\", \"failover\"\n    |\n    */\n\n    'mailers' => [\n        'smtp' => [\n            'transport' => 'smtp',\n            'host' => env('MAIL_HOST', 'smtp.mailgun.org'),\n            'port' => env('MAIL_PORT', 587),\n            'encryption' => env('MAIL_ENCRYPTION', 'tls'),\n            'username' => env('MAIL_USERNAME'),\n            'password' => env('MAIL_PASSWORD'),\n            'timeout' => null,\n            'local_domain' => env('MAIL_EHLO_DOMAIN'),\n        ],\n\n        'ses' => [\n            'transport' => 'ses',\n        ],\n\n        'mailgun' => [\n            'transport' => 'mailgun',\n        ],\n\n        'postmark' => [\n            'transport' => 'postmark',\n        ],\n\n        'sendmail' => [\n            'transport' => 'sendmail',\n            'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'),\n        ],\n\n        'log' => [\n            'transport' => 'log',\n            'channel' => env('MAIL_LOG_CHANNEL'),\n        ],\n\n        'array' => [\n            'transport' => 'array',\n        ],\n\n        'failover' => [\n            'transport' => 'failover',\n            'mailers' => [\n                'smtp',\n                'log',\n            ],\n        ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Global \"From\" Address\n    |--------------------------------------------------------------------------\n    |\n    | You may wish for all e-mails sent by your application to be sent from\n    | the same address. Here, you may specify a name and address that is\n    | used globally for all e-mails that are sent by your application.\n    |\n    */\n\n    'from' => [\n        'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),\n        'name' => env('MAIL_FROM_NAME', 'Example'),\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Markdown Mail Settings\n    |--------------------------------------------------------------------------\n    |\n    | If you are using Markdown based email rendering, you may configure your\n    | theme and component paths here, allowing you to customize the design\n    | of the emails. Or, you may simply stick with the Laravel defaults!\n    |\n    */\n\n    'markdown' => [\n        'theme' => 'default',\n\n        'paths' => [\n            resource_path('views/vendor/mail'),\n        ],\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/config/queue.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Queue Connection Name\n    |--------------------------------------------------------------------------\n    |\n    | Laravel's queue API supports an assortment of back-ends via a single\n    | API, giving you convenient access to each back-end using the same\n    | syntax for every one. Here you may define a default connection.\n    |\n    */\n\n    'default' => env('QUEUE_CONNECTION', 'sync'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Queue Connections\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure the connection information for each server that\n    | is used by your application. A default configuration has been added\n    | for each back-end shipped with Laravel. You are free to add more.\n    |\n    | Drivers: \"sync\", \"database\", \"beanstalkd\", \"sqs\", \"redis\", \"null\"\n    |\n    */\n\n    'connections' => [\n\n        'sync' => [\n            'driver' => 'sync',\n        ],\n\n        'database' => [\n            'driver' => 'database',\n            'table' => 'jobs',\n            'queue' => 'default',\n            'retry_after' => 90,\n            'after_commit' => false,\n        ],\n\n        'beanstalkd' => [\n            'driver' => 'beanstalkd',\n            'host' => 'localhost',\n            'queue' => 'default',\n            'retry_after' => 90,\n            'block_for' => 0,\n            'after_commit' => false,\n        ],\n\n        'sqs' => [\n            'driver' => 'sqs',\n            'key' => env('AWS_ACCESS_KEY_ID'),\n            'secret' => env('AWS_SECRET_ACCESS_KEY'),\n            'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),\n            'queue' => env('SQS_QUEUE', 'default'),\n            'suffix' => env('SQS_SUFFIX'),\n            'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),\n            'after_commit' => false,\n        ],\n\n        'redis' => [\n            'driver' => 'redis',\n            'connection' => 'default',\n            'queue' => env('REDIS_QUEUE', 'default'),\n            'retry_after' => 90,\n            'block_for' => null,\n            'after_commit' => false,\n        ],\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Failed Queue Jobs\n    |--------------------------------------------------------------------------\n    |\n    | These options configure the behavior of failed queue job logging so you\n    | can control which database and table are used to store the jobs that\n    | have failed. You may change them to any database / table you wish.\n    |\n    */\n\n    'failed' => [\n        'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),\n        'database' => env('DB_CONNECTION', 'mysql'),\n        'table' => 'failed_jobs',\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/config/sanctum.php",
    "content": "<?php\n\nuse Laravel\\Sanctum\\Sanctum;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Stateful Domains\n    |--------------------------------------------------------------------------\n    |\n    | Requests from the following domains / hosts will receive stateful API\n    | authentication cookies. Typically, these should include your local\n    | and production domains which access your API via a frontend SPA.\n    |\n    */\n\n    'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(\n        '%s%s',\n        'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',\n        Sanctum::currentApplicationUrlWithPort()\n    ))),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Sanctum Guards\n    |--------------------------------------------------------------------------\n    |\n    | This array contains the authentication guards that will be checked when\n    | Sanctum is trying to authenticate a request. If none of these guards\n    | are able to authenticate the request, Sanctum will use the bearer\n    | token that's present on an incoming request for authentication.\n    |\n    */\n\n    'guard' => ['web'],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Expiration Minutes\n    |--------------------------------------------------------------------------\n    |\n    | This value controls the number of minutes until an issued token will be\n    | considered expired. If this value is null, personal access tokens do\n    | not expire. This won't tweak the lifetime of first-party sessions.\n    |\n    */\n\n    'expiration' => null,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Sanctum Middleware\n    |--------------------------------------------------------------------------\n    |\n    | When authenticating your first-party SPA with Sanctum you may need to\n    | customize some of the middleware Sanctum uses while processing the\n    | request. You may change the middleware listed below as required.\n    |\n    */\n\n    'middleware' => [\n        'verify_csrf_token' => App\\Http\\Middleware\\VerifyCsrfToken::class,\n        'encrypt_cookies' => App\\Http\\Middleware\\EncryptCookies::class,\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/config/services.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Third Party Services\n    |--------------------------------------------------------------------------\n    |\n    | This file is for storing the credentials for third party services such\n    | as Mailgun, Postmark, AWS and more. This file provides the de facto\n    | location for this type of information, allowing packages to have\n    | a conventional file to locate the various service credentials.\n    |\n    */\n\n    'mailgun' => [\n        'domain' => env('MAILGUN_DOMAIN'),\n        'secret' => env('MAILGUN_SECRET'),\n        'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),\n        'scheme' => 'https',\n    ],\n\n    'postmark' => [\n        'token' => env('POSTMARK_TOKEN'),\n    ],\n\n    'ses' => [\n        'key' => env('AWS_ACCESS_KEY_ID'),\n        'secret' => env('AWS_SECRET_ACCESS_KEY'),\n        'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/config/session.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Str;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Session Driver\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default session \"driver\" that will be used on\n    | requests. By default, we will use the lightweight native driver but\n    | you may specify any of the other wonderful drivers provided here.\n    |\n    | Supported: \"file\", \"cookie\", \"database\", \"apc\",\n    |            \"memcached\", \"redis\", \"dynamodb\", \"array\"\n    |\n    */\n\n    'driver' => env('SESSION_DRIVER', 'file'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Lifetime\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the number of minutes that you wish the session\n    | to be allowed to remain idle before it expires. If you want them\n    | to immediately expire on the browser closing, set that option.\n    |\n    */\n\n    'lifetime' => env('SESSION_LIFETIME', 120),\n\n    'expire_on_close' => false,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Encryption\n    |--------------------------------------------------------------------------\n    |\n    | This option allows you to easily specify that all of your session data\n    | should be encrypted before it is stored. All encryption will be run\n    | automatically by Laravel and you can use the Session like normal.\n    |\n    */\n\n    'encrypt' => false,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session File Location\n    |--------------------------------------------------------------------------\n    |\n    | When using the native session driver, we need a location where session\n    | files may be stored. A default has been set for you but a different\n    | location may be specified. This is only needed for file sessions.\n    |\n    */\n\n    'files' => storage_path('framework/sessions'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Database Connection\n    |--------------------------------------------------------------------------\n    |\n    | When using the \"database\" or \"redis\" session drivers, you may specify a\n    | connection that should be used to manage these sessions. This should\n    | correspond to a connection in your database configuration options.\n    |\n    */\n\n    'connection' => env('SESSION_CONNECTION'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Database Table\n    |--------------------------------------------------------------------------\n    |\n    | When using the \"database\" session driver, you may specify the table we\n    | should use to manage the sessions. Of course, a sensible default is\n    | provided for you; however, you are free to change this as needed.\n    |\n    */\n\n    'table' => 'sessions',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Cache Store\n    |--------------------------------------------------------------------------\n    |\n    | While using one of the framework's cache driven session backends you may\n    | list a cache store that should be used for these sessions. This value\n    | must match with one of the application's configured cache \"stores\".\n    |\n    | Affects: \"apc\", \"dynamodb\", \"memcached\", \"redis\"\n    |\n    */\n\n    'store' => env('SESSION_STORE'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Sweeping Lottery\n    |--------------------------------------------------------------------------\n    |\n    | Some session drivers must manually sweep their storage location to get\n    | rid of old sessions from storage. Here are the chances that it will\n    | happen on a given request. By default, the odds are 2 out of 100.\n    |\n    */\n\n    'lottery' => [2, 100],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Cookie Name\n    |--------------------------------------------------------------------------\n    |\n    | Here you may change the name of the cookie used to identify a session\n    | instance by ID. The name specified here will get used every time a\n    | new session cookie is created by the framework for every driver.\n    |\n    */\n\n    'cookie' => env(\n        'SESSION_COOKIE',\n        Str::slug(env('APP_NAME', 'laravel'), '_').'_session'\n    ),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Cookie Path\n    |--------------------------------------------------------------------------\n    |\n    | The session cookie path determines the path for which the cookie will\n    | be regarded as available. Typically, this will be the root path of\n    | your application but you are free to change this when necessary.\n    |\n    */\n\n    'path' => '/',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Cookie Domain\n    |--------------------------------------------------------------------------\n    |\n    | Here you may change the domain of the cookie used to identify a session\n    | in your application. This will determine which domains the cookie is\n    | available to in your application. A sensible default has been set.\n    |\n    */\n\n    'domain' => env('SESSION_DOMAIN'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | HTTPS Only Cookies\n    |--------------------------------------------------------------------------\n    |\n    | By setting this option to true, session cookies will only be sent back\n    | to the server if the browser has a HTTPS connection. This will keep\n    | the cookie from being sent to you when it can't be done securely.\n    |\n    */\n\n    'secure' => env('SESSION_SECURE_COOKIE'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | HTTP Access Only\n    |--------------------------------------------------------------------------\n    |\n    | Setting this value to true will prevent JavaScript from accessing the\n    | value of the cookie and the cookie will only be accessible through\n    | the HTTP protocol. You are free to modify this option if needed.\n    |\n    */\n\n    'http_only' => true,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Same-Site Cookies\n    |--------------------------------------------------------------------------\n    |\n    | This option determines how your cookies behave when cross-site requests\n    | take place, and can be used to mitigate CSRF attacks. By default, we\n    | will set this value to \"lax\" since this is a secure default value.\n    |\n    | Supported: \"lax\", \"strict\", \"none\", null\n    |\n    */\n\n    'same_site' => 'lax',\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/config/view.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | View Storage Paths\n    |--------------------------------------------------------------------------\n    |\n    | Most templating systems load templates from disk. Here you may specify\n    | an array of paths that should be checked for your views. Of course\n    | the usual Laravel view path has already been registered for you.\n    |\n    */\n\n    'paths' => [\n        resource_path('views'),\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Compiled View Path\n    |--------------------------------------------------------------------------\n    |\n    | This option determines where all the compiled Blade templates will be\n    | stored for your application. Typically, this is within the storage\n    | directory. However, as usual, you are free to change this value.\n    |\n    */\n\n    'compiled' => env(\n        'VIEW_COMPILED_PATH',\n        realpath(storage_path('framework/views'))\n    ),\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/database/.gitignore",
    "content": "*.sqlite*\n"
  },
  {
    "path": "playgrounds/svelte5/database/factories/UserFactory.php",
    "content": "<?php\n\nnamespace Database\\Factories;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\nuse Illuminate\\Support\\Str;\n\n/**\n * @extends \\Illuminate\\Database\\Eloquent\\Factories\\Factory<\\App\\Models\\User>\n */\nclass UserFactory extends Factory\n{\n    /**\n     * Define the model's default state.\n     *\n     * @return array<string, mixed>\n     */\n    public function definition()\n    {\n        return [\n            'name' => fake()->name(),\n            'email' => fake()->unique()->safeEmail(),\n            'email_verified_at' => now(),\n            'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password\n            'remember_token' => Str::random(10),\n        ];\n    }\n\n    /**\n     * Indicate that the model's email address should be unverified.\n     *\n     * @return static\n     */\n    public function unverified()\n    {\n        return $this->state(fn (array $attributes) => [\n            'email_verified_at' => null,\n        ]);\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/database/migrations/2014_10_12_000000_create_users_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('users', function (Blueprint $table) {\n            $table->id();\n            $table->string('name');\n            $table->string('email')->unique();\n            $table->timestamp('email_verified_at')->nullable();\n            $table->string('password');\n            $table->rememberToken();\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('users');\n    }\n};\n"
  },
  {
    "path": "playgrounds/svelte5/database/migrations/2014_10_12_100000_create_password_resets_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('password_resets', function (Blueprint $table) {\n            $table->string('email')->index();\n            $table->string('token');\n            $table->timestamp('created_at')->nullable();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('password_resets');\n    }\n};\n"
  },
  {
    "path": "playgrounds/svelte5/database/migrations/2019_08_19_000000_create_failed_jobs_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('failed_jobs', function (Blueprint $table) {\n            $table->id();\n            $table->string('uuid')->unique();\n            $table->text('connection');\n            $table->text('queue');\n            $table->longText('payload');\n            $table->longText('exception');\n            $table->timestamp('failed_at')->useCurrent();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('failed_jobs');\n    }\n};\n"
  },
  {
    "path": "playgrounds/svelte5/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('personal_access_tokens', function (Blueprint $table) {\n            $table->id();\n            $table->morphs('tokenable');\n            $table->string('name');\n            $table->string('token', 64)->unique();\n            $table->text('abilities')->nullable();\n            $table->timestamp('last_used_at')->nullable();\n            $table->timestamp('expires_at')->nullable();\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('personal_access_tokens');\n    }\n};\n"
  },
  {
    "path": "playgrounds/svelte5/database/seeders/DatabaseSeeder.php",
    "content": "<?php\n\nnamespace Database\\Seeders;\n\n// use Illuminate\\Database\\Console\\Seeds\\WithoutModelEvents;\nuse Illuminate\\Database\\Seeder;\n\nclass DatabaseSeeder extends Seeder\n{\n    /**\n     * Seed the application's database.\n     *\n     * @return void\n     */\n    public function run()\n    {\n        // \\App\\Models\\User::factory(10)->create();\n\n        // \\App\\Models\\User::factory()->create([\n        //     'name' => 'Test User',\n        //     'email' => 'test@example.com',\n        // ]);\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/init.sh",
    "content": "#!/bin/bash\nset -e\n\n# Install PHP dependencies via Composer\nif [ ! -d \"vendor\" ]; then\n    echo \"Installing PHP dependencies...\"\n    composer install\nelse\n    echo \"PHP dependencies already installed\"\nfi\n\n# Install Node.js dependencies via pnpm\nif [ ! -d \"node_modules\" ]; then\n    echo \"Installing Node.js dependencies...\"\n    pnpm install\nelse\n    echo \"Node.js dependencies already installed\"\nfi\n\n# Set up environment configuration\nif [ ! -f \".env\" ]; then\n    echo \"Creating environment configuration...\"\n    cp .env.example .env\n    php artisan key:generate\nelse\n    echo \"Environment configuration already exists\"\nfi\n\n# Set up SQLite database\nif [ ! -f \"database/database.sqlite\" ]; then\n    echo \"Creating SQLite database...\"\n    touch database/database.sqlite\n    echo \"Running fresh migrations with seed data...\"\n    php artisan migrate:fresh --seed\nelse\n    echo \"Database already exists\"\nfi\n\n# Ensure database is up to date\necho \"Running any pending migrations...\"\nphp artisan migrate\n"
  },
  {
    "path": "playgrounds/svelte5/lang/en/auth.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Authentication Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines are used during authentication for various\n    | messages that we need to display to the user. You are free to modify\n    | these language lines according to your application's requirements.\n    |\n    */\n\n    'failed' => 'These credentials do not match our records.',\n    'password' => 'The provided password is incorrect.',\n    'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/lang/en/pagination.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Pagination Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines are used by the paginator library to build\n    | the simple pagination links. You are free to change them to anything\n    | you want to customize your views to better match your application.\n    |\n    */\n\n    'previous' => '&laquo; Previous',\n    'next' => 'Next &raquo;',\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/lang/en/passwords.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Password Reset Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines are the default lines which match reasons\n    | that are given by the password broker for a password update attempt\n    | has failed, such as for an invalid token or invalid new password.\n    |\n    */\n\n    'reset' => 'Your password has been reset!',\n    'sent' => 'We have emailed your password reset link!',\n    'throttled' => 'Please wait before retrying.',\n    'token' => 'This password reset token is invalid.',\n    'user' => \"We can't find a user with that email address.\",\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/lang/en/validation.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Validation Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines contain the default error messages used by\n    | the validator class. Some of these rules have multiple versions such\n    | as the size rules. Feel free to tweak each of these messages here.\n    |\n    */\n\n    'accepted' => 'The :attribute must be accepted.',\n    'accepted_if' => 'The :attribute must be accepted when :other is :value.',\n    'active_url' => 'The :attribute is not a valid URL.',\n    'after' => 'The :attribute must be a date after :date.',\n    'after_or_equal' => 'The :attribute must be a date after or equal to :date.',\n    'alpha' => 'The :attribute must only contain letters.',\n    'alpha_dash' => 'The :attribute must only contain letters, numbers, dashes and underscores.',\n    'alpha_num' => 'The :attribute must only contain letters and numbers.',\n    'array' => 'The :attribute must be an array.',\n    'ascii' => 'The :attribute must only contain single-byte alphanumeric characters and symbols.',\n    'before' => 'The :attribute must be a date before :date.',\n    'before_or_equal' => 'The :attribute must be a date before or equal to :date.',\n    'between' => [\n        'array' => 'The :attribute must have between :min and :max items.',\n        'file' => 'The :attribute must be between :min and :max kilobytes.',\n        'numeric' => 'The :attribute must be between :min and :max.',\n        'string' => 'The :attribute must be between :min and :max characters.',\n    ],\n    'boolean' => 'The :attribute field must be true or false.',\n    'confirmed' => 'The :attribute confirmation does not match.',\n    'current_password' => 'The password is incorrect.',\n    'date' => 'The :attribute is not a valid date.',\n    'date_equals' => 'The :attribute must be a date equal to :date.',\n    'date_format' => 'The :attribute does not match the format :format.',\n    'decimal' => 'The :attribute must have :decimal decimal places.',\n    'declined' => 'The :attribute must be declined.',\n    'declined_if' => 'The :attribute must be declined when :other is :value.',\n    'different' => 'The :attribute and :other must be different.',\n    'digits' => 'The :attribute must be :digits digits.',\n    'digits_between' => 'The :attribute must be between :min and :max digits.',\n    'dimensions' => 'The :attribute has invalid image dimensions.',\n    'distinct' => 'The :attribute field has a duplicate value.',\n    'doesnt_end_with' => 'The :attribute may not end with one of the following: :values.',\n    'doesnt_start_with' => 'The :attribute may not start with one of the following: :values.',\n    'email' => 'The :attribute must be a valid email address.',\n    'ends_with' => 'The :attribute must end with one of the following: :values.',\n    'enum' => 'The selected :attribute is invalid.',\n    'exists' => 'The selected :attribute is invalid.',\n    'file' => 'The :attribute must be a file.',\n    'filled' => 'The :attribute field must have a value.',\n    'gt' => [\n        'array' => 'The :attribute must have more than :value items.',\n        'file' => 'The :attribute must be greater than :value kilobytes.',\n        'numeric' => 'The :attribute must be greater than :value.',\n        'string' => 'The :attribute must be greater than :value characters.',\n    ],\n    'gte' => [\n        'array' => 'The :attribute must have :value items or more.',\n        'file' => 'The :attribute must be greater than or equal to :value kilobytes.',\n        'numeric' => 'The :attribute must be greater than or equal to :value.',\n        'string' => 'The :attribute must be greater than or equal to :value characters.',\n    ],\n    'image' => 'The :attribute must be an image.',\n    'in' => 'The selected :attribute is invalid.',\n    'in_array' => 'The :attribute field does not exist in :other.',\n    'integer' => 'The :attribute must be an integer.',\n    'ip' => 'The :attribute must be a valid IP address.',\n    'ipv4' => 'The :attribute must be a valid IPv4 address.',\n    'ipv6' => 'The :attribute must be a valid IPv6 address.',\n    'json' => 'The :attribute must be a valid JSON string.',\n    'lowercase' => 'The :attribute must be lowercase.',\n    'lt' => [\n        'array' => 'The :attribute must have less than :value items.',\n        'file' => 'The :attribute must be less than :value kilobytes.',\n        'numeric' => 'The :attribute must be less than :value.',\n        'string' => 'The :attribute must be less than :value characters.',\n    ],\n    'lte' => [\n        'array' => 'The :attribute must not have more than :value items.',\n        'file' => 'The :attribute must be less than or equal to :value kilobytes.',\n        'numeric' => 'The :attribute must be less than or equal to :value.',\n        'string' => 'The :attribute must be less than or equal to :value characters.',\n    ],\n    'mac_address' => 'The :attribute must be a valid MAC address.',\n    'max' => [\n        'array' => 'The :attribute must not have more than :max items.',\n        'file' => 'The :attribute must not be greater than :max kilobytes.',\n        'numeric' => 'The :attribute must not be greater than :max.',\n        'string' => 'The :attribute must not be greater than :max characters.',\n    ],\n    'max_digits' => 'The :attribute must not have more than :max digits.',\n    'mimes' => 'The :attribute must be a file of type: :values.',\n    'mimetypes' => 'The :attribute must be a file of type: :values.',\n    'min' => [\n        'array' => 'The :attribute must have at least :min items.',\n        'file' => 'The :attribute must be at least :min kilobytes.',\n        'numeric' => 'The :attribute must be at least :min.',\n        'string' => 'The :attribute must be at least :min characters.',\n    ],\n    'min_digits' => 'The :attribute must have at least :min digits.',\n    'multiple_of' => 'The :attribute must be a multiple of :value.',\n    'not_in' => 'The selected :attribute is invalid.',\n    'not_regex' => 'The :attribute format is invalid.',\n    'numeric' => 'The :attribute must be a number.',\n    'password' => [\n        'letters' => 'The :attribute must contain at least one letter.',\n        'mixed' => 'The :attribute must contain at least one uppercase and one lowercase letter.',\n        'numbers' => 'The :attribute must contain at least one number.',\n        'symbols' => 'The :attribute must contain at least one symbol.',\n        'uncompromised' => 'The given :attribute has appeared in a data leak. Please choose a different :attribute.',\n    ],\n    'present' => 'The :attribute field must be present.',\n    'prohibited' => 'The :attribute field is prohibited.',\n    'prohibited_if' => 'The :attribute field is prohibited when :other is :value.',\n    'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.',\n    'prohibits' => 'The :attribute field prohibits :other from being present.',\n    'regex' => 'The :attribute format is invalid.',\n    'required' => 'The :attribute field is required.',\n    'required_array_keys' => 'The :attribute field must contain entries for: :values.',\n    'required_if' => 'The :attribute field is required when :other is :value.',\n    'required_if_accepted' => 'The :attribute field is required when :other is accepted.',\n    'required_unless' => 'The :attribute field is required unless :other is in :values.',\n    'required_with' => 'The :attribute field is required when :values is present.',\n    'required_with_all' => 'The :attribute field is required when :values are present.',\n    'required_without' => 'The :attribute field is required when :values is not present.',\n    'required_without_all' => 'The :attribute field is required when none of :values are present.',\n    'same' => 'The :attribute and :other must match.',\n    'size' => [\n        'array' => 'The :attribute must contain :size items.',\n        'file' => 'The :attribute must be :size kilobytes.',\n        'numeric' => 'The :attribute must be :size.',\n        'string' => 'The :attribute must be :size characters.',\n    ],\n    'starts_with' => 'The :attribute must start with one of the following: :values.',\n    'string' => 'The :attribute must be a string.',\n    'timezone' => 'The :attribute must be a valid timezone.',\n    'unique' => 'The :attribute has already been taken.',\n    'uploaded' => 'The :attribute failed to upload.',\n    'uppercase' => 'The :attribute must be uppercase.',\n    'url' => 'The :attribute must be a valid URL.',\n    'ulid' => 'The :attribute must be a valid ULID.',\n    'uuid' => 'The :attribute must be a valid UUID.',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Custom Validation Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify custom validation messages for attributes using the\n    | convention \"attribute.rule\" to name the lines. This makes it quick to\n    | specify a specific custom language line for a given attribute rule.\n    |\n    */\n\n    'custom' => [\n        'attribute-name' => [\n            'rule-name' => 'custom-message',\n        ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Custom Validation Attributes\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines are used to swap our attribute placeholder\n    | with something more reader friendly such as \"E-Mail Address\" instead\n    | of \"email\". This simply helps us make our message more expressive.\n    |\n    */\n\n    'attributes' => [],\n\n];\n"
  },
  {
    "path": "playgrounds/svelte5/package.json",
    "content": "{\n  \"name\": \"@inertiajs/svelte5-playground\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"vite build && vite build --ssr\",\n    \"check\": \"svelte-check --tsconfig ./tsconfig.json\",\n    \"check:watch\": \"svelte-check --tsconfig ./tsconfig.json --watch\"\n  },\n  \"devDependencies\": {\n    \"@inertiajs/core\": \"workspace:*\",\n    \"@inertiajs/svelte\": \"workspace:*\",\n    \"@sveltejs/vite-plugin-svelte\": \"^6.2.4\",\n    \"@tailwindcss/vite\": \"^4.2.1\",\n    \"@tsconfig/svelte\": \"^5.0.8\",\n    \"axios\": \"^1.13.5\",\n    \"laravel-vite-plugin\": \"^2.1.0\",\n    \"lodash\": \"^4.17.23\",\n    \"svelte\": \"^5.53.5\",\n    \"svelte-check\": \"^4.4.4\",\n    \"tailwindcss\": \"^4.2.1\",\n    \"typescript\": \"^5.9.3\",\n    \"vite\": \"^7.3.1\"\n  }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/phpunit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:noNamespaceSchemaLocation=\"./vendor/phpunit/phpunit/phpunit.xsd\"\n         bootstrap=\"vendor/autoload.php\"\n         colors=\"true\"\n>\n    <testsuites>\n        <testsuite name=\"Unit\">\n            <directory suffix=\"Test.php\">./tests/Unit</directory>\n        </testsuite>\n        <testsuite name=\"Feature\">\n            <directory suffix=\"Test.php\">./tests/Feature</directory>\n        </testsuite>\n    </testsuites>\n    <coverage processUncoveredFiles=\"true\">\n        <include>\n            <directory suffix=\".php\">./app</directory>\n        </include>\n    </coverage>\n    <php>\n        <env name=\"APP_ENV\" value=\"testing\"/>\n        <env name=\"BCRYPT_ROUNDS\" value=\"4\"/>\n        <env name=\"CACHE_DRIVER\" value=\"array\"/>\n        <!-- <env name=\"DB_CONNECTION\" value=\"sqlite\"/> -->\n        <!-- <env name=\"DB_DATABASE\" value=\":memory:\"/> -->\n        <env name=\"MAIL_MAILER\" value=\"array\"/>\n        <env name=\"QUEUE_CONNECTION\" value=\"sync\"/>\n        <env name=\"SESSION_DRIVER\" value=\"array\"/>\n        <env name=\"TELESCOPE_ENABLED\" value=\"false\"/>\n    </php>\n</phpunit>\n"
  },
  {
    "path": "playgrounds/svelte5/public/.htaccess",
    "content": "<IfModule mod_rewrite.c>\n    <IfModule mod_negotiation.c>\n        Options -MultiViews -Indexes\n    </IfModule>\n\n    RewriteEngine On\n\n    # Handle Authorization Header\n    RewriteCond %{HTTP:Authorization} .\n    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]\n\n    # Redirect Trailing Slashes If Not A Folder...\n    RewriteCond %{REQUEST_FILENAME} !-d\n    RewriteCond %{REQUEST_URI} (.+)/$\n    RewriteRule ^ %1 [L,R=301]\n\n    # Send Requests To Front Controller...\n    RewriteCond %{REQUEST_FILENAME} !-d\n    RewriteCond %{REQUEST_FILENAME} !-f\n    RewriteRule ^ index.php [L]\n</IfModule>\n"
  },
  {
    "path": "playgrounds/svelte5/public/index.php",
    "content": "<?php\n\nuse Illuminate\\Contracts\\Http\\Kernel;\nuse Illuminate\\Http\\Request;\n\ndefine('LARAVEL_START', microtime(true));\n\n/*\n|--------------------------------------------------------------------------\n| Check If The Application Is Under Maintenance\n|--------------------------------------------------------------------------\n|\n| If the application is in maintenance / demo mode via the \"down\" command\n| we will load this file so that any pre-rendered content can be shown\n| instead of starting the framework, which could cause an exception.\n|\n*/\n\nif (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {\n    require $maintenance;\n}\n\n/*\n|--------------------------------------------------------------------------\n| Register The Auto Loader\n|--------------------------------------------------------------------------\n|\n| Composer provides a convenient, automatically generated class loader for\n| this application. We just need to utilize it! We'll simply require it\n| into the script here so we don't need to manually load our classes.\n|\n*/\n\nrequire __DIR__.'/../vendor/autoload.php';\n\n/*\n|--------------------------------------------------------------------------\n| Run The Application\n|--------------------------------------------------------------------------\n|\n| Once we have the application, we can handle the incoming request using\n| the application's HTTP kernel. Then, we will send the response back\n| to this client's browser, allowing them to enjoy our application.\n|\n*/\n\n$app = require_once __DIR__.'/../bootstrap/app.php';\n\n$kernel = $app->make(Kernel::class);\n\n$response = $kernel->handle(\n    $request = Request::capture()\n)->send();\n\n$kernel->terminate($request, $response);\n"
  },
  {
    "path": "playgrounds/svelte5/public/robots.txt",
    "content": "User-agent: *\nDisallow:\n"
  },
  {
    "path": "playgrounds/svelte5/resources/css/app.css",
    "content": "@import 'tailwindcss';\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Components/Image.svelte",
    "content": "<script>\n  import { onMount } from 'svelte'\n\n  let { id, url } = $props()\n\n  let loaded = $state(false)\n  let imageElement\n\n  onMount(() => {\n    if (imageElement?.complete) {\n      loaded = true\n    }\n  })\n\n  function handleLoad() {\n    loaded = true\n  }\n</script>\n\n<div class=\"relative aspect-square overflow-hidden rounded-lg bg-gray-200\">\n  {#if !loaded}\n    <div class=\"absolute inset-0 animate-pulse bg-gray-300\" aria-hidden=\"true\" />\n  {/if}\n\n  <img\n    bind:this={imageElement}\n    src={url}\n    loading=\"lazy\"\n    decoding=\"async\"\n    class={`h-full w-full object-cover transition duration-500 ease-out ${\n      loaded ? 'blur-0 scale-100 opacity-100' : 'scale-105 opacity-0 blur-sm'\n    }`}\n    on:load={handleLoad}\n    alt=\"\"\n  />\n\n  <span class=\"pointer-events-none absolute bottom-2 left-2 rounded bg-black/50 px-2 py-1 text-sm text-white\">\n    {id}\n  </span>\n</div>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Components/Layout.svelte",
    "content": "<script>\n  import { inertia, page } from '@inertiajs/svelte'\n\n  let { children } = $props()\n</script>\n\n<nav class=\"flex items-center space-x-6 bg-slate-800 px-10 py-6 text-white\">\n  <div class=\"rounded-lg bg-slate-700 px-4 py-1\">{$page.props.appName}</div>\n  <a href=\"/\" use:inertia class=\"hover:underline\">Home</a>\n  <a href=\"/users\" use:inertia class=\"hover:underline\">Users</a>\n  <a href=\"/article\" use:inertia class=\"hover:underline\">Article</a>\n  <a href=\"/form\" use:inertia class=\"hover:underline\">useForm</a>\n  <a href=\"/form-component\" use:inertia class=\"hover:underline\">{'<Form>'}</a>\n  <a href=\"/form-component/precognition\" use:inertia class=\"hover:underline\">Precognition</a>\n  <a href=\"/photo-grid\" use:inertia class=\"hover:underline\">Photo Grid</a>\n  <a href=\"/photo-grid/horizontal\" use:inertia class=\"hover:underline\">Photo Row</a>\n  <a href=\"/data-table\" use:inertia class=\"hover:underline\">Table</a>\n  <a href=\"/once/1\" use:inertia class=\"hover:underline\">Once</a>\n  <a href=\"/flash\" use:inertia class=\"hover:underline\">Flash</a>\n  <button use:inertia={{ method: 'post', href: '/logout' }} type=\"button\" class=\"hover:underline\">Logout</button>\n</nav>\n\n<main class=\"px-10 py-8\">\n  {@render children()}\n</main>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Components/Spinner.svelte",
    "content": "<script>\n  let className = ''\n  export { className as class }\n</script>\n\n<svg class={`animate-spin text-black ${className}`} xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n  <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n  <path\n    class=\"opacity-75\"\n    fill=\"currentColor\"\n    d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n  ></path>\n</svg>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Components/TestGrid.svelte",
    "content": "<script>\n  let className = ''\n  export { className as class }\n</script>\n\n<div {...$$restProps} class=\"mt-6 grid grid-cols-3 gap-4 {className}\">\n  <slot />\n</div>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Components/TestGridItem.svelte",
    "content": "<script>\n  let className\n  export { className as class }\n</script>\n\n<div {...$$restProps} class=\"rounded-sm border border-gray-300 p-4 text-sm text-gray-500 {className}\">\n  {#if $$slots.title}\n    <div class=\"mb-2 font-bold\">\n      <slot name=\"title\" />\n    </div>\n  {/if}\n\n  <slot />\n</div>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/Article.svelte",
    "content": "<script module>\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  let { appName } = $props()\n</script>\n\n<svelte:head>\n  <title>Article - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Article</h1>\n\n<article class=\"max-w-3xl\">\n  <p class=\"my-6\">\n    Sunt culpa sit sunt enim aliquip. Esse ea ea quis voluptate. Enim consectetur aliqua ex ex magna cupidatat id minim\n    sit elit. Amet pariatur occaecat pariatur duis eiusmod dolore magna. Et commodo cupidatat in commodo elit cupidatat\n    minim qui id non enim ad. Culpa aliquip ad Lorem sit consectetur ullamco culpa duis nisi et fugiat mollit eiusmod.\n    Laboris voluptate veniam consequat proident in nulla irure velit.\n  </p>\n  <p class=\"my-6\">\n    Sit sint laboris sunt eiusmod ipsum laborum eiusmod amet commodo exercitation in duis magna. Proident sunt minim in\n    elit qui. Id pariatur commodo fugiat excepteur in deserunt Lorem ipsum occaecat est. Excepteur sit tempor ipsum ex\n    officia veniam enim amet velit fugiat mollit cillum. Incididunt aliqua nulla id occaecat nulla. Non ea ad est\n    occaecat deserunt officia qui commodo exercitation.\n  </p>\n  <p class=\"my-6\">\n    Voluptate laborum quis aliqua ullamco magna amet ullamco laborum qui cillum eu. Dolore dolore aliqua proident\n    proident sunt ipsum in. Enim velit dolore labore dolor quis incididunt duis culpa Lorem. Eu adipisicing non elit\n    fugiat voluptate labore ipsum dolore consectetur commodo. Et in et cillum duis consequat quis ex eu commodo. Eiusmod\n    aliqua excepteur consectetur eiusmod aute et consectetur sit pariatur dolore qui officia pariatur.\n  </p>\n  <p class=\"my-6\">\n    Non sunt eu mollit qui reprehenderit. Aute culpa anim voluptate do in esse duis laborum ad dolore. Ullamco nisi in\n    nostrud officia do. Duis pariatur officia id duis. Deserunt ad incididunt est sint consectetur reprehenderit mollit\n    est Lorem ea pariatur anim dolor adipisicing. Nostrud irure magna nostrud laboris aute sunt veniam laboris veniam\n    incididunt sit. Nulla proident ad aliqua fugiat culpa sunt est in dolor velit ad irure nulla.\n  </p>\n  <p class=\"my-6\">\n    Do aute laborum deserunt non laborum voluptate voluptate. Anim ut laborum magna sunt cupidatat irure. Cupidatat\n    fugiat minim sint cillum laborum excepteur irure id est irure ad occaecat adipisicing enim. Deserunt nulla anim\n    proident velit irure nostrud est est reprehenderit consequat pariatur qui. Fugiat Lorem sint eu laborum minim\n    pariatur cillum mollit nulla consequat ullamco ex. Ex consectetur ad ut irure fugiat occaecat aliqua exercitation\n    cillum ipsum anim dolore tempor.\n  </p>\n  <p class=\"my-6\">\n    Adipisicing consequat irure fugiat Lorem deserunt aliquip do cupidatat. Lorem labore elit ex qui nostrud qui cillum\n    sunt adipisicing occaecat. Sunt nostrud amet amet cupidatat fugiat Lorem quis nulla id cillum esse eu. Ullamco\n    aliqua dolore irure amet mollit anim velit dolore.\n  </p>\n  <p class=\"my-6\">\n    Veniam cupidatat ipsum ea officia ipsum nisi laborum culpa qui dolore. Aliqua Lorem nisi labore ea velit aliquip\n    irure excepteur eu. Laboris proident duis non labore sunt quis aute tempor laboris enim anim eiusmod.\n  </p>\n  <p class=\"my-6\">\n    Minim proident ut aliqua ea ut culpa fugiat ullamco nisi esse nostrud reprehenderit id. Id id ullamco velit anim\n    nisi magna Lorem tempor. Et veniam occaecat ut labore consequat fugiat duis.\n  </p>\n  <p class=\"my-6\">\n    Adipisicing ea consectetur adipisicing aute eu pariatur enim labore consequat occaecat consectetur minim nisi.\n    Cillum commodo sunt labore reprehenderit. Duis esse excepteur magna tempor eiusmod exercitation Lorem reprehenderit\n    excepteur pariatur. Esse cupidatat occaecat magna do aliquip Lorem. Consectetur adipisicing consequat dolore nostrud\n    esse eu cillum id commodo duis. Aliquip dolor cillum cupidatat fugiat.\n  </p>\n  <h2 id=\"far-down\" class=\"mt-8 text-2xl\">Far down</h2>\n  <p class=\"my-6\">\n    Ex eiusmod id est laborum sunt ex ea aute adipisicing ad magna deserunt duis. Nostrud velit dolore id commodo quis\n    enim fugiat. Sint non quis consectetur voluptate aliqua dolore ad voluptate nulla. Irure sit reprehenderit sint\n    laboris non elit. Duis minim nisi esse dolor. Sit ex in consequat non occaecat commodo irure et. Commodo qui ipsum\n    Lorem magna consequat consequat et minim eiusmod Lorem eiusmod cupidatat voluptate.\n  </p>\n</article>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/Async.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script lang=\"ts\">\n  import { router, useForm } from '@inertiajs/svelte'\n  import TestGrid from '../Components/TestGrid.svelte'\n  import TestGridItem from '../Components/TestGridItem.svelte'\n\n  export let appName\n  export let jonathan: boolean\n  export let taylor: boolean\n  export let joe: boolean\n\n  let reloadCount = 0\n  const form = useForm({ jonathan, taylor, joe })\n\n  $: console.log('watched reload count value', reloadCount)\n\n  function submit() {\n    router.post(\n      '/async/checkbox',\n      {\n        jonathan: $form.jonathan,\n        taylor: $form.taylor,\n        joe: $form.joe,\n      },\n      {\n        async: true,\n      },\n    )\n  }\n\n  function simulateConflict() {\n    router.reload({\n      only: ['sleep'],\n    })\n    router.visit('/sleepy/2')\n  }\n\n  function triggerVisitThenReload() {\n    router.visit('/sleepy/1')\n    router.reload({\n      only: ['sleep'],\n    })\n  }\n\n  function triggerLongReload() {\n    router.reload({\n      only: ['sleep'],\n      onFinish() {\n        console.log('finished reload')\n        reloadCount++\n        console.log('incremented reload count')\n      },\n    })\n  }\n\n  function triggerCancel() {\n    router.post(\n      '/sleepy/3',\n      {},\n      {\n        onCancelToken: (token) => {\n          console.log('onCancelToken')\n\n          setTimeout(() => {\n            console.log('CANCELLING!')\n            token.cancel()\n          }, 1000)\n        },\n      },\n    )\n  }\n\n  function triggerCancelAfterFinish() {\n    let cancelToken\n\n    router.post(\n      '/sleepy/1',\n      {},\n      {\n        onCancelToken: (token) => {\n          console.log('onCancelToken')\n\n          cancelToken = token\n        },\n        onFinish: () => {\n          console.log('onFinish')\n          console.log('CANCELLING!')\n          cancelToken.cancel()\n        },\n      },\n    )\n  }\n</script>\n\n<svelte:head>\n  <title>Async Request - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Async Request</h1>\n<p class=\"mt-6\">Reload Count: {reloadCount}</p>\n\n<TestGrid>\n  <TestGridItem class=\"space-y-4\">\n    <p>Trigger an async reload that takes a moment and immediately programmatically visit another page</p>\n    <button class=\"rounded-sm bg-green-600 px-4 py-2 text-white\" on:click={simulateConflict}>Reload → Visit</button>\n  </TestGridItem>\n\n  <TestGridItem class=\"space-y-4\">\n    <form on:change={submit}>\n      <label class=\"block\">\n        <input bind:checked={$form.jonathan} type=\"checkbox\" class=\"mr-2\" />\n        Jonathan\n      </label>\n      <label class=\"block\">\n        <input bind:checked={$form.taylor} type=\"checkbox\" class=\"mr-2\" />\n        Taylor\n      </label>\n      <label class=\"block\">\n        <input bind:checked={$form.joe} type=\"checkbox\" class=\"mr-2\" />\n        Joe\n      </label>\n    </form>\n    <p>You can check these on and off and then navigate to another page and the requests should still complete.</p>\n    <p>Toggling \"Joe\" on will cause a redirect to \"Article\", simulating an authorized action e.g.</p>\n  </TestGridItem>\n\n  <TestGridItem class=\"space-y-4\">\n    <p>Trigger programmatic visit and an async reload one after another</p>\n\n    <p>Reload should still happen but won't re-direct back to the reloaded component, we should respect the visit</p>\n\n    <button on:click={triggerVisitThenReload} class=\"rounded-sm bg-green-600 px-4 py-2 text-white\"\n      >Visit → Reload</button\n    >\n  </TestGridItem>\n\n  <TestGridItem class=\"space-y-4\">\n    <p>Simply trigger a 4 second reload so you can navigate or do whatever you'd like during it.</p>\n    <button on:click={triggerLongReload} class=\"rounded-sm bg-green-600 px-4 py-2 text-white\"\n      >Trigger Long Reload</button\n    >\n  </TestGridItem>\n\n  <TestGridItem class=\"space-y-4\">\n    <p>Trigger an automatic cancellation from the token.</p>\n    <button on:click={triggerCancel} class=\"rounded-sm bg-green-600 px-4 py-2 text-white\">Trigger Cancel</button>\n  </TestGridItem>\n\n  <TestGridItem class=\"space-y-4\">\n    <p>Trigger an automatic cancellation from the token after finishing request.</p>\n    <button on:click={triggerCancelAfterFinish} class=\"rounded-sm bg-green-600 px-4 py-2 text-white\">\n      Trigger Cancel After Finish\n    </button>\n  </TestGridItem>\n</TestGrid>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/DataTable.svelte",
    "content": "<script module>\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import Spinner from '../Components/Spinner.svelte'\n\n  let { appName, users } = $props()\n</script>\n\n<svelte:head>\n  <title>Data Table - {appName}</title>\n</svelte:head>\n\n<InfiniteScroll data=\"users\" class=\"mx-auto max-w-7xl px-8\" buffer={3000} itemsElement=\"tbody\">\n  <div slot=\"loading\">\n    <div class=\"flex justify-center py-16\">\n      <Spinner class=\"size-6 text-gray-400\" />\n    </div>\n  </div>\n\n  <div class=\"overflow-hidden rounded-2xl shadow ring-1 ring-gray-200\">\n    <table class=\"min-w-full\">\n      <thead class=\"bg-gray-50\">\n        <tr>\n          <th class=\"px-6 py-4 text-left text-sm font-semibold text-gray-900\">ID</th>\n          <th class=\"px-6 py-4 text-left text-sm font-semibold text-gray-900\">Name</th>\n        </tr>\n      </thead>\n      <tbody class=\"divide-y divide-gray-200 bg-white\">\n        {#each users.data as user (user.id)}\n          <tr class=\"transition-colors hover:bg-gray-50\">\n            <td class=\"px-6 py-4 text-sm text-gray-700\">{user.id}</td>\n            <td class=\"px-6 py-4 text-sm text-gray-700\">{user.name}</td>\n          </tr>\n        {/each}\n      </tbody>\n    </table>\n  </div>\n</InfiniteScroll>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/Flash.svelte",
    "content": "<script module>\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  import { Link, page, router } from '@inertiajs/svelte'\n\n  let { appName } = $props()\n\n  let flashLog = $state([])\n\n  router.on('flash', ({ detail: { flash } }) => {\n    flashLog = [...flashLog, flash]\n  })\n\n  const triggerFrontendFlash = () => {\n    router.flash('message', 'Hello from the frontend!')\n  }\n\n  const triggerMultipleFlash = () => {\n    router.flash({\n      message: 'Multiple items',\n      count: 42,\n    })\n  }\n\n  const clearLog = () => {\n    flashLog = []\n  }\n</script>\n\n<svelte:head>\n  <title>Flash - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Flash</h1>\n\n<div class=\"mt-6 space-y-6\">\n  <div>\n    <h2 class=\"text-lg font-semibold\">Current page.flash</h2>\n    <pre class=\"mt-2 rounded-sm bg-gray-100 p-3 text-sm\">{JSON.stringify($page.flash ?? 'null', null, 2)}</pre>\n  </div>\n\n  <div>\n    <h2 class=\"text-lg font-semibold\">Flash Event Log</h2>\n    <pre class=\"mt-2 rounded-sm bg-gray-100 p-3 text-sm\">{JSON.stringify(\n        flashLog.length ? flashLog : 'No flash events yet',\n        null,\n        2,\n      )}</pre>\n    {#if flashLog.length}\n      <button onclick={clearLog} class=\"mt-2 text-sm text-gray-500 underline\">Clear log</button>\n    {/if}\n  </div>\n\n  <div class=\"space-y-3\">\n    <h2 class=\"text-lg font-semibold\">Server-side Flash</h2>\n    <div>\n      <Link href=\"/flash/direct\" class=\"rounded-sm bg-slate-800 px-4 py-2 text-white\">Flash with render</Link>\n    </div>\n    <form\n      onsubmit={(e) => {\n        e.preventDefault()\n        router.post('/flash/form')\n      }}\n    >\n      <button type=\"submit\" class=\"rounded-sm bg-slate-800 px-4 py-2 text-white\">Flash with redirect</button>\n    </form>\n  </div>\n\n  <div class=\"space-y-3\">\n    <h2 class=\"text-lg font-semibold\">Frontend Flash</h2>\n    <div class=\"flex gap-3\">\n      <button onclick={triggerFrontendFlash} class=\"rounded-sm bg-slate-800 px-4 py-2 text-white\">\n        router.flash(key, value)\n      </button>\n      <button onclick={triggerMultipleFlash} class=\"rounded-sm bg-slate-800 px-4 py-2 text-white\">\n        router.flash(object)\n      </button>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/Form.svelte",
    "content": "<script module>\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  import { useForm } from '@inertiajs/svelte'\n\n  let { appName } = $props()\n\n  let form = useForm('NewUser', {\n    name: '',\n    company: '',\n    role: '',\n  })\n\n  function submit(e) {\n    e.preventDefault()\n    $form.post('/user')\n  }\n</script>\n\n<svelte:head>\n  <title>Form - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Form</h1>\n\n<form onsubmit={submit} class=\"mt-6 max-w-md space-y-4\">\n  {#if $form.isDirty}\n    <div class=\"my-5 rounded-sm border border-amber-100 bg-amber-50 p-3 text-amber-800\">There are unsaved changes!</div>\n  {/if}\n  <div>\n    <label class=\"block\" for=\"name\">Name:</label>\n    <input\n      type=\"text\"\n      bind:value={$form.name}\n      id=\"name\"\n      class=\"mt-1 w-full appearance-none rounded-sm border border-gray-200 px-2 py-1 shadow-xs\"\n    />\n    {#if $form.errors.name}\n      <div class=\"mt-2 text-sm text-red-600\">{$form.errors.name}</div>\n    {/if}\n  </div>\n  <div>\n    <label class=\"block\" for=\"company\">Company:</label>\n    <input\n      type=\"text\"\n      bind:value={$form.company}\n      id=\"company\"\n      class=\"mt-1 w-full appearance-none rounded-sm border border-gray-200 px-2 py-1 shadow-xs\"\n    />\n    {#if $form.errors.company}\n      <div class=\"mt-2 text-sm text-red-600\">{$form.errors.company}</div>\n    {/if}\n  </div>\n  <div>\n    <label class=\"block\" for=\"role\">Role:</label>\n    <select\n      bind:value={$form.role}\n      id=\"role\"\n      class=\"mt-1 w-full appearance-none rounded-sm border border-gray-200 px-2 py-1 shadow-xs\"\n    >\n      <option></option>\n      <option>User</option>\n      <option>Admin</option>\n      <option>Super</option>\n    </select>\n    {#if $form.errors.role}\n      <div class=\"mt-2 text-sm text-red-600\">{$form.errors.role}</div>\n    {/if}\n  </div>\n  <div class=\"flex gap-4\">\n    <button type=\"submit\" disabled={$form.processing} class=\"rounded-sm bg-slate-800 px-6 py-2 text-white\">\n      Submit\n    </button>\n    <button type=\"button\" onclick={() => $form.reset()}>Reset</button>\n  </div>\n</form>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/FormComponent.svelte",
    "content": "<script module>\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  import { Form } from '@inertiajs/svelte'\n\n  let { appName, foo, bar, quux } = $props()\n\n  let customHeaders = { 'X-Custom-Header': 'Demo-Value' }\n  let errorBag = 'custom-bag'\n</script>\n\n<svelte:head>\n  <title>Form Component - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Form Component</h1>\n\n<!-- Main Demo Form -->\n<Form\n  action=\"/form-component\"\n  method=\"post\"\n  headers={customHeaders}\n  {errorBag}\n  options={{\n    only: ['foo'],\n    reset: ['bar'],\n  }}\n  transform={(data) => ({ ...data, demo: 'data' })}\n  class=\"mt-6 max-w-2xl space-y-6\"\n>\n  {#snippet children({\n    errors,\n    hasErrors,\n    processing,\n    progress,\n    wasSuccessful,\n    recentlySuccessful,\n    setError,\n    clearErrors,\n    isDirty,\n    reset,\n    submit,\n  })}\n    <!-- Status Display -->\n    <div class=\"rounded border border-gray-200 bg-gray-50 p-4\">\n      <h3 class=\"mb-3 text-lg font-medium\">Form Status</h3>\n      <div class=\"grid grid-cols-2 gap-4 text-sm\">\n        <div>\n          isDirty: <span class=\"font-mono\" class:text-orange-600={isDirty} class:text-gray-500={!isDirty}\n            >{isDirty}</span\n          >\n        </div>\n        <div>\n          hasErrors: <span class=\"font-mono\" class:text-red-600={hasErrors} class:text-gray-500={!hasErrors}\n            >{hasErrors}</span\n          >\n        </div>\n        <div>\n          processing: <span class=\"font-mono\" class:text-blue-600={processing} class:text-gray-500={!processing}\n            >{processing}</span\n          >\n        </div>\n        <div>\n          wasSuccessful: <span\n            class=\"font-mono\"\n            class:text-green-600={wasSuccessful}\n            class:text-gray-500={!wasSuccessful}>{wasSuccessful}</span\n          >\n        </div>\n        <div>\n          recentlySuccessful: <span\n            class=\"font-mono\"\n            class:text-green-600={recentlySuccessful}\n            class:text-gray-500={!recentlySuccessful}>{recentlySuccessful}</span\n          >\n        </div>\n        {#if progress}\n          <div>\n            progress: <span class=\"font-mono text-blue-600\">{Math.round(progress.percentage)}%</span>\n          </div>\n        {/if}\n      </div>\n    </div>\n\n    {#if isDirty}\n      <div class=\"rounded border border-amber-100 bg-amber-50 p-3 text-amber-800\">There are unsaved changes!</div>\n    {/if}\n\n    <!-- Form Fields -->\n    <div class=\"space-y-4\">\n      <!-- Text Input -->\n      <div>\n        <label class=\"block font-medium\" for=\"name\">Name</label>\n        <input\n          type=\"text\"\n          name=\"name\"\n          id=\"name\"\n          placeholder=\"Enter your name\"\n          class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n          class:border-red-500={errors.name}\n        />\n        {#if errors.name}\n          <div class=\"mt-1 text-sm text-red-600\">{errors.name}</div>\n        {/if}\n      </div>\n\n      <!-- File Input -->\n      <div>\n        <label class=\"block font-medium\" for=\"avatar\">Avatar</label>\n        <input\n          type=\"file\"\n          name=\"avatar\"\n          id=\"avatar\"\n          class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n        />\n        {#if errors.avatar}\n          <div class=\"mt-1 text-sm text-red-600\">{errors.avatar}</div>\n        {/if}\n      </div>\n\n      <!-- Multiple Select -->\n      <div>\n        <label class=\"block font-medium\" for=\"skills\">Skills (Multiple)</label>\n        <select\n          name=\"skills[]\"\n          id=\"skills\"\n          multiple\n          class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n        >\n          <option value=\"vue\">Vue.js</option>\n          <option value=\"react\">React</option>\n          <option value=\"laravel\">Laravel</option>\n          <option value=\"tailwind\">Tailwind CSS</option>\n        </select>\n        {#if errors.skills}\n          <div class=\"mt-1 text-sm text-red-600\">{errors.skills}</div>\n        {/if}\n      </div>\n\n      <!-- Array Input (Tags) -->\n      <div>\n        <label class=\"block font-medium\">Tags</label>\n        <div class=\"mt-1 space-y-2\">\n          <input\n            type=\"text\"\n            name=\"tags[]\"\n            placeholder=\"Tag 1\"\n            class=\"w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n          />\n          {#if errors['tags.0']}\n            <div class=\"text-sm text-red-600\">{errors['tags.0']}</div>\n          {/if}\n          <input\n            type=\"text\"\n            name=\"tags[]\"\n            placeholder=\"Tag 2\"\n            class=\"w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n          />\n          {#if errors['tags.1']}\n            <div class=\"text-sm text-red-600\">{errors['tags.1']}</div>\n          {/if}\n        </div>\n      </div>\n\n      <!-- Nested Object Input -->\n      <div>\n        <label class=\"block font-medium\">Address</label>\n        <div class=\"mt-1 grid grid-cols-2 gap-2\">\n          <input\n            type=\"text\"\n            name=\"user[address][street]\"\n            placeholder=\"Street\"\n            class=\"appearance-none rounded border px-2 py-1 shadow-sm\"\n          />\n          <input\n            type=\"text\"\n            name=\"user[address][city]\"\n            placeholder=\"City\"\n            class=\"appearance-none rounded border px-2 py-1 shadow-sm\"\n          />\n        </div>\n      </div>\n    </div>\n\n    <!-- Action Buttons -->\n    <div class=\"flex flex-wrap gap-2\">\n      <button type=\"submit\" disabled={processing} class=\"rounded bg-slate-800 px-4 py-2 text-white disabled:opacity-50\">\n        Submit\n      </button>\n\n      <button type=\"button\" onclick={reset} class=\"rounded bg-gray-500 px-4 py-2 text-white\"> Reset </button>\n\n      <button\n        type=\"button\"\n        onclick={() => setError({ name: 'Name is required', avatar: 'Please select a file' })}\n        class=\"rounded bg-red-500 px-4 py-2 text-white\"\n      >\n        Set Errors\n      </button>\n\n      <button type=\"button\" onclick={() => clearErrors()} class=\"rounded bg-green-500 px-4 py-2 text-white\">\n        Clear Errors\n      </button>\n    </div>\n  {/snippet}\n</Form>\n\n<!-- Form Configuration -->\n<div class=\"mt-8 max-w-2xl space-y-4\">\n  <h2 class=\"text-2xl\">Form Configuration</h2>\n\n  <div class=\"grid grid-cols-1 gap-6 md:grid-cols-2\">\n    <div class=\"rounded border border-gray-200 bg-gray-50 p-4\">\n      <div class=\"space-y-1 text-sm\">\n        <div>\n          <strong>Headers:</strong> <code class=\"text-xs\">{JSON.stringify(customHeaders)}</code>\n        </div>\n        <div>\n          <strong>Error Bag:</strong> <code>{errorBag}</code>\n        </div>\n        <div><strong>Only:</strong> <code>['foo']</code></div>\n        <div><strong>Reset:</strong> <code>['bar']</code></div>\n        <div><strong>Method:</strong> <code>POST</code></div>\n      </div>\n    </div>\n\n    <div class=\"space-y-3\">\n      <div>\n        <label class=\"block text-sm font-medium\">Error Bag</label>\n        <input\n          type=\"text\"\n          bind:value={errorBag}\n          class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n          placeholder=\"Error bag name\"\n        />\n      </div>\n\n      <div>\n        <label class=\"block text-sm font-medium\">Custom Header Value</label>\n        <input\n          type=\"text\"\n          bind:value={customHeaders['X-Custom-Header']}\n          class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n          placeholder=\"Header value\"\n        />\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/FormComponentPrecognition.svelte",
    "content": "<script module>\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script lang=\"ts\">\n  import type { FormComponentMethods } from '@inertiajs/core'\n  import { Form } from '@inertiajs/svelte'\n\n  let { appName } = $props()\n\n  let validateFiles = $state(false)\n  let validationTimeout = $state(1500)\n\n  let callbacks = $state({\n    success: false,\n    error: false,\n    finish: false,\n  })\n\n  const validateWithCallbacks = (validate: FormComponentMethods['validate']) => {\n    callbacks = { success: false, error: false, finish: false }\n\n    validate({\n      onPrecognitionSuccess: () => (callbacks.success = true),\n      onValidationError: () => (callbacks.error = true),\n      onFinish: () => (callbacks.finish = true),\n      onBeforeValidation: (newReq) => {\n        if (newReq.data?.name === 'block') {\n          alert('Validation blocked by onBeforeValidation!')\n          return false\n        }\n      },\n    })\n  }\n</script>\n\n<svelte:head>\n  <title>Form Component Precognition - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Form Component Precognition</h1>\n\n<Form\n  action=\"/form-component/precognition\"\n  method=\"post\"\n  {validateFiles}\n  {validationTimeout}\n  class=\"mt-6 max-w-2xl space-y-6\"\n>\n  {#snippet children({ errors, invalid, valid, validate, validating, touch, touched, processing })}\n    <!-- Status Display -->\n    <div class=\"rounded border border-gray-200 bg-gray-50 p-4\">\n      <h3 class=\"mb-3 text-lg font-medium\">Validation Status (slot props)</h3>\n      <div class=\"grid grid-cols-2 gap-4 text-sm\">\n        <div>\n          validating:\n          <span class=\"font-mono\" class:text-blue-600={validating} class:text-gray-500={!validating}>{validating}</span>\n        </div>\n        <div>\n          processing:\n          <span class=\"font-mono\" class:text-blue-600={processing} class:text-gray-500={!processing}>{processing}</span>\n        </div>\n        <div>\n          touched():\n          <span class=\"font-mono\" class:text-orange-600={touched()} class:text-gray-500={!touched()}>{touched()}</span>\n        </div>\n        <div>\n          touched('name'):\n          <span class=\"font-mono\" class:text-orange-600={touched('name')} class:text-gray-500={!touched('name')}\n            >{touched('name')}</span\n          >\n        </div>\n        <div>\n          touched('email'):\n          <span class=\"font-mono\" class:text-orange-600={touched('email')} class:text-gray-500={!touched('email')}\n            >{touched('email')}</span\n          >\n        </div>\n      </div>\n    </div>\n\n    <!-- Form Fields -->\n    <div class=\"space-y-4\">\n      <!-- Name Input -->\n      <div>\n        <label class=\"block font-medium\" for=\"name\">Name</label>\n        <input\n          type=\"text\"\n          name=\"name\"\n          id=\"name\"\n          placeholder=\"Enter your name (min 3 chars)\"\n          onblur={() => validate('name')}\n          class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n          class:border-red-500={invalid('name')}\n          class:border-green-500={valid('name')}\n        />\n        {#if invalid('name')}\n          <div class=\"mt-1 text-sm text-red-600\">{errors.name}</div>\n        {/if}\n        {#if valid('name')}\n          <div class=\"mt-1 text-sm text-green-600\">Valid!</div>\n        {/if}\n      </div>\n\n      <!-- Email Input -->\n      <div>\n        <label class=\"block font-medium\" for=\"email\">Email</label>\n        <input\n          type=\"email\"\n          name=\"email\"\n          id=\"email\"\n          placeholder=\"Enter your email\"\n          onblur={() => validate('email')}\n          class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n          class:border-red-500={invalid('email')}\n          class:border-green-500={valid('email')}\n        />\n        {#if invalid('email')}\n          <div class=\"mt-1 text-sm text-red-600\">{errors.email}</div>\n        {/if}\n        {#if valid('email')}\n          <div class=\"mt-1 text-sm text-green-600\">Valid!</div>\n        {/if}\n      </div>\n\n      <!-- File Input -->\n      <div>\n        <label class=\"block font-medium\" for=\"avatar\">Avatar</label>\n        <input\n          type=\"file\"\n          name=\"avatar\"\n          id=\"avatar\"\n          onchange={() => validate('avatar')}\n          class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n          class:border-red-500={invalid('avatar')}\n          class:border-green-500={valid('avatar')}\n        />\n        {#if invalid('avatar')}\n          <div class=\"mt-1 text-sm text-red-600\">{errors.avatar}</div>\n        {/if}\n        {#if valid('avatar')}\n          <div class=\"mt-1 text-sm text-green-600\">Valid!</div>\n        {/if}\n      </div>\n    </div>\n\n    <!-- Action Buttons -->\n    <div class=\"flex flex-wrap gap-2\">\n      <button type=\"submit\" disabled={processing} class=\"rounded bg-slate-800 px-4 py-2 text-white disabled:opacity-50\">\n        Submit\n      </button>\n\n      <button\n        type=\"button\"\n        onclick={() => validate()}\n        class=\"rounded border border-slate-300 px-4 py-2 hover:bg-slate-50\"\n      >\n        Validate Touched\n      </button>\n\n      <button\n        type=\"button\"\n        onclick={() => touch('name')}\n        class=\"rounded border border-slate-300 px-4 py-2 hover:bg-slate-50\"\n      >\n        Touch Name\n      </button>\n\n      <button\n        type=\"button\"\n        onclick={() => validateWithCallbacks(validate)}\n        class=\"rounded border border-slate-300 px-4 py-2 hover:bg-slate-50\"\n      >\n        Validate with Callbacks\n      </button>\n    </div>\n\n    <!-- Callbacks Display -->\n    <div class=\"rounded border border-gray-200 bg-gray-50 p-4\">\n      <h3 class=\"mb-3 text-lg font-medium\">Validation Callbacks</h3>\n      <p class=\"mb-3 text-sm text-gray-600\">Enter \"block\" in the name field to test onBeforeValidation blocking.</p>\n      <div class=\"grid grid-cols-3 gap-4 text-sm\">\n        <div>\n          onPrecognitionSuccess:\n          <span class=\"font-mono\" class:text-green-600={callbacks.success} class:text-gray-500={!callbacks.success}\n            >{callbacks.success}</span\n          >\n        </div>\n        <div>\n          onValidationError:\n          <span class=\"font-mono\" class:text-red-600={callbacks.error} class:text-gray-500={!callbacks.error}\n            >{callbacks.error}</span\n          >\n        </div>\n        <div>\n          onFinish:\n          <span class=\"font-mono\" class:text-blue-600={callbacks.finish} class:text-gray-500={!callbacks.finish}\n            >{callbacks.finish}</span\n          >\n        </div>\n      </div>\n    </div>\n  {/snippet}\n</Form>\n\n<!-- Configuration -->\n<div class=\"mt-8 max-w-2xl space-y-4\">\n  <h2 class=\"text-2xl\">Configuration</h2>\n\n  <div class=\"grid grid-cols-1 gap-6 md:grid-cols-2\">\n    <div class=\"rounded border border-gray-200 bg-gray-50 p-4\">\n      <div class=\"space-y-1 text-sm\">\n        <div>\n          <strong>Validate Files:</strong> <code>{validateFiles}</code>\n        </div>\n        <div>\n          <strong>Validation Timeout:</strong> <code>{validationTimeout}ms</code>\n        </div>\n        <div><strong>Method:</strong> <code>POST</code></div>\n      </div>\n    </div>\n\n    <div class=\"space-y-3\">\n      <div>\n        <label class=\"flex items-center gap-2\">\n          <input type=\"checkbox\" bind:checked={validateFiles} class=\"rounded\" />\n          <span class=\"text-sm\">Enable file validation</span>\n        </label>\n      </div>\n\n      <div>\n        <label class=\"block text-sm font-medium\">Validation Timeout</label>\n        <select bind:value={validationTimeout} class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\">\n          <option value={500}>500ms</option>\n          <option value={1000}>1000ms</option>\n          <option value={1500}>1500ms</option>\n          <option value={2000}>2000ms</option>\n        </select>\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/Home.svelte",
    "content": "<script module>\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  import { inertia } from '@inertiajs/svelte'\n\n  let { appName } = $props()\n</script>\n\n<svelte:head>\n  <title>Home - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Home</h1>\n\n<p class=\"mt-6\">\n  <a href=\"/article#far-down\" use:inertia class=\"text-blue-700 underline\">Link to bottom of article page</a>\n</p>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/Login.svelte",
    "content": "<script module>\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  let { appName } = $props()\n</script>\n\n<svelte:head>\n  <title>Login - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Login</h1>\n\n<p class=\"mt-6\">You made a <code>POST</code> request to the logout endpoint and were redirected to the login page.</p>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/Once/First.svelte",
    "content": "<script module>\n  export { default as layout } from './Layout.svelte'\n</script>\n\n<script>\n  let { foo, bar, baz1, qux } = $props()\n</script>\n\n<svelte:head>\n  <title>Once Props: First Page</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Once Props: First Page</h1>\n<p>Foo: {foo}</p>\n<p>Bar: {bar}</p>\n<p>Baz: {baz1}</p>\n<p>Qux: {qux ?? 'Loading...'}</p>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/Once/Fourth.svelte",
    "content": "<script module>\n  export { default as layout } from './Layout.svelte'\n</script>\n\n<script>\n  let { foo, bar, baz4, qux } = $props()\n</script>\n\n<svelte:head>\n  <title>Once Props: Fourth Page</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Once Props: Fourth Page</h1>\n<p>Foo: {foo}</p>\n<p>Bar: {bar}</p>\n<p>Baz: {baz4}</p>\n<p>Qux: {qux ?? 'Loading...'}</p>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/Once/Layout.svelte",
    "content": "<script>\n  import { inertia, router } from '@inertiajs/svelte'\n  import MainLayout from '../../Components/Layout.svelte'\n\n  let { children } = $props()\n</script>\n\n<MainLayout>\n  {@render children()}\n  <a href=\"/once/1\" use:inertia class=\"text-blue-500 underline\">Go to First Page</a>\n  <a href=\"/once/2\" use:inertia class=\"ml-4 text-blue-500 underline\">Go to Second Page</a>\n  <a href=\"/once/3\" use:inertia class=\"ml-4 text-blue-500 underline\">Go to Third Page</a>\n  <a href=\"/once/4\" use:inertia={{ prefetch: 'mount' }} class=\"ml-4 text-blue-500 underline\">Go to Fourth Page</a>\n  <button onclick={() => router.reload({ only: ['foo'] })} class=\"ml-4 text-blue-500 underline\">Reload Foo</button>\n  <button onclick={() => router.reload({ only: ['bar'] })} class=\"ml-4 text-blue-500 underline\">Reload Bar</button>\n  <button\n    onclick={() => router.reload({ only: ['baz1', 'baz2', 'baz3', 'baz4'] })}\n    class=\"ml-4 text-blue-500 underline\"\n  >\n    Reload Baz\n  </button>\n  <button onclick={() => router.reload({ only: ['qux'] })} class=\"ml-4 text-blue-500 underline\">Reload Qux</button>\n</MainLayout>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/Once/Second.svelte",
    "content": "<script module>\n  export { default as layout } from './Layout.svelte'\n</script>\n\n<script>\n  let { foo, bar, baz2, qux } = $props()\n</script>\n\n<svelte:head>\n  <title>Once Props: Second Page</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Once Props: Second Page</h1>\n<p>Foo: {foo}</p>\n<p>Bar: {bar}</p>\n<p>Baz: {baz2}</p>\n<p>Qux: {qux ?? 'Loading...'}</p>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/Once/Third.svelte",
    "content": "<script module>\n  export { default as layout } from './Layout.svelte'\n</script>\n\n<script>\n  let { foo, bar, baz3, qux } = $props()\n</script>\n\n<svelte:head>\n  <title>Once Props: Third Page</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Once Props: Third Page</h1>\n<p>Foo: {foo}</p>\n<p>Bar: {bar}</p>\n<p>Baz: {baz3}</p>\n<p>Qux: {qux ?? 'Loading...'}</p>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/PhotoGrid.svelte",
    "content": "<script module>\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import Image from '../Components/Image.svelte'\n  import Spinner from '../Components/Spinner.svelte'\n\n  let { appName, photos } = $props()\n</script>\n\n<svelte:head>\n  <title>Photo Grid - {appName}</title>\n</svelte:head>\n\n<InfiniteScroll\n  data=\"photos\"\n  class=\"mx-auto grid max-w-7xl grid-cols-1 gap-6 px-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\"\n  buffer={1000}\n>\n  <div slot=\"loading\">\n    <div class=\"flex justify-center py-16\">\n      <Spinner class=\"size-6 text-gray-400\" />\n    </div>\n  </div>\n\n  {#each photos.data as photo (photo.id)}\n    <Image id={photo.id} url={photo.url} />\n  {/each}\n</InfiniteScroll>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/PhotoHorizontal.svelte",
    "content": "<script module>\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  import { InfiniteScroll } from '@inertiajs/svelte'\n  import Image from '../Components/Image.svelte'\n  import Spinner from '../Components/Spinner.svelte'\n\n  let { appName, photos } = $props()\n</script>\n\n<svelte:head>\n  <title>Photo Grid (Horizontal) - {appName}</title>\n</svelte:head>\n\n<div class=\"flex h-[200px] w-full overflow-x-scroll\">\n  <InfiniteScroll data=\"photos\" buffer={1000} class=\"flex h-[200px] gap-6\" preserveUrl onlyNext>\n    <div slot=\"loading\">\n      <div class=\"flex size-[200px] items-center justify-center\">\n        <Spinner class=\"size-6 text-gray-400\" />\n      </div>\n    </div>\n\n    {#each photos.data as photo (photo.id)}\n      <Image id={photo.id} url={photo.url} />\n    {/each}\n  </InfiniteScroll>\n</div>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/Poll.svelte",
    "content": "<script context=\"module\">\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  import { onMount } from 'svelte'\n  import { router, usePoll } from '@inertiajs/svelte'\n  import TestGrid from '../Components/TestGrid.svelte'\n  import TestGridItem from '../Components/TestGridItem.svelte'\n\n  export let appName\n  export let users = []\n  export let companies = []\n\n  let userPollCount = 0\n  let hookPollCount = 0\n  let companyPollCount = 0\n\n  const triggerAsyncRedirect = () => {\n    router.get(\n      '/elsewhere',\n      {},\n      {\n        only: ['something'],\n        async: true,\n      },\n    )\n  }\n\n  const { start: startHookPolling, stop } = usePoll(\n    2000,\n    {\n      only: ['asdf'],\n      onFinish() {\n        hookPollCount++\n      },\n    },\n    {\n      keepAlive: true,\n      autoStart: false,\n    },\n  )\n\n  onMount(() => {\n    setTimeout(() => {\n      startHookPolling()\n    }, 2000)\n\n    const { stop: stopUserPolling } = router.poll(\n      1000,\n      {\n        only: ['users'],\n        onFinish() {\n          userPollCount++\n        },\n      },\n      { keepAlive: true },\n    )\n\n    setTimeout(() => {\n      console.log('stopping user polling')\n      stopUserPolling()\n    }, 3000)\n  })\n</script>\n\n<svelte:head>\n  <title>Async Request - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Poll</h1>\n\n<TestGrid>\n  <TestGridItem>\n    <svelte:fragment slot=\"title\">\n      User Poll Request Count: {userPollCount}\n    </svelte:fragment>\n    <div>\n      {#each users as user}\n        <div>{user}</div>\n      {/each}\n    </div>\n  </TestGridItem>\n  <TestGridItem>\n    <svelte:fragment slot=\"title\">\n      Companies Poll Request Count: {companyPollCount}\n    </svelte:fragment>\n    <div>\n      {#each companies as company}\n        <div>{company}</div>\n      {/each}\n    </div>\n  </TestGridItem>\n  <TestGridItem>\n    <svelte:fragment slot=\"title\">\n      Hook Poll Request Count: {hookPollCount}\n    </svelte:fragment>\n  </TestGridItem>\n  <TestGridItem>\n    <button on:click={() => triggerAsyncRedirect()}>Trigger Async Redirect</button>\n  </TestGridItem>\n</TestGrid>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/User.svelte",
    "content": "<script module>\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  let { appName, user } = $props()\n</script>\n\n<svelte:head>\n  <title>User - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">User</h1>\n\n<p class=\"mt-6\">You successfully created a new user! Well not really, there is no persistence in this app.</p>\n\n<ul class=\"mt-6 space-y-2\">\n  <li><strong>Name:</strong> {user.name}</li>\n  <li><strong>Company:</strong> {user.company}</li>\n  <li><strong>Role:</strong> {user.role}</li>\n</ul>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/Pages/Users.svelte",
    "content": "<script module>\n  export { default as layout } from '../Components/Layout.svelte'\n</script>\n\n<script>\n  let { appName, users } = $props()\n</script>\n\n<svelte:head>\n  <title>Users - {appName}</title>\n</svelte:head>\n\n<h1 class=\"text-3xl\">Users</h1>\n\n<div class=\"mt-6 w-full max-w-2xl overflow-hidden rounded-sm border border-gray-200 shadow-xs\">\n  <table class=\"w-full text-left\">\n    <thead>\n      <tr>\n        <th class=\"px-4 py-2\">Id</th>\n        <th class=\"px-4 py-2\">Name</th>\n        <th class=\"px-4 py-2\">Email</th>\n      </tr>\n    </thead>\n    <tbody>\n      {#each users as user (user.id)}\n        <tr class=\"border-t border-gray-200\">\n          <td class=\"px-4 py-2\">{user.id}</td>\n          <td class=\"px-4 py-2\">{user.name}</td>\n          <td class=\"px-4 py-2\">{user.email}</td>\n        </tr>\n      {/each}\n    </tbody>\n  </table>\n</div>\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/app.ts",
    "content": "import { createInertiaApp, type ResolvedComponent } from '@inertiajs/svelte'\nimport { hydrate, mount } from 'svelte'\n\ncreateInertiaApp({\n  resolve: (name) => {\n    const pages = import.meta.glob<ResolvedComponent>('./Pages/**/*.svelte', { eager: true })\n    return pages[`./Pages/${name}.svelte`]\n  },\n  setup({ el, App, props }) {\n    if (el.dataset.serverRendered === 'true') {\n      hydrate(App, { target: el, props })\n    } else {\n      mount(App, { target: el, props })\n    }\n  },\n})\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/ssr.ts",
    "content": "import { createInertiaApp, type ResolvedComponent } from '@inertiajs/svelte'\nimport createServer from '@inertiajs/svelte/server'\nimport { render } from 'svelte/server'\n\ncreateServer((page) =>\n  createInertiaApp({\n    page,\n    resolve: (name) => {\n      const pages = import.meta.glob<ResolvedComponent>('./Pages/**/*.svelte', { eager: true })\n      return pages[`./Pages/${name}.svelte`]\n    },\n    setup({ App, props }) {\n      return render(App, { props })\n    },\n  }),\n)\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/types/globals.d.ts",
    "content": "import '@inertiajs/core'\n\ndeclare module '@inertiajs/core' {\n  export interface InertiaConfig {\n    sharedPageProps: {\n      appName: string\n    }\n  }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/resources/js/vite-env.d.ts",
    "content": "/// <reference types=\"svelte\" />\n/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "playgrounds/svelte5/resources/views/app.blade.php",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\" />\n    <meta name=\"csrf-token\" content=\"{{ csrf_token() }}\">\n    @vite(['resources/css/app.css', 'resources/js/app.ts'])\n    @inertiaHead\n  </head>\n  <body>\n    @inertia\n  </body>\n</html>\n"
  },
  {
    "path": "playgrounds/svelte5/routes/api.php",
    "content": "<?php\n\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Route;\n\n/*\n|--------------------------------------------------------------------------\n| API Routes\n|--------------------------------------------------------------------------\n|\n| Here is where you can register API routes for your application. These\n| routes are loaded by the RouteServiceProvider within a group which\n| is assigned the \"api\" middleware group. Enjoy building your API!\n|\n*/\n\nRoute::middleware('auth:sanctum')->get('/user', function (Request $request) {\n    return $request->user();\n});\n"
  },
  {
    "path": "playgrounds/svelte5/routes/channels.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Facades\\Broadcast;\n\n/*\n|--------------------------------------------------------------------------\n| Broadcast Channels\n|--------------------------------------------------------------------------\n|\n| Here you may register all of the event broadcasting channels that your\n| application supports. The given channel authorization callbacks are\n| used to check if an authenticated user can listen to the channel.\n|\n*/\n\nBroadcast::channel('App.Models.User.{id}', function ($user, $id) {\n    return (int) $user->id === (int) $id;\n});\n"
  },
  {
    "path": "playgrounds/svelte5/routes/console.php",
    "content": "<?php\n\nuse Illuminate\\Foundation\\Inspiring;\nuse Illuminate\\Support\\Facades\\Artisan;\n\n/*\n|--------------------------------------------------------------------------\n| Console Routes\n|--------------------------------------------------------------------------\n|\n| This file is where you may define all of your Closure based console\n| commands. Each Closure is bound to a command instance allowing a\n| simple approach to interacting with each command's IO methods.\n|\n*/\n\nArtisan::command('inspire', function () {\n    $this->comment(Inspiring::quote());\n})->purpose('Display an inspiring quote');\n"
  },
  {
    "path": "playgrounds/svelte5/routes/web.php",
    "content": "<?php\n\nuse App\\Http\\Requests\\PrecognitionFormRequest;\nuse Illuminate\\Foundation\\Http\\Middleware\\HandlePrecognitiveRequests;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Pagination\\LengthAwarePaginator;\nuse Illuminate\\Support\\Facades\\Cache;\nuse Illuminate\\Support\\Facades\\Route;\nuse Inertia\\Inertia;\n\n/*\n|--------------------------------------------------------------------------\n| Web Routes\n|--------------------------------------------------------------------------\n|\n| Here is where you can register web routes for your application. These\n| routes are loaded by the RouteServiceProvider within a group which\n| contains the \"web\" middleware group. Now create something great!\n|\n*/\n\nRoute::get('/', function () {\n    return inertia('Home');\n});\n\nRoute::get('/users', function () {\n    sleep(2);\n\n    return inertia('Users', [\n        'date' => now()->toDateTimeString(),\n        'users' => collect([\n            [\n                'id' => 1,\n                'name' => 'Jonathan Reinink',\n                'email' => 'jonathan@example.com',\n            ],\n            [\n                'id' => 2,\n                'name' => 'Adam Wathan',\n                'email' => 'adam@example.com',\n            ],\n            [\n                'id' => 3,\n                'name' => 'Taylor Otwell',\n                'email' => 'taylor@example.com',\n            ],\n            [\n                'id' => 4,\n                'name' => 'Jordan Pittman',\n                'email' => 'jordan@example.com',\n            ],\n            [\n                'id' => 5,\n                'name' => 'Jess Archer',\n                'email' => 'jess@example.com',\n            ],\n            [\n                'id' => 6,\n                'name' => 'Claudio Dekker',\n                'email' => 'claudio@example.com',\n            ],\n            [\n                'id' => 7,\n                'name' => 'Sebastian De Deyne',\n                'email' => 'sebastian@example.com',\n            ],\n            [\n                'id' => 8,\n                'name' => 'Pedro Borges',\n                'email' => 'pedro@example.com',\n            ],\n        ])->shuffle()->values(),\n    ]);\n});\n\nRoute::get('/users/2', function () {\n    sleep(2);\n\n    return inertia('Users', [\n        'date' => now()->toDateTimeString(),\n        'users' => [\n            [\n                'id' => 1,\n                'name' => 'Jonathan Reinink',\n                'email' => 'jonathan@example.com',\n            ],\n            [\n                'id' => 2,\n                'name' => 'Adam Wathan',\n                'email' => 'adam@example.com',\n            ],\n            [\n                'id' => 3,\n                'name' => 'Taylor Otwell',\n                'email' => 'taylor@example.com',\n            ],\n            [\n                'id' => 4,\n                'name' => 'Jordan Pittman',\n                'email' => 'jordan@example.com',\n            ],\n            [\n                'id' => 5,\n                'name' => 'Jess Archer',\n                'email' => 'jess@example.com',\n            ],\n            [\n                'id' => 6,\n                'name' => 'Claudio Dekker',\n                'email' => 'claudio@example.com',\n            ],\n            [\n                'id' => 7,\n                'name' => 'Sebastian De Deyne',\n                'email' => 'sebastian@example.com',\n            ],\n            [\n                'id' => 8,\n                'name' => 'Pedro Borges',\n                'email' => 'pedro@example.com',\n            ],\n        ],\n    ]);\n});\n\nRoute::get('/article', function () {\n    Inertia::encryptHistory();\n\n    return inertia('Article');\n});\n\nRoute::get('/form', function () {\n    return inertia('Form');\n});\n\nRoute::post('/user', function () {\n    return inertia('User', [\n        'user' => request()->validate([\n            'name' => ['required'],\n            'company' => ['required'],\n            'role' => ['required', 'in:User,Admin,Super'],\n        ]),\n    ]);\n});\n\nRoute::get('/login', function () {\n    return inertia('Login');\n});\n\nRoute::get('/async', function () {\n    return inertia('Async', [\n        'sleep' => Inertia::lazy(function () {\n            sleep(4);\n        }),\n        'jonathan' => Cache::get('jonathan', false),\n        'taylor' => Cache::get('taylor', false),\n        'joe' => Cache::get('joe', false),\n    ]);\n});\n\n// @deprecated - We now have a InfiniteScroll component and Inertia::scroll() method...\nRoute::get('/infinite-scroll', function () {\n    $page = request()->integer('page', 1);\n    $perPage = 25;\n    $start = ($page - 1) * $perPage;\n    $end = $start + $perPage;\n    $itemTypes = ['user', 'food', 'animal', 'plant'];\n    $itemType = request()->input('item_type', $itemTypes[0]);\n\n    return inertia('InfiniteScroll', [\n        'items' => Inertia::defer(\n            function () use ($start, $end, $itemType) {\n                sleep(1);\n\n                return collect(range($start, $end))->map(fn ($i) => [\n                    'id' => $i,\n                    'name' => ucwords($itemType).' '.$i,\n                ])->toArray();\n            }\n        )->merge(),\n        'page' => $page,\n        'item_type' => $itemType,\n        'item_types' => $itemTypes,\n    ]);\n});\n\nRoute::post('/async/checkbox', function () {\n    sleep(2);\n    $previousJoe = Cache::get('joe', false);\n\n    Cache::put('jonathan', request('jonathan'), 10);\n    Cache::put('taylor', request('taylor'), 10);\n    Cache::put('joe', request('joe'), 10);\n\n    if (! $previousJoe && request()->boolean('joe')) {\n        return redirect('article');\n    }\n\n    return redirect('/async');\n});\n\nRoute::get('/defer', function () {\n    info('defer route');\n\n    return inertia('Defer', [\n        'users' => Inertia::defer(function () {\n            sleep(1);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => 'Jonathan Reinink',\n                    'email' => 'hello@reinink.com',\n                ],\n                [\n                    'id' => 2,\n                    'name' => 'Taylor Otwell',\n                    'email' => 'howdy@otwell.biz',\n                ],\n                [\n                    'id' => 3,\n                    'name' => 'Joe Tannenbaum',\n                    'email' => 'yo@tannenbaum.edu',\n                ],\n            ];\n        }, 'u'),\n        'foods' => Inertia::defer(function () {\n            sleep(3);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => 'Pizza',\n                ],\n                [\n                    'id' => 2,\n                    'name' => 'Tacos',\n                ],\n                [\n                    'id' => 3,\n                    'name' => 'Sushi',\n                ],\n            ];\n        }, 'f'),\n        'organizations' => Inertia::defer(function () {\n            sleep(2);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => 'InertiaJS',\n                    'url' => 'https://inertiajs.com',\n                ],\n                [\n                    'id' => 2,\n                    'name' => 'Laravel',\n                    'url' => 'https://laravel.com',\n                ],\n                [\n                    'id' => 3,\n                    'name' => 'VueJS',\n                    'url' => 'https://vuejs.org',\n                ],\n            ];\n        }, 'o'),\n        'surprise' => Inertia::optional(function () {\n            sleep(2);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => 'Surprise!',\n                ],\n                [\n                    'id' => 2,\n                    'name' => 'Aha!',\n                ],\n                [\n                    'id' => 3,\n                    'name' => 'Gotcha!',\n                ],\n                [\n                    'id' => 4,\n                    'name' => '👋!',\n                ],\n            ];\n        }),\n        'dogs' => Inertia::optional(function () {\n            sleep(1);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => '🐕',\n                ],\n                [\n                    'id' => 2,\n                    'name' => '🐩',\n                ],\n                [\n                    'id' => 3,\n                    'name' => '🐶',\n                ],\n            ];\n        }),\n        'lunch' => Inertia::optional(function () {\n            sleep(1);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => '🍔',\n                ],\n                [\n                    'id' => 2,\n                    'name' => '🍟',\n                ],\n                [\n                    'id' => 3,\n                    'name' => '🥤',\n                ],\n            ];\n        }),\n    ]);\n});\n\nRoute::get('/goodbye', function () {\n    return Inertia::location('https://inertiajs.com/redirects');\n});\n\nRoute::get('/poll', function () {\n    return inertia('Poll', [\n        'users' => collect([\n            'Jonathan Reinink',\n            'Taylor Otwell',\n            'Joe Tannenbaum',\n            'Jess Archer',\n            'Claudio Dekker',\n            'Sebastian De Deyne',\n            'Pedro Borges',\n        ])->shuffle()->take(3)->values(),\n        'companies' => collect([\n            'InertiaJS',\n            'Laravel',\n            'VueJS',\n            'Tailwind CSS',\n            'AlpineJS',\n            'Livewire',\n            'Spatie',\n        ])->shuffle()->take(3)->values(),\n    ]);\n});\n\nRoute::get('/elsewhere', function () {\n    return inertia('Users');\n});\n\nRoute::get('/sleepy/{duration}', function ($duration) {\n    sleep($duration);\n\n    return inertia('Users');\n});\n\nRoute::post('/sleepy/{duration}', function ($duration) {\n    sleep($duration);\n\n    return inertia('Article');\n});\n\nRoute::post('/logout', function () {\n    return redirect('/login');\n});\n\nRoute::get('/form-component', function () {\n    return inertia('FormComponent', [\n        'foo' => fn () => now()->getTimestampMs(),\n        'bar' => fn () => now()->getTimestampMs(),\n        'quux' => fn () => now()->getTimestampMs(),\n    ]);\n});\n\nRoute::post('/form-component', function () {\n    $data = request()->validateWithBag('custom-bag', [\n        'name' => ['required', 'string', 'max:255'],\n        'avatar' => ['nullable', 'file', 'image', 'max:2048'],\n        'skills' => ['nullable', 'array', 'min:2'],\n        'skills.*' => ['string', 'in:vue,react,laravel,tailwind'],\n        'tags' => ['nullable', 'array'],\n        'tags.*' => ['string', 'max:50'],\n        'user.address.street' => ['nullable', 'string', 'max:255'],\n        'user.address.city' => ['nullable', 'string', 'max:255'],\n    ]);\n\n    // Simulate file upload progress\n    if (request()->hasFile('avatar')) {\n        sleep(1);\n    }\n\n    return back();\n});\n\nRoute::get('/form-component/precognition', function () {\n    return inertia('FormComponentPrecognition');\n});\n\nRoute::post('/form-component/precognition', function (PrecognitionFormRequest $request) {\n    $data = $request->validated();\n\n    // dd($data);\n\n    return back();\n})->middleware([HandlePrecognitiveRequests::class]);\n\nRoute::get('/photo-grid/{horizontal?}', function ($horizontal = null) {\n    if (request()->header('X-Inertia-Partial-Component')) {\n        // Simulate latency for partial reloads\n        usleep(250_000);\n    }\n\n    $perPage = 24;\n    $pages = 30;\n    $total = $perPage * $pages;\n    $page = request()->integer('page', 1);\n\n    $photos = collect()\n        ->range(1, $total)\n        ->forPage($page, $perPage)\n        ->map(fn ($i) => [\n            'id' => $i,\n            'url' => \"https://picsum.photos/id/{$i}/300/300\",\n        ])\n        ->pipe(fn ($photos) => new LengthAwarePaginator(\n            $photos->values(),\n            $total,\n            $perPage,\n            $page,\n        ));\n\n    return inertia($horizontal ? 'PhotoHorizontal' : 'PhotoGrid', [\n        'photos' => Inertia::scroll($photos),\n    ]);\n});\n\nRoute::get('/data-table', function () {\n    if (request()->header('X-Inertia-Partial-Component')) {\n        // Simulate latency for partial reloads\n        usleep(500_000);\n    }\n\n    $perPage = 200;\n    $pages = 30;\n    $total = $perPage * $pages;\n    $page = request()->integer('page', 1);\n\n    $users = collect()\n        ->range(1, $total)\n        ->forPage($page, $perPage)\n        ->map(fn ($i) => [\n            'id' => $i,\n            'name' => \"User {$i}\",\n        ])\n        ->pipe(fn ($photos) => new LengthAwarePaginator(\n            $photos->values(),\n            $total,\n            $perPage,\n            $page,\n        ));\n\n    return inertia('DataTable', [\n        'users' => Inertia::scroll($users),\n    ]);\n});\n\nRoute::get('/once/{page}', function (int $page) {\n    $component = match ($page) {\n        1 => 'Once/First',\n        2 => 'Once/Second',\n        3 => 'Once/Third',\n        4 => 'Once/Fourth',\n        default => abort(404),\n    };\n\n    return inertia($component, [\n        'foo' => Inertia::once(fn () => 'foo value: '.now()->getTimestampMs())->fresh($page === 3),\n        'bar' => Inertia::once(fn () => 'bar value: '.now()->getTimestampMs())->until(10),\n        'baz' . $page => Inertia::once(fn () => 'baz value: '.now()->getTimestampMs())->as('baz'),\n        'qux' => Inertia::defer(fn () => 'qux value: '.now()->getTimestampMs())->once(),\n    ]);\n});\n\nRoute::get('/flash', function () {\n    return inertia('Flash');\n});\n\nRoute::get('/flash/direct', function () {\n    return Inertia::flash('message', 'Sent with render!')->render('Flash');\n});\n\nRoute::post('/flash/form', function () {\n    return Inertia::flash('message', 'Sent with redirect!')->back();\n});\n"
  },
  {
    "path": "playgrounds/svelte5/storage/app/.gitignore",
    "content": "*\n!public/\n!.gitignore\n"
  },
  {
    "path": "playgrounds/svelte5/storage/framework/.gitignore",
    "content": "compiled.php\nconfig.php\ndown\nevents.scanned.php\nmaintenance.php\nroutes.php\nroutes.scanned.php\nschedule-*\nservices.json\n"
  },
  {
    "path": "playgrounds/svelte5/storage/framework/cache/.gitignore",
    "content": "*\n!data/\n!.gitignore\n"
  },
  {
    "path": "playgrounds/svelte5/storage/framework/sessions/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/svelte5/storage/framework/testing/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/svelte5/storage/framework/views/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/svelte5/storage/logs/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/svelte5/tests/CreatesApplication.php",
    "content": "<?php\n\nnamespace Tests;\n\nuse Illuminate\\Contracts\\Console\\Kernel;\n\ntrait CreatesApplication\n{\n    /**\n     * Creates the application.\n     *\n     * @return \\Illuminate\\Foundation\\Application\n     */\n    public function createApplication()\n    {\n        $app = require __DIR__.'/../bootstrap/app.php';\n\n        $app->make(Kernel::class)->bootstrap();\n\n        return $app;\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/tests/Feature/ExampleTest.php",
    "content": "<?php\n\nnamespace Tests\\Feature;\n\n// use Illuminate\\Foundation\\Testing\\RefreshDatabase;\nuse Tests\\TestCase;\n\nclass ExampleTest extends TestCase\n{\n    /**\n     * A basic test example.\n     *\n     * @return void\n     */\n    public function test_the_application_returns_a_successful_response()\n    {\n        $response = $this->get('/');\n\n        $response->assertStatus(200);\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/tests/TestCase.php",
    "content": "<?php\n\nnamespace Tests;\n\nuse Illuminate\\Foundation\\Testing\\TestCase as BaseTestCase;\n\nabstract class TestCase extends BaseTestCase\n{\n    use CreatesApplication;\n}\n"
  },
  {
    "path": "playgrounds/svelte5/tests/Unit/ExampleTest.php",
    "content": "<?php\n\nnamespace Tests\\Unit;\n\nuse PHPUnit\\Framework\\TestCase;\n\nclass ExampleTest extends TestCase\n{\n    /**\n     * A basic test example.\n     *\n     * @return void\n     */\n    public function test_that_true_is_true()\n    {\n        $this->assertTrue(true);\n    }\n}\n"
  },
  {
    "path": "playgrounds/svelte5/tsconfig.json",
    "content": "{\n  \"extends\": \"@tsconfig/svelte/tsconfig.json\",\n  \"compilerOptions\": {\n    \"allowJs\": true,\n    \"checkJs\": true,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"resolveJsonModule\": true,\n    \"skipLibCheck\": true,\n    \"sourceMap\": true,\n    \"strict\": true,\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"node\",\n    \"paths\": {\n      \"@inertiajs/svelte/server\": [\"../../node_modules/@inertiajs/svelte/dist/server\"]\n    }\n  },\n  \"include\": [\n    \"resources/**/*.d.ts\",\n    \"resources/**/*.ts\",\n    \"resources/**/*.js\",\n    \"resources/**/*.svelte\",\n    \"*.config.js\",\n    \"*.config.cjs\"\n  ]\n}\n"
  },
  {
    "path": "playgrounds/svelte5/vite.config.js",
    "content": "import { svelte } from '@sveltejs/vite-plugin-svelte'\nimport tailwindcss from '@tailwindcss/vite'\nimport laravel from 'laravel-vite-plugin'\nimport { defineConfig } from 'vite'\n\nexport default defineConfig({\n  build: {\n    minify: false,\n  },\n  plugins: [\n    laravel({\n      input: ['resources/css/app.css', 'resources/js/app.ts'],\n      ssr: 'resources/js/ssr.ts',\n      refresh: true,\n    }),\n    svelte(),\n    tailwindcss(),\n  ],\n})\n"
  },
  {
    "path": "playgrounds/vue3/.gitattributes",
    "content": "* text=auto\n\n*.blade.php diff=html\n*.css diff=css\n*.html diff=html\n*.md diff=markdown\n*.php diff=php\n\n/.github export-ignore\nCHANGELOG.md export-ignore\n.styleci.yml export-ignore\n"
  },
  {
    "path": "playgrounds/vue3/.gitignore",
    "content": "/node_modules\n/bootstrap/ssr\n/public/build\n/public/hot\n/public/storage\n/storage/*.key\n/vendor\n.env\n.env.backup\n.env.production\n.phpunit.result.cache\nHomestead.json\nHomestead.yaml\nauth.json\nnpm-debug.log\nyarn-error.log\n/.fleet\n/.idea\n/.vscode\n"
  },
  {
    "path": "playgrounds/vue3/README.md",
    "content": "<p align=\"center\"><a href=\"https://laravel.com\" target=\"_blank\"><img src=\"https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg\" width=\"400\" alt=\"Laravel Logo\"></a></p>\n\n<p align=\"center\">\n<a href=\"https://travis-ci.org/laravel/framework\"><img src=\"https://travis-ci.org/laravel/framework.svg\" alt=\"Build Status\"></a>\n<a href=\"https://packagist.org/packages/laravel/framework\"><img src=\"https://img.shields.io/packagist/dt/laravel/framework\" alt=\"Total Downloads\"></a>\n<a href=\"https://packagist.org/packages/laravel/framework\"><img src=\"https://img.shields.io/packagist/v/laravel/framework\" alt=\"Latest Stable Version\"></a>\n<a href=\"https://packagist.org/packages/laravel/framework\"><img src=\"https://img.shields.io/packagist/l/laravel/framework\" alt=\"License\"></a>\n</p>\n\n## About Laravel\n\nLaravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:\n\n- [Simple, fast routing engine](https://laravel.com/docs/routing).\n- [Powerful dependency injection container](https://laravel.com/docs/container).\n- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.\n- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).\n- Database agnostic [schema migrations](https://laravel.com/docs/migrations).\n- [Robust background job processing](https://laravel.com/docs/queues).\n- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).\n\nLaravel is accessible, powerful, and provides tools required for large, robust applications.\n\n## Learning Laravel\n\nLaravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.\n\nYou may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.\n\nIf you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 2000 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.\n\n## Laravel Sponsors\n\nWe would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell).\n\n### Premium Partners\n\n- **[Vehikl](https://vehikl.com/)**\n- **[Tighten Co.](https://tighten.co)**\n- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**\n- **[64 Robots](https://64robots.com)**\n- **[Cubet Techno Labs](https://cubettech.com)**\n- **[Cyber-Duck](https://cyber-duck.co.uk)**\n- **[Many](https://www.many.co.uk)**\n- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**\n- **[DevSquad](https://devsquad.com)**\n- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**\n- **[OP.GG](https://op.gg)**\n- **[WebReinvent](https://webreinvent.com/?utm_source=laravel&utm_medium=github&utm_campaign=patreon-sponsors)**\n- **[Lendio](https://lendio.com)**\n\n## Contributing\n\nThank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).\n\n## Code of Conduct\n\nIn order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).\n\n## Security Vulnerabilities\n\nIf you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.\n\n## License\n\nThe Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).\n"
  },
  {
    "path": "playgrounds/vue3/app/Console/Kernel.php",
    "content": "<?php\n\nnamespace App\\Console;\n\nuse Illuminate\\Console\\Scheduling\\Schedule;\nuse Illuminate\\Foundation\\Console\\Kernel as ConsoleKernel;\n\nclass Kernel extends ConsoleKernel\n{\n    /**\n     * Define the application's command schedule.\n     *\n     * @return void\n     */\n    protected function schedule(Schedule $schedule)\n    {\n        // $schedule->command('inspire')->hourly();\n    }\n\n    /**\n     * Register the commands for the application.\n     *\n     * @return void\n     */\n    protected function commands()\n    {\n        $this->load(__DIR__.'/Commands');\n\n        require base_path('routes/console.php');\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Exceptions/Handler.php",
    "content": "<?php\n\nnamespace App\\Exceptions;\n\nuse Illuminate\\Foundation\\Exceptions\\Handler as ExceptionHandler;\nuse Throwable;\n\nclass Handler extends ExceptionHandler\n{\n    /**\n     * A list of exception types with their corresponding custom log levels.\n     *\n     * @var array<class-string<\\Throwable>, \\Psr\\Log\\LogLevel::*>\n     */\n    protected $levels = [\n        //\n    ];\n\n    /**\n     * A list of the exception types that are not reported.\n     *\n     * @var array<int, class-string<\\Throwable>>\n     */\n    protected $dontReport = [\n        //\n    ];\n\n    /**\n     * A list of the inputs that are never flashed to the session on validation exceptions.\n     *\n     * @var array<int, string>\n     */\n    protected $dontFlash = [\n        'current_password',\n        'password',\n        'password_confirmation',\n    ];\n\n    /**\n     * Register the exception handling callbacks for the application.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        $this->reportable(function (Throwable $e) {\n            //\n        });\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Http/Controllers/Controller.php",
    "content": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Foundation\\Auth\\Access\\AuthorizesRequests;\nuse Illuminate\\Foundation\\Bus\\DispatchesJobs;\nuse Illuminate\\Foundation\\Validation\\ValidatesRequests;\nuse Illuminate\\Routing\\Controller as BaseController;\n\nclass Controller extends BaseController\n{\n    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Http/Kernel.php",
    "content": "<?php\n\nnamespace App\\Http;\n\nuse Illuminate\\Foundation\\Http\\Kernel as HttpKernel;\n\nclass Kernel extends HttpKernel\n{\n    /**\n     * The application's global HTTP middleware stack.\n     *\n     * These middleware are run during every request to your application.\n     *\n     * @var array<int, class-string|string>\n     */\n    protected $middleware = [\n        // \\App\\Http\\Middleware\\TrustHosts::class,\n        \\App\\Http\\Middleware\\TrustProxies::class,\n        \\Illuminate\\Http\\Middleware\\HandleCors::class,\n        \\App\\Http\\Middleware\\PreventRequestsDuringMaintenance::class,\n        \\Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize::class,\n        \\App\\Http\\Middleware\\TrimStrings::class,\n        \\Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull::class,\n    ];\n\n    /**\n     * The application's route middleware groups.\n     *\n     * @var array<string, array<int, class-string|string>>\n     */\n    protected $middlewareGroups = [\n        'web' => [\n            \\App\\Http\\Middleware\\EncryptCookies::class,\n            \\Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse::class,\n            \\Illuminate\\Session\\Middleware\\StartSession::class,\n            \\Illuminate\\View\\Middleware\\ShareErrorsFromSession::class,\n            \\App\\Http\\Middleware\\VerifyCsrfToken::class,\n            \\Illuminate\\Routing\\Middleware\\SubstituteBindings::class,\n            \\App\\Http\\Middleware\\HandleInertiaRequests::class,\n        ],\n\n        'api' => [\n            // \\Laravel\\Sanctum\\Http\\Middleware\\EnsureFrontendRequestsAreStateful::class,\n            'throttle:api',\n            \\Illuminate\\Routing\\Middleware\\SubstituteBindings::class,\n        ],\n    ];\n\n    /**\n     * The application's route middleware.\n     *\n     * These middleware may be assigned to groups or used individually.\n     *\n     * @var array<string, class-string|string>\n     */\n    protected $routeMiddleware = [\n        'auth' => \\App\\Http\\Middleware\\Authenticate::class,\n        'auth.basic' => \\Illuminate\\Auth\\Middleware\\AuthenticateWithBasicAuth::class,\n        'auth.session' => \\Illuminate\\Session\\Middleware\\AuthenticateSession::class,\n        'cache.headers' => \\Illuminate\\Http\\Middleware\\SetCacheHeaders::class,\n        'can' => \\Illuminate\\Auth\\Middleware\\Authorize::class,\n        'guest' => \\App\\Http\\Middleware\\RedirectIfAuthenticated::class,\n        'password.confirm' => \\Illuminate\\Auth\\Middleware\\RequirePassword::class,\n        'signed' => \\App\\Http\\Middleware\\ValidateSignature::class,\n        'throttle' => \\Illuminate\\Routing\\Middleware\\ThrottleRequests::class,\n        'verified' => \\Illuminate\\Auth\\Middleware\\EnsureEmailIsVerified::class,\n    ];\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Http/Middleware/Authenticate.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Auth\\Middleware\\Authenticate as Middleware;\n\nclass Authenticate extends Middleware\n{\n    /**\n     * Get the path the user should be redirected to when they are not authenticated.\n     *\n     * @param  \\Illuminate\\Http\\Request  $request\n     * @return string|null\n     */\n    protected function redirectTo($request)\n    {\n        if (! $request->expectsJson()) {\n            return route('login');\n        }\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Http/Middleware/EncryptCookies.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Cookie\\Middleware\\EncryptCookies as Middleware;\n\nclass EncryptCookies extends Middleware\n{\n    /**\n     * The names of the cookies that should not be encrypted.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        //\n    ];\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Http/Middleware/HandleInertiaRequests.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Http\\Request;\nuse Inertia\\Middleware;\n\nclass HandleInertiaRequests extends Middleware\n{\n    /**\n     * The root template that's loaded on the first page visit.\n     *\n     * @see https://inertiajs.com/server-side-setup#root-template\n     *\n     * @var string\n     */\n    protected $rootView = 'app';\n\n    /**\n     * Determines the current asset version.\n     *\n     * @see https://inertiajs.com/asset-versioning\n     */\n    public function version(Request $request): ?string\n    {\n        return parent::version($request);\n    }\n\n    /**\n     * Defines the props that are shared by default.\n     *\n     * @see https://inertiajs.com/shared-data\n     */\n    public function share(Request $request): array\n    {\n        return array_merge(parent::share($request), [\n            'appName' => config('app.name'),\n        ]);\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Http/Middleware/PreventRequestsDuringMaintenance.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance as Middleware;\n\nclass PreventRequestsDuringMaintenance extends Middleware\n{\n    /**\n     * The URIs that should be reachable while maintenance mode is enabled.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        //\n    ];\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Http/Middleware/RedirectIfAuthenticated.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse App\\Providers\\RouteServiceProvider;\nuse Closure;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Auth;\n\nclass RedirectIfAuthenticated\n{\n    /**\n     * Handle an incoming request.\n     *\n     * @param  \\Closure(\\Illuminate\\Http\\Request): (\\Illuminate\\Http\\Response|\\Illuminate\\Http\\RedirectResponse)  $next\n     * @param  string|null  ...$guards\n     * @return \\Illuminate\\Http\\Response|\\Illuminate\\Http\\RedirectResponse\n     */\n    public function handle(Request $request, Closure $next, ...$guards)\n    {\n        $guards = empty($guards) ? [null] : $guards;\n\n        foreach ($guards as $guard) {\n            if (Auth::guard($guard)->check()) {\n                return redirect(RouteServiceProvider::HOME);\n            }\n        }\n\n        return $next($request);\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Http/Middleware/TrimStrings.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Foundation\\Http\\Middleware\\TrimStrings as Middleware;\n\nclass TrimStrings extends Middleware\n{\n    /**\n     * The names of the attributes that should not be trimmed.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        'current_password',\n        'password',\n        'password_confirmation',\n    ];\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Http/Middleware/TrustHosts.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Http\\Middleware\\TrustHosts as Middleware;\n\nclass TrustHosts extends Middleware\n{\n    /**\n     * Get the host patterns that should be trusted.\n     *\n     * @return array<int, string|null>\n     */\n    public function hosts()\n    {\n        return [\n            $this->allSubdomainsOfApplicationUrl(),\n        ];\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Http/Middleware/TrustProxies.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Http\\Middleware\\TrustProxies as Middleware;\nuse Illuminate\\Http\\Request;\n\nclass TrustProxies extends Middleware\n{\n    /**\n     * The trusted proxies for this application.\n     *\n     * @var array<int, string>|string|null\n     */\n    protected $proxies;\n\n    /**\n     * The headers that should be used to detect proxies.\n     *\n     * @var int\n     */\n    protected $headers =\n        Request::HEADER_X_FORWARDED_FOR |\n        Request::HEADER_X_FORWARDED_HOST |\n        Request::HEADER_X_FORWARDED_PORT |\n        Request::HEADER_X_FORWARDED_PROTO |\n        Request::HEADER_X_FORWARDED_AWS_ELB;\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Http/Middleware/ValidateSignature.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Routing\\Middleware\\ValidateSignature as Middleware;\n\nclass ValidateSignature extends Middleware\n{\n    /**\n     * The names of the query string parameters that should be ignored.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        // 'fbclid',\n        // 'utm_campaign',\n        // 'utm_content',\n        // 'utm_medium',\n        // 'utm_source',\n        // 'utm_term',\n    ];\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Http/Middleware/VerifyCsrfToken.php",
    "content": "<?php\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Foundation\\Http\\Middleware\\VerifyCsrfToken as Middleware;\n\nclass VerifyCsrfToken extends Middleware\n{\n    /**\n     * The URIs that should be excluded from CSRF verification.\n     *\n     * @var array<int, string>\n     */\n    protected $except = [\n        //\n    ];\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Http/Requests/PrecognitionFormRequest.php",
    "content": "<?php\n\nnamespace App\\Http\\Requests;\n\nuse Illuminate\\Foundation\\Http\\FormRequest;\n\nclass PrecognitionFormRequest extends FormRequest\n{\n    /**\n     * Determine if the user is authorized to make this request.\n     */\n    public function authorize(): bool\n    {\n        return true;\n    }\n\n    /**\n     * Get the validation rules that apply to the request.\n     *\n     * @return array<string, \\Illuminate\\Contracts\\Validation\\ValidationRule|array<mixed>|string>\n     */\n    public function rules(): array\n    {\n        sleep(1);\n\n        return [\n            'name' => ['required', 'string', 'min:3', 'max:255'],\n            'email' => ['required', 'email', 'max:255'],\n            'avatar' => ['nullable', 'file', 'image'],\n        ];\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Http/Resources/UserResource.php",
    "content": "<?php\n\nnamespace App\\Http\\Resources;\n\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Http\\Resources\\Json\\JsonResource;\n\nclass UserResource extends JsonResource\n{\n    /**\n     * Transform the resource into an array.\n     *\n     * @return array<string, mixed>\n     */\n    public function toArray(Request $request): array\n    {\n        return parent::toArray($request);\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Models/ChatMessage.php",
    "content": "<?php\n\nnamespace App\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\n\nclass ChatMessage extends Model\n{\n    protected $hidden = ['updated_at'];\n\n    protected $guarded = [];\n\n    use HasFactory;\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Models/User.php",
    "content": "<?php\n\nnamespace App\\Models;\n\n// use Illuminate\\Contracts\\Auth\\MustVerifyEmail;\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Foundation\\Auth\\User as Authenticatable;\nuse Illuminate\\Notifications\\Notifiable;\nuse Laravel\\Sanctum\\HasApiTokens;\n\nclass User extends Authenticatable\n{\n    use HasApiTokens, HasFactory, Notifiable;\n\n    /**\n     * The attributes that are mass assignable.\n     *\n     * @var array<int, string>\n     */\n    protected $fillable = [\n        'name',\n        'email',\n        'password',\n    ];\n\n    /**\n     * The attributes that should be hidden for serialization.\n     *\n     * @var array<int, string>\n     */\n    protected $hidden = [\n        'password',\n        'remember_token',\n    ];\n\n    /**\n     * The attributes that should be cast.\n     *\n     * @var array<string, string>\n     */\n    protected $casts = [\n        'email_verified_at' => 'datetime',\n    ];\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Providers/AppServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Support\\ServiceProvider;\n\nclass AppServiceProvider extends ServiceProvider\n{\n    /**\n     * Register any application services.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        //\n    }\n\n    /**\n     * Bootstrap any application services.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Providers/AuthServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\n// use Illuminate\\Support\\Facades\\Gate;\nuse Illuminate\\Foundation\\Support\\Providers\\AuthServiceProvider as ServiceProvider;\n\nclass AuthServiceProvider extends ServiceProvider\n{\n    /**\n     * The model to policy mappings for the application.\n     *\n     * @var array<class-string, class-string>\n     */\n    protected $policies = [\n        // 'App\\Models\\Model' => 'App\\Policies\\ModelPolicy',\n    ];\n\n    /**\n     * Register any authentication / authorization services.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        $this->registerPolicies();\n\n        //\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Providers/BroadcastServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Support\\Facades\\Broadcast;\nuse Illuminate\\Support\\ServiceProvider;\n\nclass BroadcastServiceProvider extends ServiceProvider\n{\n    /**\n     * Bootstrap any application services.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        Broadcast::routes();\n\n        require base_path('routes/channels.php');\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Providers/EventServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Auth\\Events\\Registered;\nuse Illuminate\\Auth\\Listeners\\SendEmailVerificationNotification;\nuse Illuminate\\Foundation\\Support\\Providers\\EventServiceProvider as ServiceProvider;\nuse Illuminate\\Support\\Facades\\Event;\n\nclass EventServiceProvider extends ServiceProvider\n{\n    /**\n     * The event to listener mappings for the application.\n     *\n     * @var array<class-string, array<int, class-string>>\n     */\n    protected $listen = [\n        Registered::class => [\n            SendEmailVerificationNotification::class,\n        ],\n    ];\n\n    /**\n     * Register any events for your application.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        //\n    }\n\n    /**\n     * Determine if events and listeners should be automatically discovered.\n     *\n     * @return bool\n     */\n    public function shouldDiscoverEvents()\n    {\n        return false;\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/app/Providers/RouteServiceProvider.php",
    "content": "<?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Cache\\RateLimiting\\Limit;\nuse Illuminate\\Foundation\\Support\\Providers\\RouteServiceProvider as ServiceProvider;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\RateLimiter;\nuse Illuminate\\Support\\Facades\\Route;\n\nclass RouteServiceProvider extends ServiceProvider\n{\n    /**\n     * The path to the \"home\" route for your application.\n     *\n     * Typically, users are redirected here after authentication.\n     *\n     * @var string\n     */\n    public const HOME = '/home';\n\n    /**\n     * Define your route model bindings, pattern filters, and other route configuration.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        $this->configureRateLimiting();\n\n        $this->routes(function () {\n            Route::middleware('api')\n                ->prefix('api')\n                ->group(base_path('routes/api.php'));\n\n            Route::middleware('web')\n                ->group(base_path('routes/web.php'));\n        });\n    }\n\n    /**\n     * Configure the rate limiters for the application.\n     *\n     * @return void\n     */\n    protected function configureRateLimiting()\n    {\n        RateLimiter::for('api', function (Request $request) {\n            return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());\n        });\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/artisan",
    "content": "#!/usr/bin/env php\n<?php\n\ndefine('LARAVEL_START', microtime(true));\n\n/*\n|--------------------------------------------------------------------------\n| Register The Auto Loader\n|--------------------------------------------------------------------------\n|\n| Composer provides a convenient, automatically generated class loader\n| for our application. We just need to utilize it! We'll require it\n| into the script here so that we do not have to worry about the\n| loading of any of our classes manually. It's great to relax.\n|\n*/\n\nrequire __DIR__.'/vendor/autoload.php';\n\n$app = require_once __DIR__.'/bootstrap/app.php';\n\n/*\n|--------------------------------------------------------------------------\n| Run The Artisan Application\n|--------------------------------------------------------------------------\n|\n| When we run the console application, the current CLI command will be\n| executed in this console and the response sent back to a terminal\n| or another output device for the developers. Here goes nothing!\n|\n*/\n\n$kernel = $app->make(Illuminate\\Contracts\\Console\\Kernel::class);\n\n$status = $kernel->handle(\n    $input = new Symfony\\Component\\Console\\Input\\ArgvInput,\n    new Symfony\\Component\\Console\\Output\\ConsoleOutput\n);\n\n/*\n|--------------------------------------------------------------------------\n| Shutdown The Application\n|--------------------------------------------------------------------------\n|\n| Once Artisan has finished running, we will fire off the shutdown events\n| so that any final work may be done by the application before we shut\n| down the process. This is the last thing to happen to the request.\n|\n*/\n\n$kernel->terminate($input, $status);\n\nexit($status);\n"
  },
  {
    "path": "playgrounds/vue3/bootstrap/app.php",
    "content": "<?php\n\n/*\n|--------------------------------------------------------------------------\n| Create The Application\n|--------------------------------------------------------------------------\n|\n| The first thing we will do is create a new Laravel application instance\n| which serves as the \"glue\" for all the components of Laravel, and is\n| the IoC container for the system binding all of the various parts.\n|\n*/\n\n$app = new Illuminate\\Foundation\\Application(\n    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)\n);\n\n/*\n|--------------------------------------------------------------------------\n| Bind Important Interfaces\n|--------------------------------------------------------------------------\n|\n| Next, we need to bind some important interfaces into the container so\n| we will be able to resolve them when needed. The kernels serve the\n| incoming requests to this application from both the web and CLI.\n|\n*/\n\n$app->singleton(\n    Illuminate\\Contracts\\Http\\Kernel::class,\n    App\\Http\\Kernel::class\n);\n\n$app->singleton(\n    Illuminate\\Contracts\\Console\\Kernel::class,\n    App\\Console\\Kernel::class\n);\n\n$app->singleton(\n    Illuminate\\Contracts\\Debug\\ExceptionHandler::class,\n    App\\Exceptions\\Handler::class\n);\n\n/*\n|--------------------------------------------------------------------------\n| Return The Application\n|--------------------------------------------------------------------------\n|\n| This script returns the application instance. The instance is given to\n| the calling script so we can separate the building of the instances\n| from the actual running of the application and sending responses.\n|\n*/\n\nreturn $app;\n"
  },
  {
    "path": "playgrounds/vue3/bootstrap/cache/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/vue3/composer.json",
    "content": "{\n    \"name\": \"laravel/laravel\",\n    \"type\": \"project\",\n    \"description\": \"The Laravel Framework.\",\n    \"keywords\": [\n        \"framework\",\n        \"laravel\"\n    ],\n    \"license\": \"MIT\",\n    \"require\": {\n        \"php\": \"^8.2\",\n        \"guzzlehttp/guzzle\": \"^7.2\",\n        \"inertiajs/inertia-laravel\": \"^2.0.16\",\n        \"laravel/framework\": \"^11.0\",\n        \"laravel/sanctum\": \"^4.0\",\n        \"laravel/tinker\": \"^2.7\",\n        \"prism-php/prism\": \"^0.89.0\"\n    },\n    \"require-dev\": {\n        \"fakerphp/faker\": \"^1.9.1\",\n        \"laravel/pint\": \"^1.0\",\n        \"laravel/sail\": \"^1.0.1\",\n        \"mockery/mockery\": \"^1.4.4\",\n        \"nunomaduro/collision\": \"^8.1\",\n        \"phpunit/phpunit\": \"^10.0\",\n        \"spatie/laravel-ignition\": \"^2.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"App\\\\\": \"app/\",\n            \"Database\\\\Factories\\\\\": \"database/factories/\",\n            \"Database\\\\Seeders\\\\\": \"database/seeders/\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Tests\\\\\": \"tests/\"\n        }\n    },\n    \"scripts\": {\n        \"post-autoload-dump\": [\n            \"Illuminate\\\\Foundation\\\\ComposerScripts::postAutoloadDump\",\n            \"@php artisan package:discover --ansi\"\n        ],\n        \"post-update-cmd\": [\n            \"@php artisan vendor:publish --tag=laravel-assets --ansi --force\"\n        ],\n        \"post-root-package-install\": [\n            \"@php -r \\\"file_exists('.env') || copy('.env.example', '.env');\\\"\"\n        ],\n        \"post-create-project-cmd\": [\n            \"@php artisan key:generate --ansi\"\n        ],\n        \"dev\": [\n            \"Composer\\\\Config::disableProcessTimeout\",\n            \"pnpx concurrently -c \\\"#93c5fd,#c4b5fd\\\" \\\"php artisan serve\\\" \\\"pnpm run dev\\\" --names=server,vite\"\n        ]\n    },\n    \"extra\": {\n        \"laravel\": {\n            \"dont-discover\": []\n        }\n    },\n    \"config\": {\n        \"optimize-autoloader\": true,\n        \"preferred-install\": \"dist\",\n        \"sort-packages\": true,\n        \"allow-plugins\": {\n            \"pestphp/pest-plugin\": true\n        }\n    },\n    \"minimum-stability\": \"dev\",\n    \"prefer-stable\": true\n}\n"
  },
  {
    "path": "playgrounds/vue3/config/app.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Facades\\Facade;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Name\n    |--------------------------------------------------------------------------\n    |\n    | This value is the name of your application. This value is used when the\n    | framework needs to place the application's name in a notification or\n    | any other location as required by the application or its packages.\n    |\n    */\n\n    'name' => env('APP_NAME', 'Laravel'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Environment\n    |--------------------------------------------------------------------------\n    |\n    | This value determines the \"environment\" your application is currently\n    | running in. This may determine how you prefer to configure various\n    | services the application utilizes. Set this in your \".env\" file.\n    |\n    */\n\n    'env' => env('APP_ENV', 'production'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Debug Mode\n    |--------------------------------------------------------------------------\n    |\n    | When your application is in debug mode, detailed error messages with\n    | stack traces will be shown on every error that occurs within your\n    | application. If disabled, a simple generic error page is shown.\n    |\n    */\n\n    'debug' => (bool) env('APP_DEBUG', false),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application URL\n    |--------------------------------------------------------------------------\n    |\n    | This URL is used by the console to properly generate URLs when using\n    | the Artisan command line tool. You should set this to the root of\n    | your application so that it is used when running Artisan tasks.\n    |\n    */\n\n    'url' => env('APP_URL', 'http://localhost'),\n\n    'asset_url' => env('ASSET_URL'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Timezone\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the default timezone for your application, which\n    | will be used by the PHP date and date-time functions. We have gone\n    | ahead and set this to a sensible default for you out of the box.\n    |\n    */\n\n    'timezone' => 'UTC',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Locale Configuration\n    |--------------------------------------------------------------------------\n    |\n    | The application locale determines the default locale that will be used\n    | by the translation service provider. You are free to set this value\n    | to any of the locales which will be supported by the application.\n    |\n    */\n\n    'locale' => 'en',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Application Fallback Locale\n    |--------------------------------------------------------------------------\n    |\n    | The fallback locale determines the locale to use when the current one\n    | is not available. You may change the value to correspond to any of\n    | the language folders that are provided through your application.\n    |\n    */\n\n    'fallback_locale' => 'en',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Faker Locale\n    |--------------------------------------------------------------------------\n    |\n    | This locale will be used by the Faker PHP library when generating fake\n    | data for your database seeds. For example, this will be used to get\n    | localized telephone numbers, street address information and more.\n    |\n    */\n\n    'faker_locale' => 'en_US',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Encryption Key\n    |--------------------------------------------------------------------------\n    |\n    | This key is used by the Illuminate encrypter service and should be set\n    | to a random, 32 character string, otherwise these encrypted strings\n    | will not be safe. Please do this before deploying an application!\n    |\n    */\n\n    'key' => env('APP_KEY'),\n\n    'cipher' => 'AES-256-CBC',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Maintenance Mode Driver\n    |--------------------------------------------------------------------------\n    |\n    | These configuration options determine the driver used to determine and\n    | manage Laravel's \"maintenance mode\" status. The \"cache\" driver will\n    | allow maintenance mode to be controlled across multiple machines.\n    |\n    | Supported drivers: \"file\", \"cache\"\n    |\n    */\n\n    'maintenance' => [\n        'driver' => 'file',\n        // 'store'  => 'redis',\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Autoloaded Service Providers\n    |--------------------------------------------------------------------------\n    |\n    | The service providers listed here will be automatically loaded on the\n    | request to your application. Feel free to add your own services to\n    | this array to grant expanded functionality to your applications.\n    |\n    */\n\n    'providers' => [\n\n        /*\n         * Laravel Framework Service Providers...\n         */\n        Illuminate\\Auth\\AuthServiceProvider::class,\n        Illuminate\\Broadcasting\\BroadcastServiceProvider::class,\n        Illuminate\\Bus\\BusServiceProvider::class,\n        Illuminate\\Cache\\CacheServiceProvider::class,\n        Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider::class,\n        Illuminate\\Cookie\\CookieServiceProvider::class,\n        Illuminate\\Database\\DatabaseServiceProvider::class,\n        Illuminate\\Encryption\\EncryptionServiceProvider::class,\n        Illuminate\\Filesystem\\FilesystemServiceProvider::class,\n        Illuminate\\Foundation\\Providers\\FoundationServiceProvider::class,\n        Illuminate\\Hashing\\HashServiceProvider::class,\n        Illuminate\\Mail\\MailServiceProvider::class,\n        Illuminate\\Notifications\\NotificationServiceProvider::class,\n        Illuminate\\Pagination\\PaginationServiceProvider::class,\n        Illuminate\\Pipeline\\PipelineServiceProvider::class,\n        Illuminate\\Queue\\QueueServiceProvider::class,\n        Illuminate\\Redis\\RedisServiceProvider::class,\n        Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider::class,\n        Illuminate\\Session\\SessionServiceProvider::class,\n        Illuminate\\Translation\\TranslationServiceProvider::class,\n        Illuminate\\Validation\\ValidationServiceProvider::class,\n        Illuminate\\View\\ViewServiceProvider::class,\n\n        /*\n         * Package Service Providers...\n         */\n\n        /*\n         * Application Service Providers...\n         */\n        App\\Providers\\AppServiceProvider::class,\n        App\\Providers\\AuthServiceProvider::class,\n        // App\\Providers\\BroadcastServiceProvider::class,\n        App\\Providers\\EventServiceProvider::class,\n        App\\Providers\\RouteServiceProvider::class,\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Class Aliases\n    |--------------------------------------------------------------------------\n    |\n    | This array of class aliases will be registered when this application\n    | is started. However, feel free to register as many as you wish as\n    | the aliases are \"lazy\" loaded so they don't hinder performance.\n    |\n    */\n\n    'aliases' => Facade::defaultAliases()->merge([\n        // 'ExampleClass' => App\\Example\\ExampleClass::class,\n    ])->toArray(),\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/config/auth.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Authentication Defaults\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default authentication \"guard\" and password\n    | reset options for your application. You may change these defaults\n    | as required, but they're a perfect start for most applications.\n    |\n    */\n\n    'defaults' => [\n        'guard' => 'web',\n        'passwords' => 'users',\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Authentication Guards\n    |--------------------------------------------------------------------------\n    |\n    | Next, you may define every authentication guard for your application.\n    | Of course, a great default configuration has been defined for you\n    | here which uses session storage and the Eloquent user provider.\n    |\n    | All authentication drivers have a user provider. This defines how the\n    | users are actually retrieved out of your database or other storage\n    | mechanisms used by this application to persist your user's data.\n    |\n    | Supported: \"session\"\n    |\n    */\n\n    'guards' => [\n        'web' => [\n            'driver' => 'session',\n            'provider' => 'users',\n        ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | User Providers\n    |--------------------------------------------------------------------------\n    |\n    | All authentication drivers have a user provider. This defines how the\n    | users are actually retrieved out of your database or other storage\n    | mechanisms used by this application to persist your user's data.\n    |\n    | If you have multiple user tables or models you may configure multiple\n    | sources which represent each model / table. These sources may then\n    | be assigned to any extra authentication guards you have defined.\n    |\n    | Supported: \"database\", \"eloquent\"\n    |\n    */\n\n    'providers' => [\n        'users' => [\n            'driver' => 'eloquent',\n            'model' => App\\Models\\User::class,\n        ],\n\n        // 'users' => [\n        //     'driver' => 'database',\n        //     'table' => 'users',\n        // ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Resetting Passwords\n    |--------------------------------------------------------------------------\n    |\n    | You may specify multiple password reset configurations if you have more\n    | than one user table or model in the application and you want to have\n    | separate password reset settings based on the specific user types.\n    |\n    | The expire time is the number of minutes that each reset token will be\n    | considered valid. This security feature keeps tokens short-lived so\n    | they have less time to be guessed. You may change this as needed.\n    |\n    */\n\n    'passwords' => [\n        'users' => [\n            'provider' => 'users',\n            'table' => 'password_resets',\n            'expire' => 60,\n            'throttle' => 60,\n        ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Password Confirmation Timeout\n    |--------------------------------------------------------------------------\n    |\n    | Here you may define the amount of seconds before a password confirmation\n    | times out and the user is prompted to re-enter their password via the\n    | confirmation screen. By default, the timeout lasts for three hours.\n    |\n    */\n\n    'password_timeout' => 10800,\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/config/broadcasting.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Broadcaster\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default broadcaster that will be used by the\n    | framework when an event needs to be broadcast. You may set this to\n    | any of the connections defined in the \"connections\" array below.\n    |\n    | Supported: \"pusher\", \"ably\", \"redis\", \"log\", \"null\"\n    |\n    */\n\n    'default' => env('BROADCAST_DRIVER', 'null'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Broadcast Connections\n    |--------------------------------------------------------------------------\n    |\n    | Here you may define all of the broadcast connections that will be used\n    | to broadcast events to other systems or over websockets. Samples of\n    | each available type of connection are provided inside this array.\n    |\n    */\n\n    'connections' => [\n\n        'pusher' => [\n            'driver' => 'pusher',\n            'key' => env('PUSHER_APP_KEY'),\n            'secret' => env('PUSHER_APP_SECRET'),\n            'app_id' => env('PUSHER_APP_ID'),\n            'options' => [\n                'host' => env('PUSHER_HOST') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com',\n                'port' => env('PUSHER_PORT', 443),\n                'scheme' => env('PUSHER_SCHEME', 'https'),\n                'encrypted' => true,\n                'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',\n            ],\n            'client_options' => [\n                // Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html\n            ],\n        ],\n\n        'ably' => [\n            'driver' => 'ably',\n            'key' => env('ABLY_KEY'),\n        ],\n\n        'redis' => [\n            'driver' => 'redis',\n            'connection' => 'default',\n        ],\n\n        'log' => [\n            'driver' => 'log',\n        ],\n\n        'null' => [\n            'driver' => 'null',\n        ],\n\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/config/cache.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Str;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Cache Store\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default cache connection that gets used while\n    | using this caching library. This connection is used when another is\n    | not explicitly specified when executing a given caching function.\n    |\n    */\n\n    'default' => env('CACHE_DRIVER', 'file'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cache Stores\n    |--------------------------------------------------------------------------\n    |\n    | Here you may define all of the cache \"stores\" for your application as\n    | well as their drivers. You may even define multiple stores for the\n    | same cache driver to group types of items stored in your caches.\n    |\n    | Supported drivers: \"apc\", \"array\", \"database\", \"file\",\n    |         \"memcached\", \"redis\", \"dynamodb\", \"octane\", \"null\"\n    |\n    */\n\n    'stores' => [\n\n        'apc' => [\n            'driver' => 'apc',\n        ],\n\n        'array' => [\n            'driver' => 'array',\n            'serialize' => false,\n        ],\n\n        'database' => [\n            'driver' => 'database',\n            'table' => 'cache',\n            'connection' => null,\n            'lock_connection' => null,\n        ],\n\n        'file' => [\n            'driver' => 'file',\n            'path' => storage_path('framework/cache/data'),\n        ],\n\n        'memcached' => [\n            'driver' => 'memcached',\n            'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),\n            'sasl' => [\n                env('MEMCACHED_USERNAME'),\n                env('MEMCACHED_PASSWORD'),\n            ],\n            'options' => [\n                // Memcached::OPT_CONNECT_TIMEOUT => 2000,\n            ],\n            'servers' => [\n                [\n                    'host' => env('MEMCACHED_HOST', '127.0.0.1'),\n                    'port' => env('MEMCACHED_PORT', 11211),\n                    'weight' => 100,\n                ],\n            ],\n        ],\n\n        'redis' => [\n            'driver' => 'redis',\n            'connection' => 'cache',\n            'lock_connection' => 'default',\n        ],\n\n        'dynamodb' => [\n            'driver' => 'dynamodb',\n            'key' => env('AWS_ACCESS_KEY_ID'),\n            'secret' => env('AWS_SECRET_ACCESS_KEY'),\n            'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),\n            'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),\n            'endpoint' => env('DYNAMODB_ENDPOINT'),\n        ],\n\n        'octane' => [\n            'driver' => 'octane',\n        ],\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cache Key Prefix\n    |--------------------------------------------------------------------------\n    |\n    | When utilizing the APC, database, memcached, Redis, or DynamoDB cache\n    | stores there might be other applications using the same cache. For\n    | that reason, you may prefix every cache key to avoid collisions.\n    |\n    */\n\n    'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'),\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/config/cors.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cross-Origin Resource Sharing (CORS) Configuration\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure your settings for cross-origin resource sharing\n    | or \"CORS\". This determines what cross-origin operations may execute\n    | in web browsers. You are free to adjust these settings as needed.\n    |\n    | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS\n    |\n    */\n\n    'paths' => ['api/*', 'sanctum/csrf-cookie'],\n\n    'allowed_methods' => ['*'],\n\n    'allowed_origins' => ['*'],\n\n    'allowed_origins_patterns' => [],\n\n    'allowed_headers' => ['*'],\n\n    'exposed_headers' => [],\n\n    'max_age' => 0,\n\n    'supports_credentials' => false,\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/config/database.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Str;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Database Connection Name\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify which of the database connections below you wish\n    | to use as your default connection for all database work. Of course\n    | you may use many connections at once using the Database library.\n    |\n    */\n\n    'default' => env('DB_CONNECTION', 'mysql'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Database Connections\n    |--------------------------------------------------------------------------\n    |\n    | Here are each of the database connections setup for your application.\n    | Of course, examples of configuring each database platform that is\n    | supported by Laravel is shown below to make development simple.\n    |\n    |\n    | All database work in Laravel is done through the PHP PDO facilities\n    | so make sure you have the driver for your particular database of\n    | choice installed on your machine before you begin development.\n    |\n    */\n\n    'connections' => [\n\n        'sqlite' => [\n            'driver' => 'sqlite',\n            'url' => env('DATABASE_URL'),\n            'database' => env('DB_DATABASE', database_path('database.sqlite')),\n            'prefix' => '',\n            'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),\n        ],\n\n        'mysql' => [\n            'driver' => 'mysql',\n            'url' => env('DATABASE_URL'),\n            'host' => env('DB_HOST', '127.0.0.1'),\n            'port' => env('DB_PORT', '3306'),\n            'database' => env('DB_DATABASE', 'forge'),\n            'username' => env('DB_USERNAME', 'forge'),\n            'password' => env('DB_PASSWORD', ''),\n            'unix_socket' => env('DB_SOCKET', ''),\n            'charset' => 'utf8mb4',\n            'collation' => 'utf8mb4_unicode_ci',\n            'prefix' => '',\n            'prefix_indexes' => true,\n            'strict' => true,\n            'engine' => null,\n            'options' => extension_loaded('pdo_mysql') ? array_filter([\n                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),\n            ]) : [],\n        ],\n\n        'pgsql' => [\n            'driver' => 'pgsql',\n            'url' => env('DATABASE_URL'),\n            'host' => env('DB_HOST', '127.0.0.1'),\n            'port' => env('DB_PORT', '5432'),\n            'database' => env('DB_DATABASE', 'forge'),\n            'username' => env('DB_USERNAME', 'forge'),\n            'password' => env('DB_PASSWORD', ''),\n            'charset' => 'utf8',\n            'prefix' => '',\n            'prefix_indexes' => true,\n            'search_path' => 'public',\n            'sslmode' => 'prefer',\n        ],\n\n        'sqlsrv' => [\n            'driver' => 'sqlsrv',\n            'url' => env('DATABASE_URL'),\n            'host' => env('DB_HOST', 'localhost'),\n            'port' => env('DB_PORT', '1433'),\n            'database' => env('DB_DATABASE', 'forge'),\n            'username' => env('DB_USERNAME', 'forge'),\n            'password' => env('DB_PASSWORD', ''),\n            'charset' => 'utf8',\n            'prefix' => '',\n            'prefix_indexes' => true,\n            // 'encrypt' => env('DB_ENCRYPT', 'yes'),\n            // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),\n        ],\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Migration Repository Table\n    |--------------------------------------------------------------------------\n    |\n    | This table keeps track of all the migrations that have already run for\n    | your application. Using this information, we can determine which of\n    | the migrations on disk haven't actually been run in the database.\n    |\n    */\n\n    'migrations' => 'migrations',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Redis Databases\n    |--------------------------------------------------------------------------\n    |\n    | Redis is an open source, fast, and advanced key-value store that also\n    | provides a richer body of commands than a typical key-value system\n    | such as APC or Memcached. Laravel makes it easy to dig right in.\n    |\n    */\n\n    'redis' => [\n\n        'client' => env('REDIS_CLIENT', 'phpredis'),\n\n        'options' => [\n            'cluster' => env('REDIS_CLUSTER', 'redis'),\n            'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),\n        ],\n\n        'default' => [\n            'url' => env('REDIS_URL'),\n            'host' => env('REDIS_HOST', '127.0.0.1'),\n            'username' => env('REDIS_USERNAME'),\n            'password' => env('REDIS_PASSWORD'),\n            'port' => env('REDIS_PORT', '6379'),\n            'database' => env('REDIS_DB', '0'),\n        ],\n\n        'cache' => [\n            'url' => env('REDIS_URL'),\n            'host' => env('REDIS_HOST', '127.0.0.1'),\n            'username' => env('REDIS_USERNAME'),\n            'password' => env('REDIS_PASSWORD'),\n            'port' => env('REDIS_PORT', '6379'),\n            'database' => env('REDIS_CACHE_DB', '1'),\n        ],\n\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/config/filesystems.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Filesystem Disk\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the default filesystem disk that should be used\n    | by the framework. The \"local\" disk, as well as a variety of cloud\n    | based disks are available to your application. Just store away!\n    |\n    */\n\n    'default' => env('FILESYSTEM_DISK', 'local'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Filesystem Disks\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure as many filesystem \"disks\" as you wish, and you\n    | may even configure multiple disks of the same driver. Defaults have\n    | been set up for each driver as an example of the required values.\n    |\n    | Supported Drivers: \"local\", \"ftp\", \"sftp\", \"s3\"\n    |\n    */\n\n    'disks' => [\n\n        'local' => [\n            'driver' => 'local',\n            'root' => storage_path('app'),\n            'throw' => false,\n        ],\n\n        'public' => [\n            'driver' => 'local',\n            'root' => storage_path('app/public'),\n            'url' => env('APP_URL').'/storage',\n            'visibility' => 'public',\n            'throw' => false,\n        ],\n\n        's3' => [\n            'driver' => 's3',\n            'key' => env('AWS_ACCESS_KEY_ID'),\n            'secret' => env('AWS_SECRET_ACCESS_KEY'),\n            'region' => env('AWS_DEFAULT_REGION'),\n            'bucket' => env('AWS_BUCKET'),\n            'url' => env('AWS_URL'),\n            'endpoint' => env('AWS_ENDPOINT'),\n            'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),\n            'throw' => false,\n        ],\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Symbolic Links\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure the symbolic links that will be created when the\n    | `storage:link` Artisan command is executed. The array keys should be\n    | the locations of the links and the values should be their targets.\n    |\n    */\n\n    'links' => [\n        public_path('storage') => storage_path('app/public'),\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/config/hashing.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Hash Driver\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default hash driver that will be used to hash\n    | passwords for your application. By default, the bcrypt algorithm is\n    | used; however, you remain free to modify this option if you wish.\n    |\n    | Supported: \"bcrypt\", \"argon\", \"argon2id\"\n    |\n    */\n\n    'driver' => 'bcrypt',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Bcrypt Options\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the configuration options that should be used when\n    | passwords are hashed using the Bcrypt algorithm. This will allow you\n    | to control the amount of time it takes to hash the given password.\n    |\n    */\n\n    'bcrypt' => [\n        'rounds' => env('BCRYPT_ROUNDS', 10),\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Argon Options\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the configuration options that should be used when\n    | passwords are hashed using the Argon algorithm. These will allow you\n    | to control the amount of time it takes to hash the given password.\n    |\n    */\n\n    'argon' => [\n        'memory' => 65536,\n        'threads' => 1,\n        'time' => 4,\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/config/inertia.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Server Side Rendering\n    |--------------------------------------------------------------------------\n    |\n    | These options configures if and how Inertia uses Server Side Rendering\n    | to pre-render the initial visits made to your application's pages.\n    |\n    | You can specify a custom SSR bundle path, or omit it to let Inertia\n    | try and automatically detect it for you.\n    |\n    | Do note that enabling these options will NOT automatically make SSR work,\n    | as a separate rendering service needs to be available. To learn more,\n    | please visit https://inertiajs.com/server-side-rendering\n    |\n    */\n\n    'ssr' => [\n\n        'enabled' => (bool) env('INERTIA_SSR_ENABLED', true),\n\n        'url' => env('INERTIA_SSR_URL', 'http://127.0.0.1:13714'),\n\n        'ensure_bundle_exists' => (bool) env('INERTIA_SSR_ENSURE_BUNDLE_EXISTS', true),\n\n        // 'bundle' => base_path('bootstrap/ssr/ssr.mjs'),\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Pages\n    |--------------------------------------------------------------------------\n    |\n    | Set `ensure_pages_exist` to true if you want to enforce that Inertia page\n    | components exist on disk when rendering a page. This is useful for\n    | catching missing or misnamed components.\n    |\n    | The `page_paths` and `page_extensions` options define where to look\n    | for page components and which file extensions to consider.\n    |\n    */\n\n    'ensure_pages_exist' => false,\n\n    'page_paths' => [\n\n        resource_path('js/Pages'),\n\n    ],\n\n    'page_extensions' => [\n\n        'js',\n        'jsx',\n        'svelte',\n        'ts',\n        'tsx',\n        'vue',\n\n    ],\n\n    'use_script_element_for_initial_page' => (bool) env('INERTIA_USE_SCRIPT_ELEMENT_FOR_INITIAL_PAGE', false),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Testing\n    |--------------------------------------------------------------------------\n    |\n    | The values described here are used to locate Inertia components on the\n    | filesystem. For instance, when using `assertInertia`, the assertion\n    | attempts to locate the component as a file relative to any of the\n    | paths AND with any of the extensions specified here.\n    |\n    | Note: In a future release, the `page_paths` and `page_extensions`\n    | options below will be removed. The root-level options above\n    | will be used for both application and testing purposes.\n    |\n    */\n\n    'testing' => [\n\n        'ensure_pages_exist' => true,\n\n        'page_paths' => [\n\n            resource_path('js/Pages'),\n\n        ],\n\n        'page_extensions' => [\n\n            'js',\n            'jsx',\n            'svelte',\n            'ts',\n            'tsx',\n            'vue',\n\n        ],\n\n    ],\n\n    'history' => [\n\n        'encrypt' => (bool) env('INERTIA_ENCRYPT_HISTORY', true),\n\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/config/logging.php",
    "content": "<?php\n\nuse Monolog\\Handler\\NullHandler;\nuse Monolog\\Handler\\StreamHandler;\nuse Monolog\\Handler\\SyslogUdpHandler;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Log Channel\n    |--------------------------------------------------------------------------\n    |\n    | This option defines the default log channel that gets used when writing\n    | messages to the logs. The name specified in this option should match\n    | one of the channels defined in the \"channels\" configuration array.\n    |\n    */\n\n    'default' => env('LOG_CHANNEL', 'stack'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Deprecations Log Channel\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the log channel that should be used to log warnings\n    | regarding deprecated PHP and library features. This allows you to get\n    | your application ready for upcoming major versions of dependencies.\n    |\n    */\n\n    'deprecations' => [\n        'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),\n        'trace' => false,\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Log Channels\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure the log channels for your application. Out of\n    | the box, Laravel uses the Monolog PHP logging library. This gives\n    | you a variety of powerful log handlers / formatters to utilize.\n    |\n    | Available Drivers: \"single\", \"daily\", \"slack\", \"syslog\",\n    |                    \"errorlog\", \"monolog\",\n    |                    \"custom\", \"stack\"\n    |\n    */\n\n    'channels' => [\n        'stack' => [\n            'driver' => 'stack',\n            'channels' => ['single'],\n            'ignore_exceptions' => false,\n        ],\n\n        'single' => [\n            'driver' => 'single',\n            'path' => storage_path('logs/laravel.log'),\n            'level' => env('LOG_LEVEL', 'debug'),\n        ],\n\n        'daily' => [\n            'driver' => 'daily',\n            'path' => storage_path('logs/laravel.log'),\n            'level' => env('LOG_LEVEL', 'debug'),\n            'days' => 14,\n        ],\n\n        'slack' => [\n            'driver' => 'slack',\n            'url' => env('LOG_SLACK_WEBHOOK_URL'),\n            'username' => 'Laravel Log',\n            'emoji' => ':boom:',\n            'level' => env('LOG_LEVEL', 'critical'),\n        ],\n\n        'papertrail' => [\n            'driver' => 'monolog',\n            'level' => env('LOG_LEVEL', 'debug'),\n            'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class),\n            'handler_with' => [\n                'host' => env('PAPERTRAIL_URL'),\n                'port' => env('PAPERTRAIL_PORT'),\n                'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),\n            ],\n        ],\n\n        'stderr' => [\n            'driver' => 'monolog',\n            'level' => env('LOG_LEVEL', 'debug'),\n            'handler' => StreamHandler::class,\n            'formatter' => env('LOG_STDERR_FORMATTER'),\n            'with' => [\n                'stream' => 'php://stderr',\n            ],\n        ],\n\n        'syslog' => [\n            'driver' => 'syslog',\n            'level' => env('LOG_LEVEL', 'debug'),\n        ],\n\n        'errorlog' => [\n            'driver' => 'errorlog',\n            'level' => env('LOG_LEVEL', 'debug'),\n        ],\n\n        'null' => [\n            'driver' => 'monolog',\n            'handler' => NullHandler::class,\n        ],\n\n        'emergency' => [\n            'path' => storage_path('logs/laravel.log'),\n        ],\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/config/mail.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Mailer\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default mailer that is used to send any email\n    | messages sent by your application. Alternative mailers may be setup\n    | and used as needed; however, this mailer will be used by default.\n    |\n    */\n\n    'default' => env('MAIL_MAILER', 'smtp'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Mailer Configurations\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure all of the mailers used by your application plus\n    | their respective settings. Several examples have been configured for\n    | you and you are free to add your own as your application requires.\n    |\n    | Laravel supports a variety of mail \"transport\" drivers to be used while\n    | sending an e-mail. You will specify which one you are using for your\n    | mailers below. You are free to add additional mailers as required.\n    |\n    | Supported: \"smtp\", \"sendmail\", \"mailgun\", \"ses\",\n    |            \"postmark\", \"log\", \"array\", \"failover\"\n    |\n    */\n\n    'mailers' => [\n        'smtp' => [\n            'transport' => 'smtp',\n            'host' => env('MAIL_HOST', 'smtp.mailgun.org'),\n            'port' => env('MAIL_PORT', 587),\n            'encryption' => env('MAIL_ENCRYPTION', 'tls'),\n            'username' => env('MAIL_USERNAME'),\n            'password' => env('MAIL_PASSWORD'),\n            'timeout' => null,\n            'local_domain' => env('MAIL_EHLO_DOMAIN'),\n        ],\n\n        'ses' => [\n            'transport' => 'ses',\n        ],\n\n        'mailgun' => [\n            'transport' => 'mailgun',\n        ],\n\n        'postmark' => [\n            'transport' => 'postmark',\n        ],\n\n        'sendmail' => [\n            'transport' => 'sendmail',\n            'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'),\n        ],\n\n        'log' => [\n            'transport' => 'log',\n            'channel' => env('MAIL_LOG_CHANNEL'),\n        ],\n\n        'array' => [\n            'transport' => 'array',\n        ],\n\n        'failover' => [\n            'transport' => 'failover',\n            'mailers' => [\n                'smtp',\n                'log',\n            ],\n        ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Global \"From\" Address\n    |--------------------------------------------------------------------------\n    |\n    | You may wish for all e-mails sent by your application to be sent from\n    | the same address. Here, you may specify a name and address that is\n    | used globally for all e-mails that are sent by your application.\n    |\n    */\n\n    'from' => [\n        'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),\n        'name' => env('MAIL_FROM_NAME', 'Example'),\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Markdown Mail Settings\n    |--------------------------------------------------------------------------\n    |\n    | If you are using Markdown based email rendering, you may configure your\n    | theme and component paths here, allowing you to customize the design\n    | of the emails. Or, you may simply stick with the Laravel defaults!\n    |\n    */\n\n    'markdown' => [\n        'theme' => 'default',\n\n        'paths' => [\n            resource_path('views/vendor/mail'),\n        ],\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/config/prism.php",
    "content": "<?php\n\nreturn [\n    'prism_server' => [\n        // The middleware that will be applied to the Prism Server routes.\n        'middleware' => [],\n        'enabled' => env('PRISM_SERVER_ENABLED', false),\n    ],\n    'providers' => [\n        'openai' => [\n            'url' => env('OPENAI_URL', 'https://api.openai.com/v1'),\n            'api_key' => env('OPENAI_API_KEY', ''),\n            'organization' => env('OPENAI_ORGANIZATION', null),\n            'project' => env('OPENAI_PROJECT', null),\n        ],\n        'anthropic' => [\n            'api_key' => env('ANTHROPIC_API_KEY', ''),\n            'version' => env('ANTHROPIC_API_VERSION', '2023-06-01'),\n            'default_thinking_budget' => env('ANTHROPIC_DEFAULT_THINKING_BUDGET', 1024),\n            // Include beta strings as a comma separated list.\n            'anthropic_beta' => env('ANTHROPIC_BETA', null),\n        ],\n        'ollama' => [\n            'url' => env('OLLAMA_URL', 'http://localhost:11434'),\n        ],\n        'mistral' => [\n            'api_key' => env('MISTRAL_API_KEY', ''),\n            'url' => env('MISTRAL_URL', 'https://api.mistral.ai/v1'),\n        ],\n        'groq' => [\n            'api_key' => env('GROQ_API_KEY', ''),\n            'url' => env('GROQ_URL', 'https://api.groq.com/openai/v1'),\n        ],\n        'xai' => [\n            'api_key' => env('XAI_API_KEY', ''),\n            'url' => env('XAI_URL', 'https://api.x.ai/v1'),\n        ],\n        'gemini' => [\n            'api_key' => env('GEMINI_API_KEY', ''),\n            'url' => env('GEMINI_URL', 'https://generativelanguage.googleapis.com/v1beta/models'),\n        ],\n        'deepseek' => [\n            'api_key' => env('DEEPSEEK_API_KEY', ''),\n            'url' => env('DEEPSEEK_URL', 'https://api.deepseek.com/v1'),\n        ],\n        'elevenlabs' => [\n            'api_key' => env('ELEVENLABS_API_KEY', ''),\n            'url' => env('ELEVENLABS_URL', 'https://api.elevenlabs.io/v1/'),\n        ],\n        'voyageai' => [\n            'api_key' => env('VOYAGEAI_API_KEY', ''),\n            'url' => env('VOYAGEAI_URL', 'https://api.voyageai.com/v1'),\n        ],\n        'openrouter' => [\n            'api_key' => env('OPENROUTER_API_KEY', ''),\n            'url' => env('OPENROUTER_URL', 'https://openrouter.ai/api/v1'),\n        ],\n    ],\n];\n"
  },
  {
    "path": "playgrounds/vue3/config/queue.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Queue Connection Name\n    |--------------------------------------------------------------------------\n    |\n    | Laravel's queue API supports an assortment of back-ends via a single\n    | API, giving you convenient access to each back-end using the same\n    | syntax for every one. Here you may define a default connection.\n    |\n    */\n\n    'default' => env('QUEUE_CONNECTION', 'sync'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Queue Connections\n    |--------------------------------------------------------------------------\n    |\n    | Here you may configure the connection information for each server that\n    | is used by your application. A default configuration has been added\n    | for each back-end shipped with Laravel. You are free to add more.\n    |\n    | Drivers: \"sync\", \"database\", \"beanstalkd\", \"sqs\", \"redis\", \"null\"\n    |\n    */\n\n    'connections' => [\n\n        'sync' => [\n            'driver' => 'sync',\n        ],\n\n        'database' => [\n            'driver' => 'database',\n            'table' => 'jobs',\n            'queue' => 'default',\n            'retry_after' => 90,\n            'after_commit' => false,\n        ],\n\n        'beanstalkd' => [\n            'driver' => 'beanstalkd',\n            'host' => 'localhost',\n            'queue' => 'default',\n            'retry_after' => 90,\n            'block_for' => 0,\n            'after_commit' => false,\n        ],\n\n        'sqs' => [\n            'driver' => 'sqs',\n            'key' => env('AWS_ACCESS_KEY_ID'),\n            'secret' => env('AWS_SECRET_ACCESS_KEY'),\n            'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),\n            'queue' => env('SQS_QUEUE', 'default'),\n            'suffix' => env('SQS_SUFFIX'),\n            'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),\n            'after_commit' => false,\n        ],\n\n        'redis' => [\n            'driver' => 'redis',\n            'connection' => 'default',\n            'queue' => env('REDIS_QUEUE', 'default'),\n            'retry_after' => 90,\n            'block_for' => null,\n            'after_commit' => false,\n        ],\n\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Failed Queue Jobs\n    |--------------------------------------------------------------------------\n    |\n    | These options configure the behavior of failed queue job logging so you\n    | can control which database and table are used to store the jobs that\n    | have failed. You may change them to any database / table you wish.\n    |\n    */\n\n    'failed' => [\n        'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),\n        'database' => env('DB_CONNECTION', 'mysql'),\n        'table' => 'failed_jobs',\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/config/sanctum.php",
    "content": "<?php\n\nuse Laravel\\Sanctum\\Sanctum;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Stateful Domains\n    |--------------------------------------------------------------------------\n    |\n    | Requests from the following domains / hosts will receive stateful API\n    | authentication cookies. Typically, these should include your local\n    | and production domains which access your API via a frontend SPA.\n    |\n    */\n\n    'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(\n        '%s%s',\n        'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',\n        Sanctum::currentApplicationUrlWithPort()\n    ))),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Sanctum Guards\n    |--------------------------------------------------------------------------\n    |\n    | This array contains the authentication guards that will be checked when\n    | Sanctum is trying to authenticate a request. If none of these guards\n    | are able to authenticate the request, Sanctum will use the bearer\n    | token that's present on an incoming request for authentication.\n    |\n    */\n\n    'guard' => ['web'],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Expiration Minutes\n    |--------------------------------------------------------------------------\n    |\n    | This value controls the number of minutes until an issued token will be\n    | considered expired. If this value is null, personal access tokens do\n    | not expire. This won't tweak the lifetime of first-party sessions.\n    |\n    */\n\n    'expiration' => null,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Sanctum Middleware\n    |--------------------------------------------------------------------------\n    |\n    | When authenticating your first-party SPA with Sanctum you may need to\n    | customize some of the middleware Sanctum uses while processing the\n    | request. You may change the middleware listed below as required.\n    |\n    */\n\n    'middleware' => [\n        'verify_csrf_token' => App\\Http\\Middleware\\VerifyCsrfToken::class,\n        'encrypt_cookies' => App\\Http\\Middleware\\EncryptCookies::class,\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/config/services.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Third Party Services\n    |--------------------------------------------------------------------------\n    |\n    | This file is for storing the credentials for third party services such\n    | as Mailgun, Postmark, AWS and more. This file provides the de facto\n    | location for this type of information, allowing packages to have\n    | a conventional file to locate the various service credentials.\n    |\n    */\n\n    'mailgun' => [\n        'domain' => env('MAILGUN_DOMAIN'),\n        'secret' => env('MAILGUN_SECRET'),\n        'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),\n        'scheme' => 'https',\n    ],\n\n    'postmark' => [\n        'token' => env('POSTMARK_TOKEN'),\n    ],\n\n    'ses' => [\n        'key' => env('AWS_ACCESS_KEY_ID'),\n        'secret' => env('AWS_SECRET_ACCESS_KEY'),\n        'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),\n    ],\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/config/session.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Str;\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Session Driver\n    |--------------------------------------------------------------------------\n    |\n    | This option controls the default session \"driver\" that will be used on\n    | requests. By default, we will use the lightweight native driver but\n    | you may specify any of the other wonderful drivers provided here.\n    |\n    | Supported: \"file\", \"cookie\", \"database\", \"apc\",\n    |            \"memcached\", \"redis\", \"dynamodb\", \"array\"\n    |\n    */\n\n    'driver' => env('SESSION_DRIVER', 'file'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Lifetime\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the number of minutes that you wish the session\n    | to be allowed to remain idle before it expires. If you want them\n    | to immediately expire on the browser closing, set that option.\n    |\n    */\n\n    'lifetime' => env('SESSION_LIFETIME', 120),\n\n    'expire_on_close' => false,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Encryption\n    |--------------------------------------------------------------------------\n    |\n    | This option allows you to easily specify that all of your session data\n    | should be encrypted before it is stored. All encryption will be run\n    | automatically by Laravel and you can use the Session like normal.\n    |\n    */\n\n    'encrypt' => false,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session File Location\n    |--------------------------------------------------------------------------\n    |\n    | When using the native session driver, we need a location where session\n    | files may be stored. A default has been set for you but a different\n    | location may be specified. This is only needed for file sessions.\n    |\n    */\n\n    'files' => storage_path('framework/sessions'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Database Connection\n    |--------------------------------------------------------------------------\n    |\n    | When using the \"database\" or \"redis\" session drivers, you may specify a\n    | connection that should be used to manage these sessions. This should\n    | correspond to a connection in your database configuration options.\n    |\n    */\n\n    'connection' => env('SESSION_CONNECTION'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Database Table\n    |--------------------------------------------------------------------------\n    |\n    | When using the \"database\" session driver, you may specify the table we\n    | should use to manage the sessions. Of course, a sensible default is\n    | provided for you; however, you are free to change this as needed.\n    |\n    */\n\n    'table' => 'sessions',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Cache Store\n    |--------------------------------------------------------------------------\n    |\n    | While using one of the framework's cache driven session backends you may\n    | list a cache store that should be used for these sessions. This value\n    | must match with one of the application's configured cache \"stores\".\n    |\n    | Affects: \"apc\", \"dynamodb\", \"memcached\", \"redis\"\n    |\n    */\n\n    'store' => env('SESSION_STORE'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Sweeping Lottery\n    |--------------------------------------------------------------------------\n    |\n    | Some session drivers must manually sweep their storage location to get\n    | rid of old sessions from storage. Here are the chances that it will\n    | happen on a given request. By default, the odds are 2 out of 100.\n    |\n    */\n\n    'lottery' => [2, 100],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Cookie Name\n    |--------------------------------------------------------------------------\n    |\n    | Here you may change the name of the cookie used to identify a session\n    | instance by ID. The name specified here will get used every time a\n    | new session cookie is created by the framework for every driver.\n    |\n    */\n\n    'cookie' => env(\n        'SESSION_COOKIE',\n        Str::slug(env('APP_NAME', 'laravel'), '_').'_session'\n    ),\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Cookie Path\n    |--------------------------------------------------------------------------\n    |\n    | The session cookie path determines the path for which the cookie will\n    | be regarded as available. Typically, this will be the root path of\n    | your application but you are free to change this when necessary.\n    |\n    */\n\n    'path' => '/',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Session Cookie Domain\n    |--------------------------------------------------------------------------\n    |\n    | Here you may change the domain of the cookie used to identify a session\n    | in your application. This will determine which domains the cookie is\n    | available to in your application. A sensible default has been set.\n    |\n    */\n\n    'domain' => env('SESSION_DOMAIN'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | HTTPS Only Cookies\n    |--------------------------------------------------------------------------\n    |\n    | By setting this option to true, session cookies will only be sent back\n    | to the server if the browser has a HTTPS connection. This will keep\n    | the cookie from being sent to you when it can't be done securely.\n    |\n    */\n\n    'secure' => env('SESSION_SECURE_COOKIE'),\n\n    /*\n    |--------------------------------------------------------------------------\n    | HTTP Access Only\n    |--------------------------------------------------------------------------\n    |\n    | Setting this value to true will prevent JavaScript from accessing the\n    | value of the cookie and the cookie will only be accessible through\n    | the HTTP protocol. You are free to modify this option if needed.\n    |\n    */\n\n    'http_only' => true,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Same-Site Cookies\n    |--------------------------------------------------------------------------\n    |\n    | This option determines how your cookies behave when cross-site requests\n    | take place, and can be used to mitigate CSRF attacks. By default, we\n    | will set this value to \"lax\" since this is a secure default value.\n    |\n    | Supported: \"lax\", \"strict\", \"none\", null\n    |\n    */\n\n    'same_site' => 'lax',\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/config/view.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | View Storage Paths\n    |--------------------------------------------------------------------------\n    |\n    | Most templating systems load templates from disk. Here you may specify\n    | an array of paths that should be checked for your views. Of course\n    | the usual Laravel view path has already been registered for you.\n    |\n    */\n\n    'paths' => [\n        resource_path('views'),\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Compiled View Path\n    |--------------------------------------------------------------------------\n    |\n    | This option determines where all the compiled Blade templates will be\n    | stored for your application. Typically, this is within the storage\n    | directory. However, as usual, you are free to change this value.\n    |\n    */\n\n    'compiled' => env(\n        'VIEW_COMPILED_PATH',\n        realpath(storage_path('framework/views'))\n    ),\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/database/.gitignore",
    "content": "*.sqlite*\n"
  },
  {
    "path": "playgrounds/vue3/database/factories/ChatMessageFactory.php",
    "content": "<?php\n\nnamespace Database\\Factories;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\n\n/**\n * @extends \\Illuminate\\Database\\Eloquent\\Factories\\Factory<\\App\\Models\\ChatMessage>\n */\nclass ChatMessageFactory extends Factory\n{\n    /**\n     * Define the model's default state.\n     *\n     * @return array<string, mixed>\n     */\n    public function definition(): array\n    {\n        return [\n            'type' => $this->faker->randomElement(['prompt', 'response']),\n            'content' => $this->faker->sentence,\n        ];\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/database/factories/UserFactory.php",
    "content": "<?php\n\nnamespace Database\\Factories;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\nuse Illuminate\\Support\\Str;\n\n/**\n * @extends \\Illuminate\\Database\\Eloquent\\Factories\\Factory<\\App\\Models\\User>\n */\nclass UserFactory extends Factory\n{\n    /**\n     * Define the model's default state.\n     *\n     * @return array<string, mixed>\n     */\n    public function definition()\n    {\n        return [\n            'name' => fake()->name(),\n            'email' => fake()->unique()->safeEmail(),\n            'email_verified_at' => now(),\n            'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password\n            'remember_token' => Str::random(10),\n        ];\n    }\n\n    /**\n     * Indicate that the model's email address should be unverified.\n     *\n     * @return static\n     */\n    public function unverified()\n    {\n        return $this->state(fn (array $attributes) => [\n            'email_verified_at' => null,\n        ]);\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/database/migrations/2014_10_12_000000_create_users_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('users', function (Blueprint $table) {\n            $table->id();\n            $table->string('name');\n            $table->string('email')->unique();\n            $table->timestamp('email_verified_at')->nullable();\n            $table->string('password');\n            $table->rememberToken();\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('users');\n    }\n};\n"
  },
  {
    "path": "playgrounds/vue3/database/migrations/2014_10_12_100000_create_password_resets_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('password_resets', function (Blueprint $table) {\n            $table->string('email')->index();\n            $table->string('token');\n            $table->timestamp('created_at')->nullable();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('password_resets');\n    }\n};\n"
  },
  {
    "path": "playgrounds/vue3/database/migrations/2019_08_19_000000_create_failed_jobs_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('failed_jobs', function (Blueprint $table) {\n            $table->id();\n            $table->string('uuid')->unique();\n            $table->text('connection');\n            $table->text('queue');\n            $table->longText('payload');\n            $table->longText('exception');\n            $table->timestamp('failed_at')->useCurrent();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('failed_jobs');\n    }\n};\n"
  },
  {
    "path": "playgrounds/vue3/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('personal_access_tokens', function (Blueprint $table) {\n            $table->id();\n            $table->morphs('tokenable');\n            $table->string('name');\n            $table->string('token', 64)->unique();\n            $table->text('abilities')->nullable();\n            $table->timestamp('last_used_at')->nullable();\n            $table->timestamp('expires_at')->nullable();\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('personal_access_tokens');\n    }\n};\n"
  },
  {
    "path": "playgrounds/vue3/database/migrations/2025_08_29_115526_create_chat_messages_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    /**\n     * Run the migrations.\n     */\n    public function up(): void\n    {\n        Schema::create('chat_messages', function (Blueprint $table) {\n            $table->id();\n            $table->string('type');\n            $table->text('content');\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     */\n    public function down(): void\n    {\n        Schema::dropIfExists('chat_messages');\n    }\n};\n"
  },
  {
    "path": "playgrounds/vue3/database/seeders/DatabaseSeeder.php",
    "content": "<?php\n\nnamespace Database\\Seeders;\n\n// use Illuminate\\Database\\Console\\Seeds\\WithoutModelEvents;\n\nuse App\\Models\\ChatMessage;\nuse Illuminate\\Database\\Seeder;\nuse Illuminate\\Support\\Facades\\File;\n\nclass DatabaseSeeder extends Seeder\n{\n    /**\n     * Seed the application's database.\n     *\n     * @return void\n     */\n    public function run()\n    {\n        collect(File::json(database_path('seeders/conversation.json')))\n            ->each(fn ($chatMessage) => ChatMessage::create($chatMessage));\n\n        // \\App\\Models\\User::factory(5000)->create();\n\n        // \\App\\Models\\User::factory()->create([\n        //     'name' => 'Test User',\n        //     'email' => 'test@example.com',\n        // ]);\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/database/seeders/conversation.json",
    "content": "[\n  {\n    \"type\": \"prompt\",\n    \"content\": \"Hey! Tell me about PHP\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Okay, let's talk about PHP (Hypertext Preprocessor). PHP is a widely-used, open-source scripting language primarily designed for web development. It\\u2019s known for its ease of use and large community support.  \\n\\nHere's a breakdown of key aspects:\\n\\n1.  **Server-Side Scripting:** PHP code runs on the web server, generating HTML that is sent to the user's browser.  This is different from client-side languages like JavaScript, which execute in the browser.\\n\\n2.  **Dynamic Content:** PHP excels at creating dynamic web pages. It can generate content based on user input, database queries, or other variables.\\n\\n   ```php\\n   <?php\\n   echo \\\"Hello, World!\\\"; \\/\\/ Prints \\\"Hello, World!\\\" to the browser.\\n   ?>\\n   ```\\n\\n3.  **Database Integration:** PHP has excellent support for connecting to and interacting with various databases like MySQL, PostgreSQL, and MongoDB.\\n\\n   ```php\\n   <?php\\n   $servername = \\\"localhost\\\";\\n   $username = \\\"your_username\\\";\\n   $password = \\\"your_password\\\";\\n   $dbname = \\\"your_database\\\";\\n\\n   \\/\\/ Create connection\\n   $conn = new mysqli($servername, $username, $password, $dbname);\\n\\n   \\/\\/ Check connection\\n   if ($conn->connect_error) {\\n     die(\\\"Connection failed: \\\" . $conn->connect_error);\\n   }\\n\\n   echo \\\"Connected to database successfully\\\";\\n   ?>\\n   ```\\n\\n4.  **Frameworks:** Popular PHP frameworks like Laravel, Symfony, and CodeIgniter provide structure and tools to streamline development.\\n\\n5.  **Usage:** PHP is used to build everything from simple websites and blogs to complex web applications, e-commerce platforms, and APIs. \\n\\n6.  **Evolution:** PHP has evolved significantly over the years, with modern versions (PHP 7.x and 8.x) offering improved performance and features.\\n\\nIn essence, PHP is a versatile and mature language that remains a significant force in web development.\\n\\n\\n\\nDo you want to know about a specific aspect of PHP, such as its syntax, frameworks, or usage examples?\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"What is Laravel?\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Laravel is a popular, open-source PHP framework designed for building web applications efficiently. It follows the Model-View-Controller (MVC) architectural pattern, promoting organized code and maintainability. Laravel provides a robust set of tools and features to simplify development.\\n\\nHere's a basic example:\\n\\n```php\\n<?php\\n\\/\\/ Example: A simple Laravel route\\nRoute::get('\\/', function () {\\n    return \\\"Hello, World!\\\";\\n});\\n?>\\n```\\n\\nKey features include:\\n\\n*   **Eloquent ORM:** For easy database interaction.\\n*   **Templating Engine (Blade):**  For creating dynamic HTML.\\n*   **Routing:** For mapping URLs to controller actions.\\n*   **Security Features:** Built-in protection against common vulnerabilities.\\n\\nLaravel\\u2019s ecosystem has a huge community and lots of packages, making it a solid choice for modern web development. Essentially, it\\u2019s a toolkit that accelerates the process of creating robust and scalable PHP applications.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"Eloquent sounds... very nice!\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Laravel is a popular PHP framework known for its elegant design and powerful features. It follows the MVC architectural pattern, promoting organized code. Eloquent, Laravel\\u2019s ORM (Object-Relational Mapper), simplifies database interactions \\u2013 like this: `$users = User::all();`. Laravel\\u2019s routing system, like `Route::get('\\/', function () { return \\\"Hello, World!\\\"; });`, connects URLs to your application\\u2019s logic. Blade, Laravel's templating engine, allows you to create dynamic HTML. Laravel includes built-in security features to protect your app. It\\u2019s a robust framework for building web applications quickly and efficiently.  Laravel\\u2019s large community provides plenty of support and resources.  It is a great choice for modern web development.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"I want to know more about Eloquent\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Eloquent is Laravel\\u2019s powerful ORM (Object-Relational Mapper), simplifying database interactions. It allows you to interact with your database using PHP objects instead of raw SQL.  \\n\\nFor example, `$users = User::all();` retrieves all users from your database. Eloquent models represent database tables, offering a cleaner and more object-oriented approach. It handles SQL queries automatically, making development faster and more maintainable. \\n\\nEloquent provides features like relationships (one-to-one, one-to-many, many-to-many) to model complex data connections. You can also use Eloquent to perform CRUD (Create, Read, Update, Delete) operations. \\n\\n```php\\n\\/\\/ Example: Retrieving a user by ID\\n$user = User::find(1);\\n```\\n\\nEloquent is a core component of Laravel, streamlining database access and improving development efficiency.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"Does it work with MySQL?\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Yes, Eloquent works seamlessly with MySQL. It\\u2019s Laravel\\u2019s primary ORM, designed for database interactions, and MySQL is a very common and well-supported database backend for Laravel applications. Eloquent models represent your MySQL tables, allowing you to retrieve, create, update, and delete data using PHP objects. For example, `$users = User::all();` fetches all records from the `users` table. You can define relationships between models, like one-to-many, to represent data connections. Eloquent simplifies database interactions significantly, reducing the need for raw SQL queries in many cases. It\\u2019s a robust and efficient way to manage your data within a Laravel application and MySQL.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"What other engins does it support?\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Based on our discussion, Eloquent primarily supports MySQL. While the context didn\\u2019t explicitly list all supported engines, Laravel\\u2019s ORM is designed for flexibility and can be used with other databases like PostgreSQL, MongoDB, and SQLite. For example, `$users = User::all();` works regardless of the database backend.  Eloquent\\u2019s core architecture allows for database abstraction, meaning you can change the underlying database without altering your application logic. The framework provides tools to manage connections and queries. Laravel\\u2019s flexibility makes it a powerful choice for diverse database environments.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"Ah, even SQLite! What's the difference between MySQL and MariaDB these days?\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Eloquent primarily supports MySQL and SQLite. Both are excellent choices for Laravel development. MySQL is a robust, widely-used relational database, while SQLite is a lightweight, file-based database \\u2013 perfect for smaller projects or development environments.  Eloquent works identically with both, simplifying database interactions.  There isn't a significant difference in functionality between MySQL and MariaDB that would impact Eloquent\\u2019s usage. MariaDB is a fork of MySQL, offering similar features and compatibility.  Eloquent\\u2019s abstraction layer handles the underlying differences, allowing you to focus on your application logic. Essentially, you can use Eloquent with either database without needing to adjust your code significantly.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"But outside of Laravel and Eloquent, why should I use MariaDB?\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Based on our conversation, Eloquent primarily supports MySQL and SQLite. MariaDB is a fork of MySQL, offering similar features. While Laravel\\u2019s Eloquent works with both, MariaDB\\u2019s primary advantage lies in its performance and open-source nature. It\\u2019s often faster than MySQL, especially for certain workloads. MariaDB\\u2019s open-source license provides greater flexibility and control compared to proprietary databases. For example, `$users = User::all();` would function identically with MariaDB as with MySQL. MariaDB\\u2019s community support is strong. It's a viable alternative if you\\u2019re seeking a robust, open-source database solution, offering similar functionality to MySQL.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"Ok, let's change topics. Tell me about Event Broadcasting in Laravel\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Laravel\\u2019s Event Broadcasting system allows decoupled communication between services and components. It uses events and listeners to trigger actions without direct dependencies.\\n\\nTo create an event, define a class extending `Illuminate\\\\Events\\\\DispatchableEvent`.  For example:\\n\\n```php\\n<?php\\n\\nnamespace App\\\\Events;\\n\\nuse Illuminate\\\\Broadcasting\\\\Channel;\\nuse Illuminate\\\\Contracts\\\\Broadcasting\\\\Broadcastable;\\n\\nclass UserRegistered implements Broadcastable\\n{\\n    public function __construct() {}\\n}\\n```\\n\\nThen, use `dispatch()` to trigger the event: `$event = new UserRegistered(); Event::dispatch($event);`\\n\\nListeners subscribe to events using `listen()` or `subscribe()` to receive and react to them.\\n\\n```php\\n<?php\\n\\nnamespace App\\\\Listeners;\\n\\nuse App\\\\Events\\\\UserRegistered;\\nuse Illuminate\\\\Contracts\\\\Events\\\\Listener;\\n\\nclass UserRegistrationListener implements Listener\\n{\\n    public function listen(UserRegistered $event)\\n    {\\n        \\/\\/ Handle the event here.\\n        echo \\\"User registered!\\\";\\n    }\\n}\\n```\\n\\nThis allows for flexible and scalable applications. Events promote loosely coupled architecture.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"Broadcastable? Really? Shouldn't that be ShouldBroadcast?\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"You're right to question that \\u2013 the context provided focuses on the core Event Broadcasting system. Laravel\\u2019s `Broadcastable` interface defines events that can be broadcast to channels. The `Broadcastable` interface is used for events meant to be sent to clients (like web browsers) using WebSockets.  It\\u2019s not directly tied to the channel itself.  To broadcast an event to a specific channel, you\\u2019d use `Event::dispatch($event, ['channel' => 'your_channel_name']);` The `Broadcastable` interface is essential for establishing the communication channel. For example: `$event = new UserRegistered(); Event::dispatch($event, ['channel' => 'channel_name']);` Laravel\\u2019s Event Broadcasting simplifies real-time communication by decoupling event publishers and subscribers.\"\n  },\n  {\n    \"type\": \"prompt\",\n    \"content\": \"Hmm you don't know a lot about this topic... let's talk about Inertia.js\"\n  },\n  {\n    \"type\": \"response\",\n    \"content\": \"Okay, let\\u2019s discuss Inertia.js. Inertia.js simplifies building modern Vue.js applications with Laravel. It allows you to serve Vue components from your Laravel backend, handling routing and authentication.\\n\\nTo use Inertia, you\\u2019d typically create a Vue component \\u2013 for instance, a `components\\/HelloWorld.vue` file. Then, you\\u2019d use Inertia to \\u201chydrate\\u201d this component on the server. \\n\\n```php\\nuse Inertia\\\\Payload;\\nuse Illuminate\\\\Support\\\\Facades\\\\Route;\\n\\nRoute::get('\\/hello', function () {\\n    $payload = new Payload([\\n        'message' => 'Hello from Inertia!'\\n    ]);\\n    return inertia('hello', $payload);\\n});\\n```\\n\\nThis sends the Vue component and its data to the browser. The browser renders the Vue component. Inertia manages the separation of concerns, streamlining your Laravel and Vue development workflow.\"\n  }\n]\n"
  },
  {
    "path": "playgrounds/vue3/init.sh",
    "content": "#!/bin/bash\nset -e\n\n# Install PHP dependencies via Composer\nif [ ! -d \"vendor\" ]; then\n    echo \"Installing PHP dependencies...\"\n    composer install\nelse\n    echo \"PHP dependencies already installed\"\nfi\n\n# Install Node.js dependencies via pnpm\nif [ ! -d \"node_modules\" ]; then\n    echo \"Installing Node.js dependencies...\"\n    pnpm install\nelse\n    echo \"Node.js dependencies already installed\"\nfi\n\n# Set up environment configuration\nif [ ! -f \".env\" ]; then\n    echo \"Creating environment configuration...\"\n    cp .env.example .env\n    php artisan key:generate\nelse\n    echo \"Environment configuration already exists\"\nfi\n\n# Set up SQLite database\nif [ ! -f \"database/database.sqlite\" ]; then\n    echo \"Creating SQLite database...\"\n    touch database/database.sqlite\n    echo \"Running fresh migrations with seed data...\"\n    php artisan migrate:fresh --seed\nelse\n    echo \"Database already exists\"\nfi\n\n# Ensure database is up to date\necho \"Running any pending migrations...\"\nphp artisan migrate\n"
  },
  {
    "path": "playgrounds/vue3/lang/en/auth.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Authentication Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines are used during authentication for various\n    | messages that we need to display to the user. You are free to modify\n    | these language lines according to your application's requirements.\n    |\n    */\n\n    'failed' => 'These credentials do not match our records.',\n    'password' => 'The provided password is incorrect.',\n    'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/lang/en/pagination.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Pagination Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines are used by the paginator library to build\n    | the simple pagination links. You are free to change them to anything\n    | you want to customize your views to better match your application.\n    |\n    */\n\n    'previous' => '&laquo; Previous',\n    'next' => 'Next &raquo;',\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/lang/en/passwords.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Password Reset Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines are the default lines which match reasons\n    | that are given by the password broker for a password update attempt\n    | has failed, such as for an invalid token or invalid new password.\n    |\n    */\n\n    'reset' => 'Your password has been reset!',\n    'sent' => 'We have emailed your password reset link!',\n    'throttled' => 'Please wait before retrying.',\n    'token' => 'This password reset token is invalid.',\n    'user' => \"We can't find a user with that email address.\",\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/lang/en/validation.php",
    "content": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Validation Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines contain the default error messages used by\n    | the validator class. Some of these rules have multiple versions such\n    | as the size rules. Feel free to tweak each of these messages here.\n    |\n    */\n\n    'accepted' => 'The :attribute must be accepted.',\n    'accepted_if' => 'The :attribute must be accepted when :other is :value.',\n    'active_url' => 'The :attribute is not a valid URL.',\n    'after' => 'The :attribute must be a date after :date.',\n    'after_or_equal' => 'The :attribute must be a date after or equal to :date.',\n    'alpha' => 'The :attribute must only contain letters.',\n    'alpha_dash' => 'The :attribute must only contain letters, numbers, dashes and underscores.',\n    'alpha_num' => 'The :attribute must only contain letters and numbers.',\n    'array' => 'The :attribute must be an array.',\n    'ascii' => 'The :attribute must only contain single-byte alphanumeric characters and symbols.',\n    'before' => 'The :attribute must be a date before :date.',\n    'before_or_equal' => 'The :attribute must be a date before or equal to :date.',\n    'between' => [\n        'array' => 'The :attribute must have between :min and :max items.',\n        'file' => 'The :attribute must be between :min and :max kilobytes.',\n        'numeric' => 'The :attribute must be between :min and :max.',\n        'string' => 'The :attribute must be between :min and :max characters.',\n    ],\n    'boolean' => 'The :attribute field must be true or false.',\n    'confirmed' => 'The :attribute confirmation does not match.',\n    'current_password' => 'The password is incorrect.',\n    'date' => 'The :attribute is not a valid date.',\n    'date_equals' => 'The :attribute must be a date equal to :date.',\n    'date_format' => 'The :attribute does not match the format :format.',\n    'decimal' => 'The :attribute must have :decimal decimal places.',\n    'declined' => 'The :attribute must be declined.',\n    'declined_if' => 'The :attribute must be declined when :other is :value.',\n    'different' => 'The :attribute and :other must be different.',\n    'digits' => 'The :attribute must be :digits digits.',\n    'digits_between' => 'The :attribute must be between :min and :max digits.',\n    'dimensions' => 'The :attribute has invalid image dimensions.',\n    'distinct' => 'The :attribute field has a duplicate value.',\n    'doesnt_end_with' => 'The :attribute may not end with one of the following: :values.',\n    'doesnt_start_with' => 'The :attribute may not start with one of the following: :values.',\n    'email' => 'The :attribute must be a valid email address.',\n    'ends_with' => 'The :attribute must end with one of the following: :values.',\n    'enum' => 'The selected :attribute is invalid.',\n    'exists' => 'The selected :attribute is invalid.',\n    'file' => 'The :attribute must be a file.',\n    'filled' => 'The :attribute field must have a value.',\n    'gt' => [\n        'array' => 'The :attribute must have more than :value items.',\n        'file' => 'The :attribute must be greater than :value kilobytes.',\n        'numeric' => 'The :attribute must be greater than :value.',\n        'string' => 'The :attribute must be greater than :value characters.',\n    ],\n    'gte' => [\n        'array' => 'The :attribute must have :value items or more.',\n        'file' => 'The :attribute must be greater than or equal to :value kilobytes.',\n        'numeric' => 'The :attribute must be greater than or equal to :value.',\n        'string' => 'The :attribute must be greater than or equal to :value characters.',\n    ],\n    'image' => 'The :attribute must be an image.',\n    'in' => 'The selected :attribute is invalid.',\n    'in_array' => 'The :attribute field does not exist in :other.',\n    'integer' => 'The :attribute must be an integer.',\n    'ip' => 'The :attribute must be a valid IP address.',\n    'ipv4' => 'The :attribute must be a valid IPv4 address.',\n    'ipv6' => 'The :attribute must be a valid IPv6 address.',\n    'json' => 'The :attribute must be a valid JSON string.',\n    'lowercase' => 'The :attribute must be lowercase.',\n    'lt' => [\n        'array' => 'The :attribute must have less than :value items.',\n        'file' => 'The :attribute must be less than :value kilobytes.',\n        'numeric' => 'The :attribute must be less than :value.',\n        'string' => 'The :attribute must be less than :value characters.',\n    ],\n    'lte' => [\n        'array' => 'The :attribute must not have more than :value items.',\n        'file' => 'The :attribute must be less than or equal to :value kilobytes.',\n        'numeric' => 'The :attribute must be less than or equal to :value.',\n        'string' => 'The :attribute must be less than or equal to :value characters.',\n    ],\n    'mac_address' => 'The :attribute must be a valid MAC address.',\n    'max' => [\n        'array' => 'The :attribute must not have more than :max items.',\n        'file' => 'The :attribute must not be greater than :max kilobytes.',\n        'numeric' => 'The :attribute must not be greater than :max.',\n        'string' => 'The :attribute must not be greater than :max characters.',\n    ],\n    'max_digits' => 'The :attribute must not have more than :max digits.',\n    'mimes' => 'The :attribute must be a file of type: :values.',\n    'mimetypes' => 'The :attribute must be a file of type: :values.',\n    'min' => [\n        'array' => 'The :attribute must have at least :min items.',\n        'file' => 'The :attribute must be at least :min kilobytes.',\n        'numeric' => 'The :attribute must be at least :min.',\n        'string' => 'The :attribute must be at least :min characters.',\n    ],\n    'min_digits' => 'The :attribute must have at least :min digits.',\n    'multiple_of' => 'The :attribute must be a multiple of :value.',\n    'not_in' => 'The selected :attribute is invalid.',\n    'not_regex' => 'The :attribute format is invalid.',\n    'numeric' => 'The :attribute must be a number.',\n    'password' => [\n        'letters' => 'The :attribute must contain at least one letter.',\n        'mixed' => 'The :attribute must contain at least one uppercase and one lowercase letter.',\n        'numbers' => 'The :attribute must contain at least one number.',\n        'symbols' => 'The :attribute must contain at least one symbol.',\n        'uncompromised' => 'The given :attribute has appeared in a data leak. Please choose a different :attribute.',\n    ],\n    'present' => 'The :attribute field must be present.',\n    'prohibited' => 'The :attribute field is prohibited.',\n    'prohibited_if' => 'The :attribute field is prohibited when :other is :value.',\n    'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.',\n    'prohibits' => 'The :attribute field prohibits :other from being present.',\n    'regex' => 'The :attribute format is invalid.',\n    'required' => 'The :attribute field is required.',\n    'required_array_keys' => 'The :attribute field must contain entries for: :values.',\n    'required_if' => 'The :attribute field is required when :other is :value.',\n    'required_if_accepted' => 'The :attribute field is required when :other is accepted.',\n    'required_unless' => 'The :attribute field is required unless :other is in :values.',\n    'required_with' => 'The :attribute field is required when :values is present.',\n    'required_with_all' => 'The :attribute field is required when :values are present.',\n    'required_without' => 'The :attribute field is required when :values is not present.',\n    'required_without_all' => 'The :attribute field is required when none of :values are present.',\n    'same' => 'The :attribute and :other must match.',\n    'size' => [\n        'array' => 'The :attribute must contain :size items.',\n        'file' => 'The :attribute must be :size kilobytes.',\n        'numeric' => 'The :attribute must be :size.',\n        'string' => 'The :attribute must be :size characters.',\n    ],\n    'starts_with' => 'The :attribute must start with one of the following: :values.',\n    'string' => 'The :attribute must be a string.',\n    'timezone' => 'The :attribute must be a valid timezone.',\n    'unique' => 'The :attribute has already been taken.',\n    'uploaded' => 'The :attribute failed to upload.',\n    'uppercase' => 'The :attribute must be uppercase.',\n    'url' => 'The :attribute must be a valid URL.',\n    'ulid' => 'The :attribute must be a valid ULID.',\n    'uuid' => 'The :attribute must be a valid UUID.',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Custom Validation Language Lines\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify custom validation messages for attributes using the\n    | convention \"attribute.rule\" to name the lines. This makes it quick to\n    | specify a specific custom language line for a given attribute rule.\n    |\n    */\n\n    'custom' => [\n        'attribute-name' => [\n            'rule-name' => 'custom-message',\n        ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Custom Validation Attributes\n    |--------------------------------------------------------------------------\n    |\n    | The following language lines are used to swap our attribute placeholder\n    | with something more reader friendly such as \"E-Mail Address\" instead\n    | of \"email\". This simply helps us make our message more expressive.\n    |\n    */\n\n    'attributes' => [],\n\n];\n"
  },
  {
    "path": "playgrounds/vue3/package.json",
    "content": "{\n  \"name\": \"@inertiajs/vue3-playground\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"vue-tsc && vite build && vite build --ssr\"\n  },\n  \"devDependencies\": {\n    \"@inertiajs/core\": \"workspace:*\",\n    \"@inertiajs/vue3\": \"workspace:*\",\n    \"@laravel/stream-vue\": \"^0.3.13\",\n    \"@tailwindcss/typography\": \"^0.5.19\",\n    \"@tailwindcss/vite\": \"^4.2.1\",\n    \"@vitejs/plugin-vue\": \"^6.0.4\",\n    \"@vue/server-renderer\": \"^3.5.29\",\n    \"autosize\": \"^6.0.1\",\n    \"axios\": \"^1.13.5\",\n    \"laravel-vite-plugin\": \"^2.1.0\",\n    \"lodash\": \"^4.17.23\",\n    \"marked\": \"^17.0.3\",\n    \"tailwindcss\": \"^4.2.1\",\n    \"typescript\": \"^5.9.3\",\n    \"vite\": \"^7.3.1\",\n    \"vue\": \"^3.5.29\",\n    \"vue-tsc\": \"^3.2.5\"\n  },\n  \"type\": \"module\"\n}\n"
  },
  {
    "path": "playgrounds/vue3/phpunit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:noNamespaceSchemaLocation=\"./vendor/phpunit/phpunit/phpunit.xsd\"\n         bootstrap=\"vendor/autoload.php\"\n         colors=\"true\"\n>\n    <testsuites>\n        <testsuite name=\"Unit\">\n            <directory suffix=\"Test.php\">./tests/Unit</directory>\n        </testsuite>\n        <testsuite name=\"Feature\">\n            <directory suffix=\"Test.php\">./tests/Feature</directory>\n        </testsuite>\n    </testsuites>\n    <coverage processUncoveredFiles=\"true\">\n        <include>\n            <directory suffix=\".php\">./app</directory>\n        </include>\n    </coverage>\n    <php>\n        <env name=\"APP_ENV\" value=\"testing\"/>\n        <env name=\"BCRYPT_ROUNDS\" value=\"4\"/>\n        <env name=\"CACHE_DRIVER\" value=\"array\"/>\n        <!-- <env name=\"DB_CONNECTION\" value=\"sqlite\"/> -->\n        <!-- <env name=\"DB_DATABASE\" value=\":memory:\"/> -->\n        <env name=\"MAIL_MAILER\" value=\"array\"/>\n        <env name=\"QUEUE_CONNECTION\" value=\"sync\"/>\n        <env name=\"SESSION_DRIVER\" value=\"array\"/>\n        <env name=\"TELESCOPE_ENABLED\" value=\"false\"/>\n    </php>\n</phpunit>\n"
  },
  {
    "path": "playgrounds/vue3/public/.htaccess",
    "content": "<IfModule mod_rewrite.c>\n    <IfModule mod_negotiation.c>\n        Options -MultiViews -Indexes\n    </IfModule>\n\n    RewriteEngine On\n\n    # Handle Authorization Header\n    RewriteCond %{HTTP:Authorization} .\n    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]\n\n    # Redirect Trailing Slashes If Not A Folder...\n    RewriteCond %{REQUEST_FILENAME} !-d\n    RewriteCond %{REQUEST_URI} (.+)/$\n    RewriteRule ^ %1 [L,R=301]\n\n    # Send Requests To Front Controller...\n    RewriteCond %{REQUEST_FILENAME} !-d\n    RewriteCond %{REQUEST_FILENAME} !-f\n    RewriteRule ^ index.php [L]\n</IfModule>\n"
  },
  {
    "path": "playgrounds/vue3/public/index.php",
    "content": "<?php\n\nuse Illuminate\\Contracts\\Http\\Kernel;\nuse Illuminate\\Http\\Request;\n\ndefine('LARAVEL_START', microtime(true));\n\n/*\n|--------------------------------------------------------------------------\n| Check If The Application Is Under Maintenance\n|--------------------------------------------------------------------------\n|\n| If the application is in maintenance / demo mode via the \"down\" command\n| we will load this file so that any pre-rendered content can be shown\n| instead of starting the framework, which could cause an exception.\n|\n*/\n\nif (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {\n    require $maintenance;\n}\n\n/*\n|--------------------------------------------------------------------------\n| Register The Auto Loader\n|--------------------------------------------------------------------------\n|\n| Composer provides a convenient, automatically generated class loader for\n| this application. We just need to utilize it! We'll simply require it\n| into the script here so we don't need to manually load our classes.\n|\n*/\n\nrequire __DIR__.'/../vendor/autoload.php';\n\n/*\n|--------------------------------------------------------------------------\n| Run The Application\n|--------------------------------------------------------------------------\n|\n| Once we have the application, we can handle the incoming request using\n| the application's HTTP kernel. Then, we will send the response back\n| to this client's browser, allowing them to enjoy our application.\n|\n*/\n\n$app = require_once __DIR__.'/../bootstrap/app.php';\n\n$kernel = $app->make(Kernel::class);\n\n$response = $kernel->handle(\n    $request = Request::capture()\n)->send();\n\n$kernel->terminate($request, $response);\n"
  },
  {
    "path": "playgrounds/vue3/public/robots.txt",
    "content": "User-agent: *\nDisallow:\n"
  },
  {
    "path": "playgrounds/vue3/resources/css/app.css",
    "content": "@import 'tailwindcss';\n@plugin '@tailwindcss/typography';\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Components/Image.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\n\ndefineProps<{\n  id: number\n  url: string\n}>()\n\nconst loaded = ref(false)\n</script>\n\n<template>\n  <div class=\"relative aspect-square overflow-hidden rounded-lg bg-gray-200\">\n    <div v-if=\"!loaded\" class=\"absolute inset-0 animate-pulse bg-gray-300\" aria-hidden=\"true\" />\n\n    <img\n      :src=\"url\"\n      loading=\"lazy\"\n      decoding=\"async\"\n      class=\"h-full w-full object-cover transition duration-500 ease-out\"\n      :class=\"{\n        'blur-0 scale-100 opacity-100': loaded,\n        'scale-105 opacity-0 blur-sm': !loaded,\n      }\"\n      @load=\"loaded = true\"\n    />\n\n    <span class=\"pointer-events-none absolute bottom-2 left-2 rounded bg-black/50 px-2 py-1 text-sm text-white\">\n      {{ id }}\n    </span>\n  </div>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Components/Layout.vue",
    "content": "<script setup lang=\"ts\">\nimport { Link, usePage } from '@inertiajs/vue3'\nimport { computed } from 'vue'\n\nconst props = withDefaults(\n  defineProps<{\n    padding?: boolean\n  }>(),\n  {\n    padding: true,\n  },\n)\n\nconst page = usePage()\n\nconst appName = computed(() => page.props.appName)\n</script>\n\n<template>\n  <nav class=\"flex items-center space-x-6 bg-slate-800 px-10 py-6 text-white\">\n    <div class=\"rounded-lg bg-slate-700 px-4 py-1\">{{ appName }}</div>\n    <Link href=\"/\" class=\"hover:underline\" prefetch>Home</Link>\n    <Link href=\"/users\" class=\"hover:underline\" prefetch :cache-for=\"['2s', '1m']\">Users</Link>\n    <Link href=\"/article\" class=\"hover:underline\" prefetch=\"click\">Article</Link>\n    <Link href=\"/form\" class=\"hover:underline\" :prefetch=\"['mount', 'click']\" cache-for=\"1m\">useForm</Link>\n    <Link href=\"/form-component\" class=\"hover:underline\">{{ '<' + 'Form' + '>' }}</Link>\n    <Link href=\"/form-component/precognition\" class=\"hover:underline\">Precognition</Link>\n    <Link href=\"/logout\" method=\"post\" class=\"hover:underline\">Logout</Link>\n    <Link href=\"/goodbye\" class=\"hover:underline\">External</Link>\n    <Link href=\"/async\" class=\"hover:underline\">Async</Link>\n    <Link href=\"/defer\" class=\"hover:underline\">Defer</Link>\n    <Link href=\"/poll\" class=\"hover:underline\">Poll</Link>\n    <Link href=\"/chat\" class=\"hover:underline\">Chat</Link>\n    <Link href=\"/photo-grid\" class=\"hover:underline\">Photo Grid</Link>\n    <Link href=\"/photo-grid/horizontal\" class=\"hover:underline\">Photo Row</Link>\n    <Link href=\"/data-table\" class=\"hover:underline\">Table</Link>\n    <Link href=\"/once/1\" class=\"hover:underline\">Once</Link>\n    <Link href=\"/flash\" class=\"hover:underline\">Flash</Link>\n  </nav>\n  <main :class=\"padding ? 'px-10 py-8' : ''\">\n    <slot />\n  </main>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Components/Message.vue",
    "content": "<script setup lang=\"ts\">\nimport { marked } from 'marked'\nimport { computed } from 'vue'\n\nexport type Message = {\n  id: number | 'pending'\n  type: 'prompt' | 'response'\n  content: string\n}\n\nconst props = defineProps<{\n  message: Message\n}>()\n\nconst htmlContent = computed(() => marked(props.message.content))\n</script>\n\n<template>\n  <div\n    class=\"flex w-full\"\n    :class=\"{\n      'ml-auto justify-end': message.type === 'prompt',\n      'mr-auto justify-start': message.type === 'response',\n    }\"\n  >\n    <div class=\"flex max-w-[80%] items-start\">\n      <div\n        v-html=\"htmlContent\"\n        class=\"prose min-w-0 flex-1 text-[15px] leading-relaxed\"\n        :class=\"{\n          'rounded-xl bg-gray-800 px-4 py-2 text-white': message.type === 'prompt',\n          'text-gray-800': message.type === 'response',\n        }\"\n      />\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Components/PaperAirplaneIcon.vue",
    "content": "<template>\n  <svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    fill=\"none\"\n    viewBox=\"0 0 24 24\"\n    stroke-width=\"1.5\"\n    stroke=\"currentColor\"\n    class=\"size-6\"\n  >\n    <path\n      stroke-linecap=\"round\"\n      stroke-linejoin=\"round\"\n      d=\"M6 12 3.269 3.125A59.769 59.769 0 0 1 21.485 12 59.768 59.768 0 0 1 3.27 20.875L5.999 12Zm0 0h7.5\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Components/PhotoIcon.vue",
    "content": "<template>\n  <svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    fill=\"none\"\n    viewBox=\"0 0 24 24\"\n    stroke-width=\"1.5\"\n    stroke=\"currentColor\"\n    class=\"size-6\"\n  >\n    <path\n      stroke-linecap=\"round\"\n      stroke-linejoin=\"round\"\n      d=\"m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 0 0 1.5-1.5V6a1.5 1.5 0 0 0-1.5-1.5H3.75A1.5 1.5 0 0 0 2.25 6v12a1.5 1.5 0 0 0 1.5 1.5Zm10.5-11.25h.008v.008h-.008V8.25Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Components/Spinner.vue",
    "content": "<template>\n  <svg class=\"animate-spin text-black\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n    <circle class=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n    <path\n      class=\"opacity-75\"\n      fill=\"currentColor\"\n      d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n    ></path>\n  </svg>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Components/StreamingIndicator.vue",
    "content": "<template>\n  <div class=\"flex justify-start\">\n    <div class=\"mr-auto flex max-w-[80%] items-start\">\n      <div class=\"min-w-0 flex-1\">\n        <div class=\"py-2 text-[15px] leading-relaxed text-gray-800\">\n          <div class=\"flex items-center space-x-2\">\n            <div class=\"flex space-x-1\">\n              <div class=\"h-2 w-2 animate-bounce rounded-full bg-gray-500\"></div>\n              <div class=\"h-2 w-2 animate-bounce rounded-full bg-gray-500\" style=\"animation-delay: 0.1s\"></div>\n              <div class=\"h-2 w-2 animate-bounce rounded-full bg-gray-500\" style=\"animation-delay: 0.2s\"></div>\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Components/TestGrid.vue",
    "content": "<template>\n  <div class=\"mt-6 grid grid-cols-3 gap-4\"><slot /></div>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Components/TestGridItem.vue",
    "content": "<template>\n  <div class=\"rounded-sm border border-gray-300 p-4 text-sm text-gray-500\">\n    <div class=\"mb-2 font-bold\" v-if=\"$slots.title\">\n      <slot name=\"title\" />\n    </div>\n\n    <slot />\n  </div>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Components/Textarea.vue",
    "content": "<script setup lang=\"ts\">\nimport autosize from 'autosize'\nimport { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'\n\nconst modelValue = defineModel<string>()\nconst textareaRef = ref<HTMLTextAreaElement | null>(null)\n\nonMounted(() => autosize(textareaRef.value!))\nwatch(modelValue, () => nextTick(() => autosize.update(textareaRef.value!)))\nonBeforeUnmount(() => autosize.destroy(textareaRef.value!))\n</script>\n\n<template>\n  <textarea\n    rows=\"1\"\n    ref=\"textareaRef\"\n    v-model=\"modelValue\"\n    class=\"block w-full resize-none border-0 bg-transparent py-1 text-[16px] text-gray-900 placeholder-gray-500 outline-none\"\n  ></textarea>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/Article.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '../Components/Layout.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <Head title=\"Article\" />\n  <h1 class=\"text-3xl\">Article</h1>\n  <article class=\"max-w-3xl\">\n    <p class=\"my-6\">\n      Sunt culpa sit sunt enim aliquip. Esse ea ea quis voluptate. Enim consectetur aliqua ex ex magna cupidatat id\n      minim sit elit. Amet pariatur occaecat pariatur duis eiusmod dolore magna. Et commodo cupidatat in commodo elit\n      cupidatat minim qui id non enim ad. Culpa aliquip ad Lorem sit consectetur ullamco culpa duis nisi et fugiat\n      mollit eiusmod. Laboris voluptate veniam consequat proident in nulla irure velit.\n    </p>\n    <p class=\"my-6\">\n      Sit sint laboris sunt eiusmod ipsum laborum eiusmod amet commodo exercitation in duis magna. Proident sunt minim\n      in elit qui. Id pariatur commodo fugiat excepteur in deserunt Lorem ipsum occaecat est. Excepteur sit tempor ipsum\n      ex officia veniam enim amet velit fugiat mollit cillum. Incididunt aliqua nulla id occaecat nulla. Non ea ad est\n      occaecat deserunt officia qui commodo exercitation.\n    </p>\n    <p class=\"my-6\">\n      Voluptate laborum quis aliqua ullamco magna amet ullamco laborum qui cillum eu. Dolore dolore aliqua proident\n      proident sunt ipsum in. Enim velit dolore labore dolor quis incididunt duis culpa Lorem. Eu adipisicing non elit\n      fugiat voluptate labore ipsum dolore consectetur commodo. Et in et cillum duis consequat quis ex eu commodo.\n      Eiusmod aliqua excepteur consectetur eiusmod aute et consectetur sit pariatur dolore qui officia pariatur.\n    </p>\n    <p class=\"my-6\">\n      Non sunt eu mollit qui reprehenderit. Aute culpa anim voluptate do in esse duis laborum ad dolore. Ullamco nisi in\n      nostrud officia do. Duis pariatur officia id duis. Deserunt ad incididunt est sint consectetur reprehenderit\n      mollit est Lorem ea pariatur anim dolor adipisicing. Nostrud irure magna nostrud laboris aute sunt veniam laboris\n      veniam incididunt sit. Nulla proident ad aliqua fugiat culpa sunt est in dolor velit ad irure nulla.\n    </p>\n    <p class=\"my-6\">\n      Do aute laborum deserunt non laborum voluptate voluptate. Anim ut laborum magna sunt cupidatat irure. Cupidatat\n      fugiat minim sint cillum laborum excepteur irure id est irure ad occaecat adipisicing enim. Deserunt nulla anim\n      proident velit irure nostrud est est reprehenderit consequat pariatur qui. Fugiat Lorem sint eu laborum minim\n      pariatur cillum mollit nulla consequat ullamco ex. Ex consectetur ad ut irure fugiat occaecat aliqua exercitation\n      cillum ipsum anim dolore tempor.\n    </p>\n    <p class=\"my-6\">\n      Adipisicing consequat irure fugiat Lorem deserunt aliquip do cupidatat. Lorem labore elit ex qui nostrud qui\n      cillum sunt adipisicing occaecat. Sunt nostrud amet amet cupidatat fugiat Lorem quis nulla id cillum esse eu.\n      Ullamco aliqua dolore irure amet mollit anim velit dolore.\n    </p>\n    <p class=\"my-6\">\n      Veniam cupidatat ipsum ea officia ipsum nisi laborum culpa qui dolore. Aliqua Lorem nisi labore ea velit aliquip\n      irure excepteur eu. Laboris proident duis non labore sunt quis aute tempor laboris enim anim eiusmod.\n    </p>\n    <p class=\"my-6\">\n      Minim proident ut aliqua ea ut culpa fugiat ullamco nisi esse nostrud reprehenderit id. Id id ullamco velit anim\n      nisi magna Lorem tempor. Et veniam occaecat ut labore consequat fugiat duis.\n    </p>\n    <p class=\"my-6\">\n      Adipisicing ea consectetur adipisicing aute eu pariatur enim labore consequat occaecat consectetur minim nisi.\n      Cillum commodo sunt labore reprehenderit. Duis esse excepteur magna tempor eiusmod exercitation Lorem\n      reprehenderit excepteur pariatur. Esse cupidatat occaecat magna do aliquip Lorem. Consectetur adipisicing\n      consequat dolore nostrud esse eu cillum id commodo duis. Aliquip dolor cillum cupidatat fugiat.\n    </p>\n    <h2 id=\"far-down\" class=\"mt-8 text-2xl\">Far down</h2>\n    <p class=\"my-6\">\n      Ex eiusmod id est laborum sunt ex ea aute adipisicing ad magna deserunt duis. Nostrud velit dolore id commodo quis\n      enim fugiat. Sint non quis consectetur voluptate aliqua dolore ad voluptate nulla. Irure sit reprehenderit sint\n      laboris non elit. Duis minim nisi esse dolor. Sit ex in consequat non occaecat commodo irure et. Commodo qui ipsum\n      Lorem magna consequat consequat et minim eiusmod Lorem eiusmod cupidatat voluptate.\n    </p>\n  </article>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/Async.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '../Components/Layout.vue'\nimport TestGrid from '../Components/TestGrid.vue'\nimport TestGridItem from '../Components/TestGridItem.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head, router, useForm } from '@inertiajs/vue3'\nimport { ref, watch } from 'vue'\n\nconst reloadCount = ref(0)\n\nconst props = defineProps<{\n  jonathan: boolean\n  taylor: boolean\n  joe: boolean\n}>()\n\nconst form = useForm({\n  jonathan: props.jonathan,\n  taylor: props.taylor,\n  joe: props.joe,\n})\n\nwatch(form, () => {\n  router.post(\n    '/async/checkbox',\n    {\n      jonathan: form.jonathan,\n      taylor: form.taylor,\n      joe: form.joe,\n    },\n    {\n      async: true,\n    },\n  )\n})\n\nconst simulateConflict = () => {\n  router.reload({\n    only: ['sleep'],\n  })\n  router.visit('/sleepy/2')\n}\n\nconst triggerVisitThenReload = () => {\n  router.visit('/sleepy/1')\n  router.reload({\n    only: ['sleep'],\n  })\n}\n\nconst triggerLongReload = () => {\n  router.reload({\n    only: ['sleep'],\n    onFinish() {\n      console.log('finished reload')\n      reloadCount.value++\n      console.log('incremented reload count')\n    },\n  })\n}\n\nconst triggerCancel = () => {\n  router.post(\n    '/sleepy/3',\n    {},\n    {\n      onCancelToken: (token) => {\n        console.log('onCancelToken')\n\n        setTimeout(() => {\n          console.log('CANCELLING!')\n          token.cancel()\n        }, 1000)\n      },\n    },\n  )\n}\n\nconst triggerCancelAfterFinish = () => {\n  let cancelToken\n\n  router.post(\n    '/sleepy/1',\n    {},\n    {\n      onCancelToken: (token) => {\n        console.log('onCancelToken')\n\n        cancelToken = token\n      },\n      onFinish: () => {\n        console.log('onFinish')\n        console.log('CANCELLING!')\n        cancelToken.cancel()\n      },\n    },\n  )\n}\n\nwatch(reloadCount, () => {\n  console.log('watched reload count value', reloadCount.value)\n})\n</script>\n\n<template>\n  <Head title=\"Async Request\" />\n  <h1 class=\"text-3xl\">Async Request</h1>\n  <p class=\"mt-6\">Reload Count: {{ reloadCount }}</p>\n  <TestGrid>\n    <TestGridItem class=\"space-y-4\">\n      <p>Trigger an async reload that takes a moment and immediately programatically visit another page</p>\n      <button @click=\"simulateConflict\" class=\"rounded-sm bg-green-600 px-4 py-2 text-white\">Reload → Visit</button>\n    </TestGridItem>\n\n    <TestGridItem class=\"space-y-4\">\n      <div>\n        <label class=\"block\">\n          <input v-model=\"form.jonathan\" type=\"checkbox\" class=\"mr-2\" />\n          Jonathan\n        </label>\n        <label class=\"block\">\n          <input v-model=\"form.taylor\" type=\"checkbox\" class=\"mr-2\" />\n          Taylor\n        </label>\n        <label class=\"block\">\n          <input v-model=\"form.joe\" type=\"checkbox\" class=\"mr-2\" />\n          Joe\n        </label>\n      </div>\n      <p>You can check these on and off and then navigate to another page and the requests should still complete.</p>\n      <p>Toggling \"Joe\" on will cause a redirect to \"Article\", simulating an authorized action e.g.</p>\n    </TestGridItem>\n\n    <TestGridItem class=\"space-y-4\">\n      <p>Trigger programatic visit and an async reload one after another</p>\n\n      <p>Reload should still happen but won't re-direct back to the reloaded component, we should respect the visit</p>\n\n      <button @click=\"triggerVisitThenReload\" class=\"rounded-sm bg-green-600 px-4 py-2 text-white\">\n        Visit → Reload\n      </button>\n    </TestGridItem>\n\n    <TestGridItem class=\"space-y-4\">\n      <p>Simply trigger a 4 second reload so you can navigate or do whatever you'd like during it.</p>\n      <button @click=\"triggerLongReload\" class=\"rounded-sm bg-green-600 px-4 py-2 text-white\">\n        Trigger Long Reload\n      </button>\n    </TestGridItem>\n\n    <TestGridItem class=\"space-y-4\">\n      <p>Trigger an automatic cancellation from the token.</p>\n      <button @click=\"triggerCancel\" class=\"rounded-sm bg-green-600 px-4 py-2 text-white\">Trigger Cancel</button>\n    </TestGridItem>\n\n    <TestGridItem class=\"space-y-4\">\n      <p>Trigger an automatic cancellation from the token after finishing request.</p>\n      <button @click=\"triggerCancelAfterFinish\" class=\"rounded-sm bg-green-600 px-4 py-2 text-white\">\n        Trigger Cancel After Finish\n      </button>\n    </TestGridItem>\n  </TestGrid>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/Chat.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '../Components/Layout.vue'\nexport default { layout: (h, page) => h(Layout, { padding: false }, () => page) }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head, InfiniteScroll, router } from '@inertiajs/vue3'\nimport { useStream } from '@laravel/stream-vue'\nimport { computed, ref } from 'vue'\nimport { type Message, default as MessageComponent } from '../Components/Message.vue'\nimport PaperAirplaneIcon from '../Components/PaperAirplaneIcon.vue'\nimport Spinner from '../Components/Spinner.vue'\nimport StreamingIndicator from '../Components/StreamingIndicator.vue'\nimport Textarea from '../Components/Textarea.vue'\n\nconst props = defineProps<{\n  messages: {\n    data: Message[]\n  }\n}>()\n\nconst newPrompt = ref<string>('')\nconst pendingResponse = ref<string>('')\nconst requestCount = ref<number>(0)\nconst scrollContainer = ref<HTMLElement | null>(null)\n\nconst { isFetching, isStreaming, send } = useStream('messages', {\n  csrfToken: document.querySelector('meta[name=\"csrf-token\"]')?.getAttribute('content') as string,\n  onData: (data) => (pendingResponse.value += data),\n  onFinish: () => {\n    router.prependToProp('messages.data', {\n      id: Date.now(),\n      content: pendingResponse.value,\n      type: 'response',\n    })\n\n    pendingResponse.value = ''\n  },\n})\n\nconst canSendPrompt = computed(() => !!newPrompt.value.trim() && !isFetching.value && !isStreaming.value)\n\nconst sendMessage = () => {\n  if (!canSendPrompt.value) {\n    return\n  }\n\n  requestCount.value += 1\n\n  router.prependToProp(\n    'messages.data',\n    {\n      id: Date.now(),\n      content: newPrompt.value,\n      type: 'prompt',\n    },\n    {\n      onSuccess: () => {\n        scrollContainer.value?.scrollTo({ top: scrollContainer.value.scrollHeight, behavior: 'smooth' })\n\n        send({ message: newPrompt.value })\n\n        newPrompt.value = ''\n      },\n    },\n  )\n}\n\nconst reversedMessages = computed(() => {\n  const messages = props.messages.data.toReversed()\n\n  if (pendingResponse.value) {\n    // Append the pending response to the end of the reversed messages\n    // until the stream is finished and the message is added properly\n    messages.push({\n      id: 'pending',\n      content: pendingResponse.value,\n      type: 'response',\n    })\n  }\n\n  return messages\n})\n\nconst isLastMessage = (message: Message) => {\n  return message === reversedMessages.value[reversedMessages.value.length - 1]\n}\n</script>\n\n<template>\n  <Head title=\"Chat\" />\n\n  <div class=\"relative flex h-[calc(100vh-80px)] flex-col bg-gray-50\">\n    <div ref=\"scrollContainer\" class=\"h-full flex-1 overflow-y-auto\">\n      <InfiniteScroll reverse data=\"messages\" class=\"mx-auto grid max-w-3xl gap-6 px-8 py-16\">\n        <div\n          v-for=\"message in reversedMessages\"\n          :key=\"message.id\"\n          :class=\"{\n            'min-h-[calc(100vh-80px-131px-64px)]': isLastMessage(message) && requestCount > 0,\n          }\"\n        >\n          <MessageComponent :message />\n          <StreamingIndicator class=\"mt-6\" v-if=\"isLastMessage(message) && isFetching\" />\n        </div>\n\n        <template #loading=\"{ loadingNext }\">\n          <div class=\"flex justify-center\" :class=\"loadingNext ? 'pt-16' : 'pb-16'\">\n            <Spinner class=\"size-6 text-gray-400\" />\n          </div>\n        </template>\n      </InfiniteScroll>\n    </div>\n\n    <div class=\"sticky bottom-0 border-t border-gray-200 bg-white px-8 py-6\">\n      <form\n        @submit.prevent=\"sendMessage\"\n        class=\"relative mx-auto flex max-w-3xl items-end rounded-xl border border-gray-300 bg-white px-4 py-3 shadow-sm transition-colors focus-within:border-gray-400\"\n      >\n        <Textarea\n          v-model=\"newPrompt\"\n          placeholder=\"Type your message...\"\n          @keydown.enter.exact.prevent=\"sendMessage\"\n          @keydown.enter.shift.exact.prevent=\"newPrompt += '\\n'\"\n        />\n\n        <button\n          type=\"submit\"\n          :disabled=\"!canSendPrompt\"\n          class=\"ml-3 flex size-8 items-center justify-center rounded-lg bg-gray-800 disabled:cursor-not-allowed disabled:opacity-50\"\n        >\n          <Spinner v-if=\"isFetching || isStreaming\" class=\"size-4 text-white\" />\n          <PaperAirplaneIcon class=\"size-4 rotate-270 text-white\" v-else />\n        </button>\n      </form>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/DataTable.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '../Components/Layout.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head, InfiniteScroll } from '@inertiajs/vue3'\nimport Spinner from '../Components/Spinner.vue'\n\ndefineProps<{\n  users: {\n    data: {\n      id: number\n      name: string\n    }[]\n  }\n}>()\n</script>\n\n<template>\n  <Head title=\"Data Table\" />\n\n  <InfiniteScroll data=\"users\" class=\"mx-auto max-w-7xl px-8\" :buffer=\"3000\" items-element=\"tbody\">\n    <div class=\"overflow-hidden rounded-2xl shadow ring-1 ring-gray-200\">\n      <table class=\"min-w-full\">\n        <thead class=\"bg-gray-50\">\n          <tr>\n            <th class=\"px-6 py-4 text-left text-sm font-semibold text-gray-900\">ID</th>\n            <th class=\"px-6 py-4 text-left text-sm font-semibold text-gray-900\">Name</th>\n          </tr>\n        </thead>\n        <tbody class=\"divide-y divide-gray-200 bg-white\">\n          <tr v-for=\"user in users.data\" :key=\"user.id\" class=\"transition-colors hover:bg-gray-50\">\n            <td class=\"px-6 py-4 text-sm text-gray-700\">{{ user.id }}</td>\n            <td class=\"px-6 py-4 text-sm text-gray-700\">{{ user.name }}</td>\n          </tr>\n        </tbody>\n      </table>\n    </div>\n\n    <template #loading>\n      <div class=\"flex justify-center py-16\">\n        <Spinner class=\"size-6 text-gray-400\" />\n      </div>\n    </template>\n  </InfiniteScroll>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/Defer.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '../Components/Layout.vue'\nimport Spinner from '../Components/Spinner.vue'\nimport TestGrid from '../Components/TestGrid.vue'\nimport TestGridItem from '../Components/TestGridItem.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Deferred, Head, WhenVisible } from '@inertiajs/vue3'\n\ndefineProps<{\n  users?: {\n    id: number\n    name: string\n    email: string\n  }[]\n  organizations?: {\n    id: number\n    name: string\n    url: string\n  }[]\n  foods?: {\n    id: number\n    name: string\n  }[]\n  surprise?: {\n    id: number\n    name: string\n  }[]\n  dogs?: {\n    id: number\n    name: string\n  }[]\n  lunch?: {\n    id: number\n    name: string\n  }[]\n}>()\n</script>\n\n<template>\n  <Head title=\"Async Request\" />\n  <h1 class=\"text-3xl\">Deferred Props</h1>\n  <div class=\"mt-6 rounded-sm border border-yellow-500 bg-yellow-200 p-4\">\n    <p>Page is loaded!</p>\n  </div>\n  <TestGrid>\n    <TestGridItem>\n      <Deferred data=\"users\">\n        <template #fallback>\n          <p>Loading Users...</p>\n        </template>\n\n        <div v-for=\"user in users\">\n          <p>#{{ user.id }}: {{ user.name }} ({{ user.email }})</p>\n        </div>\n      </Deferred>\n    </TestGridItem>\n\n    <TestGridItem>\n      <Deferred data=\"foods\">\n        <template #fallback>\n          <p>Loading Foods...</p>\n        </template>\n\n        <div v-for=\"food in foods\">\n          <p>#{{ food.id }}: {{ food.name }}</p>\n        </div>\n      </Deferred>\n    </TestGridItem>\n\n    <TestGridItem>\n      <Deferred data=\"organizations\">\n        <template #fallback>\n          <p>Loading Organizations...</p>\n        </template>\n\n        <div v-for=\"org in organizations\">\n          <p>#{{ org.id }}: {{ org.name }} ({{ org.url }})</p>\n        </div>\n      </Deferred>\n    </TestGridItem>\n  </TestGrid>\n\n  <div class=\"mt-72\">\n    <WhenVisible data=\"surprise\">\n      <template #fallback>\n        <div class=\"h-24\">\n          <div class=\"flex items-center\"><Spinner class=\"mr-2 size-5\" /> Loading Surprise...</div>\n        </div>\n      </template>\n\n      <div v-for=\"sur in surprise\">\n        <p>#{{ sur.id }}: {{ sur.name }}</p>\n      </div>\n    </WhenVisible>\n  </div>\n\n  <div class=\"mt-72\">\n    <WhenVisible :data=\"['dogs', 'lunch']\" :buffer=\"200\">\n      <template #fallback>\n        <div class=\"h-20\">\n          <div class=\"flex items-center\"><Spinner class=\"mr-2 size-5\" /> Loading Dogs and Lunch...</div>\n        </div>\n      </template>\n\n      <div class=\"flex space-x-6\">\n        <div>\n          <div v-for=\"dog in dogs\">\n            <p>#{{ dog.id }}: {{ dog.name }}</p>\n          </div>\n        </div>\n\n        <div>\n          <div v-for=\"item in lunch\">\n            <p>#{{ item.id }}: {{ item.name }}</p>\n          </div>\n        </div>\n      </div>\n    </WhenVisible>\n  </div>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/Flash.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '../Components/Layout.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head, Link, router, usePage } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst page = usePage()\nconst flashLog = ref<Record<string, unknown>[]>([])\n\nrouter.on('flash', ({ detail: { flash } }) => {\n  flashLog.value.push(flash)\n})\n\nconst triggerFrontendFlash = () => {\n  router.flash('message', 'Hello from the frontend!')\n}\n\nconst triggerMultipleFlash = () => {\n  router.flash({\n    message: 'Multiple items',\n    count: 42,\n  })\n}\n\nconst clearLog = () => {\n  flashLog.value = []\n}\n</script>\n\n<template>\n  <Head title=\"Flash\" />\n  <h1 class=\"text-3xl\">Flash</h1>\n\n  <div class=\"mt-6 space-y-6\">\n    <div>\n      <h2 class=\"text-lg font-semibold\">Current page.flash</h2>\n      <pre class=\"mt-2 rounded-sm bg-gray-100 p-3 text-sm\">{{ page.flash ?? 'null' }}</pre>\n    </div>\n\n    <div>\n      <h2 class=\"text-lg font-semibold\">Flash Event Log</h2>\n      <pre class=\"mt-2 rounded-sm bg-gray-100 p-3 text-sm\">{{\n        flashLog.length ? flashLog : 'No flash events yet'\n      }}</pre>\n      <button v-if=\"flashLog.length\" @click=\"clearLog\" class=\"mt-2 text-sm text-gray-500 underline\">Clear log</button>\n    </div>\n\n    <div class=\"space-y-3\">\n      <h2 class=\"text-lg font-semibold\">Server-side Flash</h2>\n      <div>\n        <Link href=\"/flash/direct\" class=\"rounded-sm bg-slate-800 px-4 py-2 text-white\">Flash with render</Link>\n      </div>\n      <form @submit.prevent=\"router.post('/flash/form')\">\n        <button type=\"submit\" class=\"rounded-sm bg-slate-800 px-4 py-2 text-white\">Flash with redirect</button>\n      </form>\n    </div>\n\n    <div class=\"space-y-3\">\n      <h2 class=\"text-lg font-semibold\">Frontend Flash</h2>\n      <div class=\"flex gap-3\">\n        <button @click=\"triggerFrontendFlash\" class=\"rounded-sm bg-slate-800 px-4 py-2 text-white\">\n          router.flash(key, value)\n        </button>\n        <button @click=\"triggerMultipleFlash\" class=\"rounded-sm bg-slate-800 px-4 py-2 text-white\">\n          router.flash(object)\n        </button>\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/Form.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '../Components/Layout.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head, useForm } from '@inertiajs/vue3'\n\nconst form = useForm('NewUser', {\n  name: '',\n  company: '',\n  role: '',\n})\n</script>\n\n<template>\n  <Head title=\"Form\" />\n  <h1 class=\"text-3xl\">Form</h1>\n  <form @submit.prevent=\"form.post('/user')\" class=\"mt-6 max-w-md space-y-4\">\n    <div v-if=\"form.isDirty\" class=\"my-5 rounded-sm border border-amber-100 bg-amber-50 p-3 text-amber-800\">\n      There are unsaved changes!\n    </div>\n    <div>\n      <label class=\"block\" for=\"name\">Name:</label>\n      <input\n        type=\"text\"\n        v-model=\"form.name\"\n        id=\"name\"\n        class=\"mt-1 w-full appearance-none rounded-sm border border-gray-200 px-2 py-1 shadow-xs\"\n      />\n      <div v-if=\"form.errors.name\" class=\"mt-2 text-sm text-red-600\">{{ form.errors.name }}</div>\n    </div>\n    <div>\n      <label class=\"block\" for=\"company\">Company:</label>\n      <input\n        type=\"text\"\n        v-model=\"form.company\"\n        id=\"company\"\n        class=\"mt-1 w-full appearance-none rounded-sm border border-gray-200 px-2 py-1 shadow-xs\"\n      />\n      <div v-if=\"form.errors.company\" class=\"mt-2 text-sm text-red-600\">{{ form.errors.company }}</div>\n    </div>\n    <div>\n      <label class=\"block\" for=\"role\">Role:</label>\n      <select\n        v-model=\"form.role\"\n        id=\"role\"\n        class=\"mt-1 w-full appearance-none rounded-sm border border-gray-200 px-2 py-1 shadow-xs\"\n      >\n        <option></option>\n        <option>User</option>\n        <option>Admin</option>\n        <option>Super</option>\n      </select>\n      <div v-if=\"form.errors.role\" class=\"mt-2 text-sm text-red-600\">{{ form.errors.role }}</div>\n    </div>\n    <div class=\"flex gap-4\">\n      <button type=\"submit\" :disabled=\"form.processing\" class=\"rounded-sm bg-slate-800 px-6 py-2 text-white\">\n        Submit\n      </button>\n      <button type=\"button\" @click=\"form.reset()\">Reset</button>\n    </div>\n  </form>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/FormComponent.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '../Components/Layout.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Form, Head } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\ndefineProps({\n  foo: Number,\n  bar: Number,\n  quux: Number,\n})\n\nconst customHeaders = ref({ 'X-Custom-Header': 'Demo-Value' })\nconst errorBag = ref('custom-bag')\n</script>\n\n<template>\n  <Head title=\"Form Component\" />\n  <h1 class=\"text-3xl\">Form Component</h1>\n\n  <!-- Main Demo Form -->\n  <Form\n    action=\"/form-component\"\n    method=\"post\"\n    :headers=\"customHeaders\"\n    :error-bag=\"errorBag\"\n    :transform=\"(data) => ({ ...data, demo: 'data' })\"\n    :options=\"{\n      only: ['foo'],\n      reset: ['bar'],\n    }\"\n    #default=\"{\n      errors,\n      hasErrors,\n      processing,\n      progress,\n      wasSuccessful,\n      recentlySuccessful,\n      setError,\n      clearErrors,\n      isDirty,\n      reset,\n      submit,\n    }\"\n    class=\"mt-6 max-w-2xl space-y-6\"\n  >\n    <!-- Status Display -->\n    <div class=\"rounded border border-gray-200 bg-gray-50 p-4\">\n      <h3 class=\"mb-3 text-lg font-medium\">Form Status (v-slot props)</h3>\n      <div class=\"grid grid-cols-2 gap-4 text-sm\">\n        <div>\n          isDirty: <span class=\"font-mono\" :class=\"isDirty ? 'text-orange-600' : 'text-gray-500'\">{{ isDirty }}</span>\n        </div>\n        <div>\n          hasErrors:\n          <span class=\"font-mono\" :class=\"hasErrors ? 'text-red-600' : 'text-gray-500'\">{{ hasErrors }}</span>\n        </div>\n        <div>\n          processing:\n          <span class=\"font-mono\" :class=\"processing ? 'text-blue-600' : 'text-gray-500'\">{{ processing }}</span>\n        </div>\n        <div>\n          wasSuccessful:\n          <span class=\"font-mono\" :class=\"wasSuccessful ? 'text-green-600' : 'text-gray-500'\">{{ wasSuccessful }}</span>\n        </div>\n        <div>\n          recentlySuccessful:\n          <span class=\"font-mono\" :class=\"recentlySuccessful ? 'text-green-600' : 'text-gray-500'\">{{\n            recentlySuccessful\n          }}</span>\n        </div>\n        <div v-if=\"progress\">\n          progress: <span class=\"font-mono text-blue-600\">{{ Math.round(progress.percentage) }}%</span>\n        </div>\n      </div>\n    </div>\n\n    <div v-if=\"isDirty\" class=\"rounded border border-amber-100 bg-amber-50 p-3 text-amber-800\">\n      There are unsaved changes!\n    </div>\n\n    <!-- Form Fields -->\n    <div class=\"space-y-4\">\n      <!-- Text Input -->\n      <div>\n        <label class=\"block font-medium\" for=\"name\">Name</label>\n        <input\n          type=\"text\"\n          name=\"name\"\n          id=\"name\"\n          placeholder=\"Enter your name\"\n          class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n          :class=\"errors.name ? 'border-red-500' : ''\"\n        />\n        <div v-if=\"errors.name\" class=\"mt-1 text-sm text-red-600\">{{ errors.name }}</div>\n      </div>\n\n      <!-- File Input -->\n      <div>\n        <label class=\"block font-medium\" for=\"avatar\">Avatar</label>\n        <input\n          type=\"file\"\n          name=\"avatar\"\n          id=\"avatar\"\n          class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n        />\n        <div v-if=\"errors.avatar\" class=\"mt-1 text-sm text-red-600\">{{ errors.avatar }}</div>\n      </div>\n\n      <!-- Multiple Select -->\n      <div>\n        <label class=\"block font-medium\" for=\"skills\">Skills (Multiple)</label>\n        <select\n          name=\"skills[]\"\n          id=\"skills\"\n          multiple\n          class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n        >\n          <option value=\"vue\">Vue.js</option>\n          <option value=\"react\">React</option>\n          <option value=\"laravel\">Laravel</option>\n          <option value=\"tailwind\">Tailwind CSS</option>\n        </select>\n        <div v-if=\"errors['skills']\" class=\"mt-1 text-sm text-red-600\">{{ errors['skills'] }}</div>\n      </div>\n\n      <!-- Array Input (Tags) -->\n      <div>\n        <label class=\"block font-medium\">Tags</label>\n        <div class=\"mt-1 space-y-2\">\n          <input\n            type=\"text\"\n            name=\"tags[]\"\n            placeholder=\"Tag 1\"\n            class=\"w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n          />\n          <div v-if=\"errors['tags.0']\" class=\"text-sm text-red-600\">{{ errors['tags.0'] }}</div>\n          <input\n            type=\"text\"\n            name=\"tags[]\"\n            placeholder=\"Tag 2\"\n            class=\"w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n          />\n          <div v-if=\"errors['tags.1']\" class=\"text-sm text-red-600\">{{ errors['tags.1'] }}</div>\n        </div>\n      </div>\n\n      <!-- Nested Object Input -->\n      <div>\n        <label class=\"block font-medium\">Address</label>\n        <div class=\"mt-1 grid grid-cols-2 gap-2\">\n          <input\n            type=\"text\"\n            name=\"user[address][street]\"\n            placeholder=\"Street\"\n            class=\"appearance-none rounded border px-2 py-1 shadow-sm\"\n          />\n          <input\n            type=\"text\"\n            name=\"user[address][city]\"\n            placeholder=\"City\"\n            class=\"appearance-none rounded border px-2 py-1 shadow-sm\"\n          />\n        </div>\n      </div>\n    </div>\n\n    <!-- Action Buttons -->\n    <div class=\"flex flex-wrap gap-2\">\n      <button\n        type=\"submit\"\n        :disabled=\"processing\"\n        class=\"rounded bg-slate-800 px-4 py-2 text-white disabled:opacity-50\"\n      >\n        Submit\n      </button>\n\n      <button type=\"button\" @click=\"reset()\" class=\"rounded bg-gray-500 px-4 py-2 text-white\">Reset</button>\n\n      <button\n        type=\"button\"\n        @click=\"setError({ name: 'Name is required', avatar: 'Please select a file' })\"\n        class=\"rounded bg-red-500 px-4 py-2 text-white\"\n      >\n        Set Errors\n      </button>\n\n      <button type=\"button\" @click=\"clearErrors()\" class=\"rounded bg-green-500 px-4 py-2 text-white\">\n        Clear Errors\n      </button>\n    </div>\n  </Form>\n\n  <!-- Form Configuration -->\n  <div class=\"mt-8 max-w-2xl space-y-4\">\n    <h2 class=\"text-2xl\">Form Configuration</h2>\n\n    <div class=\"grid grid-cols-1 gap-6 md:grid-cols-2\">\n      <div class=\"rounded border border-gray-200 bg-gray-50 p-4\">\n        <div class=\"space-y-1 text-sm\">\n          <div>\n            <strong>Headers:</strong> <code class=\"text-xs\">{{ JSON.stringify(customHeaders) }}</code>\n          </div>\n          <div>\n            <strong>Error Bag:</strong> <code>{{ errorBag }}</code>\n          </div>\n          <div><strong>Only:</strong> <code>['foo']</code></div>\n          <div><strong>Reset:</strong> <code>['bar']</code></div>\n          <div><strong>Method:</strong> <code>POST</code></div>\n        </div>\n      </div>\n\n      <div class=\"space-y-3\">\n        <div>\n          <label class=\"block text-sm font-medium\">Error Bag</label>\n          <input\n            type=\"text\"\n            v-model=\"errorBag\"\n            class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n            placeholder=\"Error bag name\"\n          />\n        </div>\n\n        <div>\n          <label class=\"block text-sm font-medium\">Custom Header Value</label>\n          <input\n            type=\"text\"\n            v-model=\"customHeaders['X-Custom-Header']\"\n            class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n            placeholder=\"Header value\"\n          />\n        </div>\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/FormComponentPrecognition.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '../Components/Layout.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { FormComponentMethods } from '@inertiajs/core'\nimport { Form, Head } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst validateFiles = ref(false)\nconst validationTimeout = ref(1500)\n\nconst callbacks = ref({\n  success: false,\n  error: false,\n  finish: false,\n})\n\nconst validateWithCallbacks = (validate: FormComponentMethods['validate']) => {\n  callbacks.value = { success: false, error: false, finish: false }\n\n  validate({\n    onPrecognitionSuccess: () => (callbacks.value.success = true),\n    onValidationError: () => (callbacks.value.error = true),\n    onFinish: () => (callbacks.value.finish = true),\n    onBeforeValidation: (newReq) => {\n      if (newReq.data?.name === 'block') {\n        alert('Validation blocked by onBeforeValidation!')\n        return false\n      }\n    },\n  })\n}\n</script>\n\n<template>\n  <Head title=\"Form Component Precognition\" />\n  <h1 class=\"text-3xl\">Form Component Precognition</h1>\n\n  <Form\n    action=\"/form-component/precognition\"\n    method=\"post\"\n    :validate-files=\"validateFiles\"\n    :validation-timeout=\"validationTimeout\"\n    #default=\"{ errors, invalid, valid, validate, validating, touch, touched, processing }\"\n    class=\"mt-6 max-w-2xl space-y-6\"\n  >\n    <!-- Status Display -->\n    <div class=\"rounded border border-gray-200 bg-gray-50 p-4\">\n      <h3 class=\"mb-3 text-lg font-medium\">Validation Status (v-slot props)</h3>\n      <div class=\"grid grid-cols-2 gap-4 text-sm\">\n        <div>\n          validating:\n          <span class=\"font-mono\" :class=\"validating ? 'text-blue-600' : 'text-gray-500'\">{{ validating }}</span>\n        </div>\n        <div>\n          processing:\n          <span class=\"font-mono\" :class=\"processing ? 'text-blue-600' : 'text-gray-500'\">{{ processing }}</span>\n        </div>\n        <div>\n          touched():\n          <span class=\"font-mono\" :class=\"touched() ? 'text-orange-600' : 'text-gray-500'\">{{ touched() }}</span>\n        </div>\n        <div>\n          touched('name'):\n          <span class=\"font-mono\" :class=\"touched('name') ? 'text-orange-600' : 'text-gray-500'\">{{\n            touched('name')\n          }}</span>\n        </div>\n        <div>\n          touched('email'):\n          <span class=\"font-mono\" :class=\"touched('email') ? 'text-orange-600' : 'text-gray-500'\">{{\n            touched('email')\n          }}</span>\n        </div>\n      </div>\n    </div>\n\n    <!-- Form Fields -->\n    <div class=\"space-y-4\">\n      <!-- Name Input -->\n      <div>\n        <label class=\"block font-medium\" for=\"name\">Name</label>\n        <input\n          type=\"text\"\n          name=\"name\"\n          id=\"name\"\n          placeholder=\"Enter your name (min 3 chars)\"\n          @blur=\"validate('name')\"\n          class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n          :class=\"invalid('name') ? 'border-red-500' : valid('name') ? 'border-green-500' : ''\"\n        />\n        <div v-if=\"invalid('name')\" class=\"mt-1 text-sm text-red-600\">{{ errors.name }}</div>\n        <div v-if=\"valid('name')\" class=\"mt-1 text-sm text-green-600\">Valid!</div>\n      </div>\n\n      <!-- Email Input -->\n      <div>\n        <label class=\"block font-medium\" for=\"email\">Email</label>\n        <input\n          type=\"email\"\n          name=\"email\"\n          id=\"email\"\n          placeholder=\"Enter your email\"\n          @blur=\"validate('email')\"\n          class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n          :class=\"invalid('email') ? 'border-red-500' : valid('email') ? 'border-green-500' : ''\"\n        />\n        <div v-if=\"invalid('email')\" class=\"mt-1 text-sm text-red-600\">{{ errors.email }}</div>\n        <div v-if=\"valid('email')\" class=\"mt-1 text-sm text-green-600\">Valid!</div>\n      </div>\n\n      <!-- File Input -->\n      <div>\n        <label class=\"block font-medium\" for=\"avatar\">Avatar</label>\n        <input\n          type=\"file\"\n          name=\"avatar\"\n          id=\"avatar\"\n          @change=\"validate('avatar')\"\n          class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\"\n          :class=\"invalid('avatar') ? 'border-red-500' : valid('avatar') ? 'border-green-500' : ''\"\n        />\n        <div v-if=\"invalid('avatar')\" class=\"mt-1 text-sm text-red-600\">{{ errors.avatar }}</div>\n        <div v-if=\"valid('avatar')\" class=\"mt-1 text-sm text-green-600\">Valid!</div>\n      </div>\n    </div>\n\n    <!-- Action Buttons -->\n    <div class=\"flex flex-wrap gap-2\">\n      <button\n        type=\"submit\"\n        :disabled=\"processing\"\n        class=\"rounded bg-slate-800 px-4 py-2 text-white disabled:opacity-50\"\n      >\n        Submit\n      </button>\n\n      <button type=\"button\" @click=\"validate()\" class=\"rounded border border-slate-300 px-4 py-2 hover:bg-slate-50\">\n        Validate Touched\n      </button>\n\n      <button type=\"button\" @click=\"touch('name')\" class=\"rounded border border-slate-300 px-4 py-2 hover:bg-slate-50\">\n        Touch Name\n      </button>\n\n      <button\n        type=\"button\"\n        @click=\"validateWithCallbacks(validate)\"\n        class=\"rounded border border-slate-300 px-4 py-2 hover:bg-slate-50\"\n      >\n        Validate with Callbacks\n      </button>\n    </div>\n\n    <!-- Callbacks Display -->\n    <div class=\"rounded border border-gray-200 bg-gray-50 p-4\">\n      <h3 class=\"mb-3 text-lg font-medium\">Validation Callbacks</h3>\n      <p class=\"mb-3 text-sm text-gray-600\">Enter \"block\" in the name field to test onBeforeValidation blocking.</p>\n      <div class=\"grid grid-cols-3 gap-4 text-sm\">\n        <div>\n          onPrecognitionSuccess:\n          <span class=\"font-mono\" :class=\"callbacks.success ? 'text-green-600' : 'text-gray-500'\">{{\n            callbacks.success\n          }}</span>\n        </div>\n        <div>\n          onValidationError:\n          <span class=\"font-mono\" :class=\"callbacks.error ? 'text-red-600' : 'text-gray-500'\">{{\n            callbacks.error\n          }}</span>\n        </div>\n        <div>\n          onFinish:\n          <span class=\"font-mono\" :class=\"callbacks.finish ? 'text-blue-600' : 'text-gray-500'\">{{\n            callbacks.finish\n          }}</span>\n        </div>\n      </div>\n    </div>\n  </Form>\n\n  <!-- Configuration -->\n  <div class=\"mt-8 max-w-2xl space-y-4\">\n    <h2 class=\"text-2xl\">Configuration</h2>\n\n    <div class=\"grid grid-cols-1 gap-6 md:grid-cols-2\">\n      <div class=\"rounded border border-gray-200 bg-gray-50 p-4\">\n        <div class=\"space-y-1 text-sm\">\n          <div>\n            <strong>Validate Files:</strong> <code>{{ validateFiles }}</code>\n          </div>\n          <div>\n            <strong>Validation Timeout:</strong> <code>{{ validationTimeout }}ms</code>\n          </div>\n          <div><strong>Method:</strong> <code>POST</code></div>\n        </div>\n      </div>\n\n      <div class=\"space-y-3\">\n        <div>\n          <label class=\"flex items-center gap-2\">\n            <input type=\"checkbox\" v-model=\"validateFiles\" class=\"rounded\" />\n            <span class=\"text-sm\">Enable file validation</span>\n          </label>\n        </div>\n\n        <div>\n          <label class=\"block text-sm font-medium\">Validation Timeout</label>\n          <select v-model=\"validationTimeout\" class=\"mt-1 w-full appearance-none rounded border px-2 py-1 shadow-sm\">\n            <option :value=\"500\">500ms</option>\n            <option :value=\"1000\">1000ms</option>\n            <option :value=\"1500\">1500ms</option>\n            <option :value=\"2000\">2000ms</option>\n          </select>\n        </div>\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/Home.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '../Components/Layout.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head, Link, router } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <Head title=\"Home\" />\n  <h1 class=\"text-3xl\">Home</h1>\n  <div class=\"mt-6 space-y-4\">\n    <div>\n      <Link href=\"/article#far-down\" class=\"text-blue-700 underline\">Link to bottom of article page</Link>\n    </div>\n\n    <div>\n      <button type=\"button\" @click=\"router.clearHistory()\" class=\"rounded-lg bg-blue-500 px-4 py-2 text-white\">\n        Clear History\n      </button>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/InfiniteScroll.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '../Components/Layout.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head, router, WhenVisible } from '@inertiajs/vue3'\nimport { ref } from 'vue'\n\nconst props = defineProps<{\n  items?: {\n    id: number\n    name: string\n  }[]\n  page: number\n  item_types: string[]\n  item_type: string\n}>()\n\nconst currentItemType = ref(props.item_type)\n\nconst setItemType = (type: string) => {\n  currentItemType.value = type\n\n  router.reload({\n    data: {\n      item_type: type,\n      page: 1,\n    },\n    reset: ['items', 'page'],\n    preserveUrl: true,\n  })\n}\n</script>\n\n<template>\n  <Head title=\"Infinite Scroll\" />\n  <h1 class=\"text-3xl\">And Beyond</h1>\n\n  <div class=\"my-6 space-x-4\">\n    <button\n      v-for=\"type in item_types\"\n      @click=\"setItemType(type)\"\n      :key=\"type\"\n      class=\"rounded-lg bg-gray-200 px-4 py-1 hover:bg-gray-300\"\n    >\n      {{ type }}\n    </button>\n  </div>\n\n  <div class=\"mt-6 w-full max-w-2xl overflow-hidden rounded-sm border border-gray-200 shadow-xs\">\n    <table class=\"w-full text-left\">\n      <thead>\n        <tr>\n          <th class=\"px-4 py-2\">Id</th>\n          <th class=\"px-4 py-2\">Name</th>\n        </tr>\n      </thead>\n      <tbody v-if=\"items\">\n        <tr v-for=\"item in items\" :key=\"item.id\" class=\"border-t border-gray-200\">\n          <td class=\"px-4 py-2\">{{ item.id }}</td>\n          <td class=\"px-4 py-2\">{{ item.name }}</td>\n        </tr>\n      </tbody>\n    </table>\n\n    <div v-if=\"!items\" class=\"bg-gray-100 p-4 text-center\">Loading items...</div>\n    <WhenVisible\n      v-else\n      always\n      :buffer=\"200\"\n      :params=\"{\n        data: {\n          item_type: currentItemType,\n          page: page + 1,\n        },\n        only: ['items', 'page'],\n        preserveUrl: true,\n      }\"\n    >\n      <template #fallback>\n        <div class=\"bg-gray-100 p-4 text-center\">Fetching more items...</div>\n      </template>\n\n      <div class=\"bg-gray-100 p-4 text-center\">Fetching more items...</div>\n    </WhenVisible>\n  </div>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/Login.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '../Components/Layout.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <Head title=\"Login\" />\n  <h1 class=\"text-3xl\">Login</h1>\n  <p class=\"mt-6\">You made a <code>POST</code> request to the logout endpoint and were redirected to the login page.</p>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/Once/First.vue",
    "content": "<script lang=\"ts\">\nimport Layout from './Layout.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head } from '@inertiajs/vue3'\n\ndefineProps<{\n  foo: string\n  bar: string\n  baz1: string\n  qux?: string\n}>()\n</script>\n\n<template>\n  <Head title=\"Once Props: First Page\" />\n  <h1 class=\"text-3xl\">Once Props: First Page</h1>\n  <p>Foo: {{ foo }}</p>\n  <p>Bar: {{ bar }}</p>\n  <p>Baz: {{ baz1 }}</p>\n  <p>Qux: {{ qux ?? 'Loading...' }}</p>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/Once/Fourth.vue",
    "content": "<script lang=\"ts\">\nimport Layout from './Layout.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head } from '@inertiajs/vue3'\n\ndefineProps<{\n  foo: string\n  bar: string\n  baz4: string\n  qux?: string\n}>()\n</script>\n\n<template>\n  <Head title=\"Once Props: Fourth Page\" />\n  <h1 class=\"text-3xl\">Once Props: Fourth Page</h1>\n  <p>Foo: {{ foo }}</p>\n  <p>Bar: {{ bar }}</p>\n  <p>Baz: {{ baz4 }}</p>\n  <p>Qux: {{ qux ?? 'Loading...' }}</p>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/Once/Layout.vue",
    "content": "<script setup lang=\"ts\">\nimport Layout from '../../Components/Layout.vue'\n\nimport { Link } from '@inertiajs/vue3'\n</script>\n\n<template>\n  <Layout>\n    <slot />\n    <Link href=\"/once/1\" class=\"text-blue-500 underline\"> Go to First Page </Link>\n    <Link href=\"/once/2\" class=\"ml-4 text-blue-500 underline\"> Go to Second Page </Link>\n    <Link href=\"/once/3\" class=\"ml-4 text-blue-500 underline\"> Go to Third Page </Link>\n    <Link href=\"/once/4\" class=\"ml-4 text-blue-500 underline\" prefetch=\"mount\"> Go to Fourth Page </Link>\n    <button @click=\"$inertia.reload({ only: ['foo'] })\" class=\"ml-4 text-blue-500 underline\">Reload Foo</button>\n    <button @click=\"$inertia.reload({ only: ['bar'] })\" class=\"ml-4 text-blue-500 underline\">Reload Bar</button>\n    <button @click=\"$inertia.reload({ only: ['baz1', 'baz2', 'baz3', 'baz4'] })\" class=\"ml-4 text-blue-500 underline\">\n      Reload Baz\n    </button>\n    <button @click=\"$inertia.reload({ only: ['qux'] })\" class=\"ml-4 text-blue-500 underline\">Reload Qux</button>\n  </Layout>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/Once/Second.vue",
    "content": "<script lang=\"ts\">\nimport Layout from './Layout.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head } from '@inertiajs/vue3'\n\ndefineProps<{\n  foo: string\n  bar: string\n  baz2: string\n  qux?: string\n}>()\n</script>\n\n<template>\n  <Head title=\"Once Props: Second Page\" />\n  <h1 class=\"text-3xl\">Once Props: Second Page</h1>\n  <p>Foo: {{ foo }}</p>\n  <p>Bar: {{ bar }}</p>\n  <p>Baz: {{ baz2 }}</p>\n  <p>Qux: {{ qux ?? 'Loading...' }}</p>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/Once/Third.vue",
    "content": "<script lang=\"ts\">\nimport Layout from './Layout.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head } from '@inertiajs/vue3'\n\ndefineProps<{\n  foo: string\n  bar: string\n  baz3: string\n  qux?: string\n}>()\n</script>\n\n<template>\n  <Head title=\"Once Props: Third Page\" />\n  <h1 class=\"text-3xl\">Once Props: Third Page</h1>\n  <p>Foo: {{ foo }}</p>\n  <p>Bar: {{ bar }}</p>\n  <p>Baz: {{ baz3 }}</p>\n  <p>Qux: {{ qux ?? 'Loading...' }}</p>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/PhotoGrid.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '../Components/Layout.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head, InfiniteScroll } from '@inertiajs/vue3'\nimport Image from '../Components/Image.vue'\nimport Spinner from '../Components/Spinner.vue'\n\ndefineProps<{\n  photos: {\n    data: {\n      id: number\n      url: string\n    }[]\n  }\n}>()\n</script>\n\n<template>\n  <Head title=\"Photo Grid\" />\n\n  <InfiniteScroll\n    data=\"photos\"\n    class=\"mx-auto grid max-w-7xl grid-cols-1 gap-6 px-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\"\n    :buffer=\"1000\"\n  >\n    <Image v-for=\"photo in photos.data\" :key=\"photo.id\" :id=\"photo.id\" :url=\"photo.url\" />\n\n    <template #loading>\n      <div class=\"flex justify-center py-16\">\n        <Spinner class=\"size-6 text-gray-400\" />\n      </div>\n    </template>\n  </InfiniteScroll>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/PhotoHorizontal.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '../Components/Layout.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head, InfiniteScroll } from '@inertiajs/vue3'\nimport Image from '../Components/Image.vue'\nimport Spinner from '../Components/Spinner.vue'\n\ndefineProps<{\n  photos: {\n    data: {\n      id: number\n      url: string\n    }[]\n  }\n}>()\n</script>\n\n<template>\n  <Head title=\"Photo Grid (Horizontal)\" />\n  <div class=\"flex h-[200px] w-full overflow-x-scroll\">\n    <InfiniteScroll data=\"photos\" :buffer=\"1000\" class=\"flex h-[200px] gap-6\" only-next preserve-url>\n      <Image v-for=\"photo in photos.data\" :key=\"photo.id\" :id=\"photo.id\" :url=\"photo.url\" />\n\n      <template #loading>\n        <div class=\"flex size-[200px] items-center justify-center\">\n          <Spinner class=\"size-6 text-gray-400\" />\n        </div>\n      </template>\n    </InfiniteScroll>\n  </div>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/Poll.vue",
    "content": "<script lang=\"ts\">\nimport usePoll from '../../../../../packages/vue3/src/usePoll'\nimport Layout from '../Components/Layout.vue'\nimport TestGrid from '../Components/TestGrid.vue'\nimport TestGridItem from '../Components/TestGridItem.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head, router } from '@inertiajs/vue3'\nimport { onMounted, ref } from 'vue'\n\ndefineProps<{\n  users: string[]\n  companies: string[]\n}>()\n\nconst userPollCount = ref(0)\nconst hookPollCount = ref(0)\nconst companyPollCount = ref(0)\n\nconst triggerAsyncRedirect = () => {\n  router.get(\n    '/elsewhere',\n    {},\n    {\n      only: ['something'],\n      async: true,\n    },\n  )\n}\n\nconst { start: startHookPolling, stop } = usePoll(\n  2000,\n  {\n    only: ['asdf'],\n    onFinish() {\n      hookPollCount.value++\n    },\n  },\n  {\n    keepAlive: true,\n    autoStart: false,\n  },\n)\n\nonMounted(() => {\n  setTimeout(() => {\n    startHookPolling()\n  }, 2000)\n\n  const { stop: stopUserPolling } = router.poll(\n    1000,\n    {\n      only: ['users'],\n      onFinish() {\n        userPollCount.value++\n      },\n    },\n    { keepAlive: true },\n  )\n\n  setTimeout(() => {\n    console.log('stopping user polling')\n    stopUserPolling()\n  }, 3000)\n})\n</script>\n\n<template>\n  <Head title=\"Async Request\" />\n  <h1 class=\"text-3xl\">Poll</h1>\n  <TestGrid>\n    <TestGridItem>\n      <template #title> User Poll Request Count: {{ userPollCount }} </template>\n      <div v-for=\"user in users\">\n        <div>{{ user }}</div>\n      </div>\n    </TestGridItem>\n    <TestGridItem>\n      <template #title> Companies Poll Request Count: {{ companyPollCount }} </template>\n      <div v-for=\"company in companies\">\n        <div>{{ company }}</div>\n      </div>\n    </TestGridItem>\n    <TestGridItem>\n      <template #title> Hook Poll Request Count: {{ hookPollCount }} </template>\n    </TestGridItem>\n    <TestGridItem>\n      <button @click=\"triggerAsyncRedirect\">Trigger Async Redirect</button>\n    </TestGridItem>\n  </TestGrid>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/User.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '../Components/Layout.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head } from '@inertiajs/vue3'\n\ndefineProps({ user: Object })\n</script>\n\n<template>\n  <Head title=\"User\" />\n  <h1 class=\"text-3xl\">User</h1>\n  <p class=\"mt-6\">You successfully created a new user! Well not really, there is no persistence in this app.</p>\n  <ul class=\"mt-6 space-y-2\">\n    <li><strong>Name:</strong> {{ user.name }}</li>\n    <li><strong>Company:</strong> {{ user.company }}</li>\n    <li><strong>Role:</strong> {{ user.role }}</li>\n  </ul>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/Pages/Users.vue",
    "content": "<script lang=\"ts\">\nimport Layout from '../Components/Layout.vue'\nexport default { layout: Layout }\n</script>\n\n<script setup lang=\"ts\">\nimport { Head, usePrefetch } from '@inertiajs/vue3'\n\nconst { isPrefetching, isPrefetched, lastUpdatedAt, flush } = usePrefetch()\n\ndefineProps({ users: Array, date: String })\n</script>\n\n<template>\n  <Head title=\"User\" />\n  <h1 class=\"text-3xl\">Users</h1>\n  <div class=\"my-6\">\n    Data last refreshed at:\n    <span v-if=\"lastUpdatedAt\"> <br />Client: {{ new Date(lastUpdatedAt) }} <br />Server: {{ date }}</span>\n    <span v-else>N/A</span>\n    <div v-if=\"isPrefetched\">(Page is prefetched!)</div>\n    <span v-if=\"isPrefetching\" class=\"text-red-500\"> refreshing...</span>\n  </div>\n\n  <div class=\"mt-6 w-full max-w-2xl overflow-hidden rounded-sm border border-gray-200 shadow-xs\">\n    <table class=\"w-full text-left\">\n      <thead>\n        <tr>\n          <th class=\"px-4 py-2\">Id</th>\n          <th class=\"px-4 py-2\">Name</th>\n          <th class=\"px-4 py-2\">Email</th>\n        </tr>\n      </thead>\n      <tbody>\n        <tr v-for=\"user in users\" :key=\"user.id\" class=\"border-t border-gray-200\">\n          <td class=\"px-4 py-2\">{{ user.id }}</td>\n          <td class=\"px-4 py-2\">{{ user.name }}</td>\n          <td class=\"px-4 py-2\">{{ user.email }}</td>\n        </tr>\n      </tbody>\n    </table>\n  </div>\n</template>\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/app.ts",
    "content": "import { createInertiaApp } from '@inertiajs/vue3'\nimport { createSSRApp, h, type DefineComponent } from 'vue'\n\ncreateInertiaApp({\n  title: (title) => `${title} - Vue 3 Playground`,\n  resolve: (name) => {\n    const pages = import.meta.glob<DefineComponent>('./Pages/**/*.vue')\n\n    return pages[`./Pages/${name}.vue`]()\n  },\n  setup({ el, App, props, plugin }) {\n    createSSRApp({ render: () => h(App, props) })\n      .use(plugin)\n      .mount(el)\n  },\n})\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/ssr.ts",
    "content": "import { createInertiaApp } from '@inertiajs/vue3'\nimport createServer from '@inertiajs/vue3/server'\nimport { createSSRApp, h, type DefineComponent } from 'vue'\nimport { renderToString } from 'vue/server-renderer'\n\ncreateServer((page) =>\n  createInertiaApp({\n    page,\n    render: renderToString,\n    title: (title) => `${title} - Vue 3 Playground`,\n    resolve: (name) => {\n      const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })\n      return pages[`./Pages/${name}.vue`] as DefineComponent\n    },\n    setup({ App, props, plugin }) {\n      return createSSRApp({\n        render: () => h(App, props),\n      }).use(plugin)\n    },\n  }),\n)\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/types/globals.d.ts",
    "content": "import '@inertiajs/core'\n\ndeclare module '@inertiajs/core' {\n  export interface InertiaConfig {\n    sharedPageProps: {\n      appName: string\n    }\n  }\n}\n"
  },
  {
    "path": "playgrounds/vue3/resources/js/vite-env.d.ts",
    "content": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "playgrounds/vue3/resources/views/app.blade.php",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\" />\n    <meta name=\"csrf-token\" content=\"{{ csrf_token() }}\">\n    @vite(['resources/css/app.css', 'resources/js/app.ts'])\n    @inertiaHead\n  </head>\n  <body>\n    @inertia\n  </body>\n</html>\n"
  },
  {
    "path": "playgrounds/vue3/routes/api.php",
    "content": "<?php\n\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Route;\n\n/*\n|--------------------------------------------------------------------------\n| API Routes\n|--------------------------------------------------------------------------\n|\n| Here is where you can register API routes for your application. These\n| routes are loaded by the RouteServiceProvider within a group which\n| is assigned the \"api\" middleware group. Enjoy building your API!\n|\n*/\n\nRoute::middleware('auth:sanctum')->get('/user', function (Request $request) {\n    return $request->user();\n});\n"
  },
  {
    "path": "playgrounds/vue3/routes/channels.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Facades\\Broadcast;\n\n/*\n|--------------------------------------------------------------------------\n| Broadcast Channels\n|--------------------------------------------------------------------------\n|\n| Here you may register all of the event broadcasting channels that your\n| application supports. The given channel authorization callbacks are\n| used to check if an authenticated user can listen to the channel.\n|\n*/\n\nBroadcast::channel('App.Models.User.{id}', function ($user, $id) {\n    return (int) $user->id === (int) $id;\n});\n"
  },
  {
    "path": "playgrounds/vue3/routes/console.php",
    "content": "<?php\n\nuse Illuminate\\Foundation\\Inspiring;\nuse Illuminate\\Support\\Facades\\Artisan;\n\n/*\n|--------------------------------------------------------------------------\n| Console Routes\n|--------------------------------------------------------------------------\n|\n| This file is where you may define all of your Closure based console\n| commands. Each Closure is bound to a command instance allowing a\n| simple approach to interacting with each command's IO methods.\n|\n*/\n\nArtisan::command('inspire', function () {\n    $this->comment(Inspiring::quote());\n})->purpose('Display an inspiring quote');\n"
  },
  {
    "path": "playgrounds/vue3/routes/web.php",
    "content": "<?php\n\nuse App\\Http\\Requests\\PrecognitionFormRequest;\nuse App\\Models\\ChatMessage;\nuse Illuminate\\Foundation\\Http\\Middleware\\HandlePrecognitiveRequests;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Pagination\\LengthAwarePaginator;\nuse Illuminate\\Support\\Facades\\Cache;\nuse Illuminate\\Support\\Facades\\Route;\nuse Inertia\\Inertia;\nuse Prism\\Prism\\Enums\\Provider;\nuse Prism\\Prism\\Prism;\nuse Prism\\Prism\\ValueObjects\\Messages\\AssistantMessage;\nuse Prism\\Prism\\ValueObjects\\Messages\\UserMessage;\n\n/*\n|--------------------------------------------------------------------------\n| Web Routes\n|--------------------------------------------------------------------------\n|\n| Here is where you can register web routes for your application. These\n| routes are loaded by the RouteServiceProvider within a group which\n| contains the \"web\" middleware group. Now create something great!\n|\n*/\n\nRoute::get('/', function () {\n    return inertia('Home');\n});\n\nRoute::get('/users', function () {\n    sleep(2);\n\n    return inertia('Users', [\n        'date' => now()->toDateTimeString(),\n        'users' => collect([\n            [\n                'id' => 1,\n                'name' => 'Jonathan Reinink',\n                'email' => 'jonathan@example.com',\n            ],\n            [\n                'id' => 2,\n                'name' => 'Adam Wathan',\n                'email' => 'adam@example.com',\n            ],\n            [\n                'id' => 3,\n                'name' => 'Taylor Otwell',\n                'email' => 'taylor@example.com',\n            ],\n            [\n                'id' => 4,\n                'name' => 'Jordan Pittman',\n                'email' => 'jordan@example.com',\n            ],\n            [\n                'id' => 5,\n                'name' => 'Jess Archer',\n                'email' => 'jess@example.com',\n            ],\n            [\n                'id' => 6,\n                'name' => 'Claudio Dekker',\n                'email' => 'claudio@example.com',\n            ],\n            [\n                'id' => 7,\n                'name' => 'Sebastian De Deyne',\n                'email' => 'sebastian@example.com',\n            ],\n            [\n                'id' => 8,\n                'name' => 'Pedro Borges',\n                'email' => 'pedro@example.com',\n            ],\n        ])->shuffle()->values(),\n    ]);\n});\n\nRoute::get('/users/2', function () {\n    sleep(2);\n\n    return inertia('Users', [\n        'date' => now()->toDateTimeString(),\n        'users' => [\n            [\n                'id' => 1,\n                'name' => 'Jonathan Reinink',\n                'email' => 'jonathan@example.com',\n            ],\n            [\n                'id' => 2,\n                'name' => 'Adam Wathan',\n                'email' => 'adam@example.com',\n            ],\n            [\n                'id' => 3,\n                'name' => 'Taylor Otwell',\n                'email' => 'taylor@example.com',\n            ],\n            [\n                'id' => 4,\n                'name' => 'Jordan Pittman',\n                'email' => 'jordan@example.com',\n            ],\n            [\n                'id' => 5,\n                'name' => 'Jess Archer',\n                'email' => 'jess@example.com',\n            ],\n            [\n                'id' => 6,\n                'name' => 'Claudio Dekker',\n                'email' => 'claudio@example.com',\n            ],\n            [\n                'id' => 7,\n                'name' => 'Sebastian De Deyne',\n                'email' => 'sebastian@example.com',\n            ],\n            [\n                'id' => 8,\n                'name' => 'Pedro Borges',\n                'email' => 'pedro@example.com',\n            ],\n        ],\n    ]);\n});\n\nRoute::get('/article', function () {\n    Inertia::encryptHistory();\n\n    return inertia('Article');\n});\n\nRoute::get('/form', function () {\n    return inertia('Form');\n});\n\nRoute::get('/form-component', function () {\n    return inertia('FormComponent', [\n        'foo' => fn () => now()->getTimestampMs(),\n        'bar' => fn () => now()->getTimestampMs(),\n        'quux' => fn () => now()->getTimestampMs(),\n    ]);\n});\n\nRoute::post('/form-component', function () {\n    $data = request()->validateWithBag('custom-bag', [\n        'name' => ['required', 'string', 'max:255'],\n        'avatar' => ['nullable', 'file', 'image', 'max:2048'],\n        'skills' => ['nullable', 'array', 'min:2'],\n        'skills.*' => ['string', 'in:vue,react,laravel,tailwind'],\n        'tags' => ['nullable', 'array'],\n        'tags.*' => ['string', 'max:50'],\n        'user.address.street' => ['nullable', 'string', 'max:255'],\n        'user.address.city' => ['nullable', 'string', 'max:255'],\n    ]);\n\n    // Simulate file upload progress\n    if (request()->hasFile('avatar')) {\n        sleep(1);\n    }\n\n    return back();\n});\n\nRoute::get('/form-component/precognition', function () {\n    return inertia('FormComponentPrecognition');\n});\n\nRoute::post('/form-component/precognition', function (PrecognitionFormRequest $request) {\n    $data = $request->validated();\n\n    // dd($data);\n\n    return back();\n})->middleware([HandlePrecognitiveRequests::class]);\n\nRoute::post('/user', function () {\n    return inertia('User', [\n        'user' => request()->validate([\n            'name' => ['required'],\n            'company' => ['required'],\n            'role' => ['required', 'in:User,Admin,Super'],\n        ]),\n    ]);\n});\n\nRoute::get('/login', function () {\n    return inertia('Login');\n});\n\nRoute::get('/async', function () {\n    return inertia('Async', [\n        'sleep' => Inertia::lazy(function () {\n            sleep(4);\n        }),\n        'jonathan' => Cache::get('jonathan', false),\n        'taylor' => Cache::get('taylor', false),\n        'joe' => Cache::get('joe', false),\n    ]);\n});\n\nRoute::post('/messages', function (Request $request) {\n    $data = $request->validate([\n        'message' => ['required', 'string'],\n    ]);\n\n    // Store the new user message\n    $prompt = ChatMessage::create([\n        'type' => 'prompt',\n        'content' => $data['message'],\n    ]);\n\n    $messages = ChatMessage::latest('id')\n        ->limit(10)\n        ->get()\n        ->reverse()\n        ->map(function (ChatMessage $message) use ($prompt) {\n            $content = $message->content;\n\n            if ($message->is($prompt)) {\n                // Tell LLM not to answer too long and don't halucinate\n                $content = \"Answer in max. 10 sentences, may be shorter. Code examples allowed when needed. Don't hallucinate, just answer based on the provided context.\\n\\n\".$content;\n            }\n\n            return $message->type === 'prompt'\n                ? new UserMessage($content)\n                : new AssistantMessage($content);\n        })\n        ->all();\n\n    // Create a streaming response from the LLM\n    $stream = Prism::text()\n        ->using(Provider::Ollama, 'gemma3:4b')\n        ->withMessages($messages)\n        ->asStream();\n\n    return response()->stream(function () use ($stream) {\n        $response = '';\n\n        foreach ($stream as $chunk) {\n            $response .= $chunk->text;\n            echo $chunk->text;\n            ob_flush();\n            flush();\n        }\n\n        if (! blank($response)) {\n            ChatMessage::create([\n                'type' => 'response',\n                'content' => $response,\n            ]);\n        }\n    }, 200, ['X-Accel-Buffering' => 'no']);\n});\n\nRoute::get('/chat', function () {\n    if (request()->header('X-Inertia-Partial-Component')) {\n        // Simulate latency for partial reloads\n        usleep(500_000);\n    }\n\n    return inertia('Chat', [\n        'messages' => Inertia::scroll(ChatMessage::latest('id')->cursorPaginate(10)),\n    ]);\n});\n\nRoute::get('/photo-grid/{horizontal?}', function ($horizontal = null) {\n    if (request()->header('X-Inertia-Partial-Component')) {\n        // Simulate latency for partial reloads\n        usleep(250_000);\n    }\n\n    $perPage = 24;\n    $pages = 30;\n    $total = $perPage * $pages;\n    $page = request()->integer('page', 1);\n\n    $photos = collect()\n        ->range(1, $total)\n        ->forPage($page, $perPage)\n        ->map(fn ($i) => [\n            'id' => $i,\n            'url' => \"https://picsum.photos/id/{$i}/300/300\",\n        ])\n        ->pipe(fn ($photos) => new LengthAwarePaginator(\n            $photos->values(),\n            $total,\n            $perPage,\n            $page,\n        ));\n\n    return inertia($horizontal ? 'PhotoHorizontal' : 'PhotoGrid', [\n        'photos' => Inertia::scroll($photos),\n    ]);\n});\n\nRoute::get('/data-table', function () {\n    if (request()->header('X-Inertia-Partial-Component')) {\n        // Simulate latency for partial reloads\n        usleep(500_000);\n    }\n\n    $perPage = 200;\n    $pages = 30;\n    $total = $perPage * $pages;\n    $page = request()->integer('page', 1);\n\n    $users = collect()\n        ->range(1, $total)\n        ->forPage($page, $perPage)\n        ->map(fn ($i) => [\n            'id' => $i,\n            'name' => \"User {$i}\",\n        ])\n        ->pipe(fn ($photos) => new LengthAwarePaginator(\n            $photos->values(),\n            $total,\n            $perPage,\n            $page,\n        ));\n\n    return inertia('DataTable', [\n        'users' => Inertia::scroll($users),\n    ]);\n});\n\n// @deprecated - We now have a InfiniteScroll component and Inertia::scroll() method...\nRoute::get('/infinite-scroll', function () {\n    $page = request()->integer('page', 1);\n    $perPage = 25;\n    $start = ($page - 1) * $perPage;\n    $end = $start + $perPage;\n    $itemTypes = ['user', 'food', 'animal', 'plant'];\n    $itemType = request()->input('item_type', $itemTypes[0]);\n\n    return inertia('InfiniteScroll', [\n        'items' => Inertia::defer(\n            function () use ($start, $end, $itemType) {\n                sleep(1);\n\n                return collect(range($start, $end))->map(fn ($i) => [\n                    'id' => $i,\n                    'name' => ucwords($itemType).' '.$i,\n                ])->toArray();\n            }\n        )->merge(),\n        'page' => $page,\n        'item_type' => $itemType,\n        'item_types' => $itemTypes,\n    ]);\n});\n\nRoute::post('/async/checkbox', function () {\n    sleep(2);\n    $previousJoe = Cache::get('joe', false);\n\n    Cache::put('jonathan', request('jonathan'), 10);\n    Cache::put('taylor', request('taylor'), 10);\n    Cache::put('joe', request('joe'), 10);\n\n    if (! $previousJoe && request()->boolean('joe')) {\n        return redirect('article');\n    }\n\n    return redirect('/async');\n});\n\nRoute::get('/defer', function () {\n    info('defer route');\n\n    return inertia('Defer', [\n        'users' => Inertia::defer(function () {\n            sleep(1);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => 'Jonathan Reinink',\n                    'email' => 'hello@reinink.com',\n                ],\n                [\n                    'id' => 2,\n                    'name' => 'Taylor Otwell',\n                    'email' => 'howdy@otwell.biz',\n                ],\n                [\n                    'id' => 3,\n                    'name' => 'Joe Tannenbaum',\n                    'email' => 'yo@tannenbaum.edu',\n                ],\n            ];\n        }, 'u'),\n        'foods' => Inertia::defer(function () {\n            sleep(3);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => 'Pizza',\n                ],\n                [\n                    'id' => 2,\n                    'name' => 'Tacos',\n                ],\n                [\n                    'id' => 3,\n                    'name' => 'Sushi',\n                ],\n            ];\n        }, 'f'),\n        'organizations' => Inertia::defer(function () {\n            sleep(2);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => 'InertiaJS',\n                    'url' => 'https://inertiajs.com',\n                ],\n                [\n                    'id' => 2,\n                    'name' => 'Laravel',\n                    'url' => 'https://laravel.com',\n                ],\n                [\n                    'id' => 3,\n                    'name' => 'VueJS',\n                    'url' => 'https://vuejs.org',\n                ],\n            ];\n        }, 'o'),\n        'surprise' => Inertia::optional(function () {\n            sleep(2);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => 'Surprise!',\n                ],\n                [\n                    'id' => 2,\n                    'name' => 'Aha!',\n                ],\n                [\n                    'id' => 3,\n                    'name' => 'Gotcha!',\n                ],\n                [\n                    'id' => 4,\n                    'name' => '👋!',\n                ],\n            ];\n        }),\n        'dogs' => Inertia::optional(function () {\n            sleep(1);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => '🐕',\n                ],\n                [\n                    'id' => 2,\n                    'name' => '🐩',\n                ],\n                [\n                    'id' => 3,\n                    'name' => '🐶',\n                ],\n            ];\n        }),\n        'lunch' => Inertia::optional(function () {\n            sleep(1);\n\n            return [\n                [\n                    'id' => 1,\n                    'name' => '🍔',\n                ],\n                [\n                    'id' => 2,\n                    'name' => '🍟',\n                ],\n                [\n                    'id' => 3,\n                    'name' => '🥤',\n                ],\n            ];\n        }),\n    ]);\n});\n\nRoute::get('/goodbye', function () {\n    return Inertia::location('https://inertiajs.com/redirects');\n});\n\nRoute::get('/poll', function () {\n    return inertia('Poll', [\n        'users' => collect([\n            'Jonathan Reinink',\n            'Taylor Otwell',\n            'Joe Tannenbaum',\n            'Jess Archer',\n            'Claudio Dekker',\n            'Sebastian De Deyne',\n            'Pedro Borges',\n        ])->shuffle()->take(3)->values(),\n        'companies' => collect([\n            'InertiaJS',\n            'Laravel',\n            'VueJS',\n            'Tailwind CSS',\n            'AlpineJS',\n            'Livewire',\n            'Spatie',\n        ])->shuffle()->take(3)->values(),\n    ]);\n});\n\nRoute::get('/elsewhere', function () {\n    return inertia('Users');\n});\n\nRoute::get('/sleepy/{duration}', function ($duration) {\n    sleep($duration);\n\n    return inertia('Users');\n});\n\nRoute::post('/sleepy/{duration}', function ($duration) {\n    sleep($duration);\n\n    return inertia('Article');\n});\n\nRoute::post('/logout', function () {\n    return redirect('/login');\n});\n\n\nRoute::get('/flash', function () {\n    return inertia('Flash');\n});\n\nRoute::get('/flash/direct', function () {\n    return Inertia::flash('message', 'Sent with render!')->render('Flash');\n});\n\nRoute::post('/flash/form', function () {\n    return Inertia::flash('message', 'Sent with redirect!')->back();\n});\n\nRoute::get('/once/{page}', function (int $page) {\n    $component = match ($page) {\n        1 => 'Once/First',\n        2 => 'Once/Second',\n        3 => 'Once/Third',\n        4 => 'Once/Fourth',\n        default => abort(404),\n    };\n\n    return inertia($component, [\n        'foo' => Inertia::once(fn () => 'foo value: '.now()->getTimestampMs())->fresh($page === 3),\n        'bar' => Inertia::once(fn () => 'bar value: '.now()->getTimestampMs())->until(10),\n        'baz' . $page => Inertia::once(fn () => 'baz value: '.now()->getTimestampMs())->as('baz'),\n        'qux' => Inertia::defer(fn () => 'qux value: '.now()->getTimestampMs())->once(),\n    ]);\n});"
  },
  {
    "path": "playgrounds/vue3/storage/app/.gitignore",
    "content": "*\n!public/\n!.gitignore\n"
  },
  {
    "path": "playgrounds/vue3/storage/framework/.gitignore",
    "content": "compiled.php\nconfig.php\ndown\nevents.scanned.php\nmaintenance.php\nroutes.php\nroutes.scanned.php\nschedule-*\nservices.json\n"
  },
  {
    "path": "playgrounds/vue3/storage/framework/cache/.gitignore",
    "content": "*\n!data/\n!.gitignore\n"
  },
  {
    "path": "playgrounds/vue3/storage/framework/sessions/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/vue3/storage/framework/testing/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/vue3/storage/framework/views/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/vue3/storage/logs/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "playgrounds/vue3/tests/CreatesApplication.php",
    "content": "<?php\n\nnamespace Tests;\n\nuse Illuminate\\Contracts\\Console\\Kernel;\n\ntrait CreatesApplication\n{\n    /**\n     * Creates the application.\n     *\n     * @return \\Illuminate\\Foundation\\Application\n     */\n    public function createApplication()\n    {\n        $app = require __DIR__.'/../bootstrap/app.php';\n\n        $app->make(Kernel::class)->bootstrap();\n\n        return $app;\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/tests/Feature/ExampleTest.php",
    "content": "<?php\n\nnamespace Tests\\Feature;\n\n// use Illuminate\\Foundation\\Testing\\RefreshDatabase;\nuse Tests\\TestCase;\n\nclass ExampleTest extends TestCase\n{\n    /**\n     * A basic test example.\n     *\n     * @return void\n     */\n    public function test_the_application_returns_a_successful_response()\n    {\n        $response = $this->get('/');\n\n        $response->assertStatus(200);\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/tests/TestCase.php",
    "content": "<?php\n\nnamespace Tests;\n\nuse Illuminate\\Foundation\\Testing\\TestCase as BaseTestCase;\n\nabstract class TestCase extends BaseTestCase\n{\n    use CreatesApplication;\n}\n"
  },
  {
    "path": "playgrounds/vue3/tests/Unit/ExampleTest.php",
    "content": "<?php\n\nnamespace Tests\\Unit;\n\nuse PHPUnit\\Framework\\TestCase;\n\nclass ExampleTest extends TestCase\n{\n    /**\n     * A basic test example.\n     *\n     * @return void\n     */\n    public function test_that_true_is_true()\n    {\n        $this->assertTrue(true);\n    }\n}\n"
  },
  {
    "path": "playgrounds/vue3/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Node\",\n    \"jsx\": \"preserve\",\n    \"strict\": true,\n    \"isolatedModules\": true,\n    \"target\": \"ESNext\",\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noEmit\": true,\n    \"skipLibCheck\": true\n  },\n  \"include\": [\"resources/js/**/*.ts\", \"resources/js/**/*.d.ts\", \"resources/js/**/*.vue\"]\n}\n"
  },
  {
    "path": "playgrounds/vue3/vite.config.ts",
    "content": "import tailwindcss from '@tailwindcss/vite'\nimport vue from '@vitejs/plugin-vue'\nimport laravel from 'laravel-vite-plugin'\nimport { defineConfig } from 'vite'\n\nexport default defineConfig({\n  build: {\n    minify: false,\n  },\n  plugins: [\n    laravel({\n      input: ['resources/css/app.css', 'resources/js/app.ts'],\n      ssr: 'resources/js/ssr.ts',\n      refresh: true,\n    }),\n    vue({\n      template: {\n        transformAssetUrls: {\n          base: null,\n          includeAbsolute: false,\n        },\n      },\n    }),\n    tailwindcss(),\n  ],\n})\n"
  },
  {
    "path": "playwright.config.ts",
    "content": "import { defineConfig, devices } from '@playwright/test'\n\n// define process env for TS\ndeclare const process: {\n  argv: string[]\n  env: {\n    BROWSER?: 'chromium' | 'webkit' | 'firefox'\n    CI?: boolean\n    PACKAGE?: 'vue3' | 'react' | 'svelte'\n    SSR?: 'true'\n  }\n  platform: string\n}\n\nconst adapter = process.env.PACKAGE || 'vue3'\nconst runsInCI = !!process.env.CI\nconst runsOnMac = process.platform === 'darwin'\nconst ssrEnabled = process.env.SSR === 'true'\n\nconst adapterPorts = { vue3: 13715, react: 13716, svelte: 13717 }\nconst url = `http://localhost:${adapterPorts[adapter]}`\n\nconst adapters = ['react', 'svelte', 'vue3']\n\nif (!adapters.includes(adapter)) {\n  throw new Error(`Invalid adapter package \"${adapter}\". Expected one of: ${adapters.join(', ')}.`)\n}\n\n// Always define all projects, but can be overridden via --webkit or --firefox flags\nconst projects = [\n  {\n    name: 'chromium',\n    use: { ...devices['Desktop Chrome'] },\n  },\n  {\n    name: 'webkit',\n    use: { ...devices['Desktop Safari'] },\n  },\n  {\n    name: 'firefox',\n    use: { ...devices['Desktop Firefox'] },\n  },\n]\n\n/**\n * Read environment variables from file.\n * https://github.com/motdotla/dotenv\n */\n// import dotenv from 'dotenv';\n// dotenv.config({ path: path.resolve(__dirname, '.env') });\n\n/**\n * See https://playwright.dev/docs/test-configuration.\n */\n// Build commands\nconst buildCommand = `pnpm -r --filter './packages/${adapter}/test-app' build`\nconst buildSSRCommand = `pnpm -r --filter './packages/${adapter}/test-app' build:ssr`\nconst serveCommand = `cd tests/app && PACKAGE=${adapter} pnpm serve`\n\n// Web server configuration based on SSR mode\nconst webServerConfig = ssrEnabled\n  ? [\n      {\n        command: `${buildCommand} && ${buildSSRCommand} && node packages/${adapter}/test-app/dist/ssr.js`,\n        url: 'http://localhost:13714/health',\n        reuseExistingServer: !runsInCI,\n      },\n      {\n        command: serveCommand,\n        url,\n        reuseExistingServer: !runsInCI,\n      },\n    ]\n  : {\n      command: `${buildCommand} && ${serveCommand}`,\n      url,\n      reuseExistingServer: !runsInCI,\n    }\n\nexport default defineConfig({\n  testDir: './tests',\n  /* Only run SSR tests when SSR=true, otherwise exclude them */\n  ...(ssrEnabled ? { testMatch: 'ssr.spec.ts' } : { testIgnore: 'ssr.spec.ts' }),\n  /* Run tests in files in parallel */\n  fullyParallel: true,\n  /* Fail the build on CI if you accidentally left test.only in the source code. */\n  forbidOnly: !!runsInCI,\n  /* Retry on CI only */\n  retries: runsInCI ? 2 : 0,\n  /* The GitHub Action runner has 4 cores on Ubuntu and 3 cores on macOS, we need one core for the server */\n  workers: runsInCI ? (runsOnMac ? 2 : 3) : undefined,\n  /* Reporter to use. See https://playwright.dev/docs/test-reporters */\n  //   reporter: 'html',\n  /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */\n  use: {\n    /* Base URL to use in actions like `await page.goto('/')`. */\n    baseURL: url,\n\n    /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */\n    trace: 'on-first-retry',\n\n    /* Collect screenshots on failure */\n    screenshot: 'only-on-failure',\n  },\n\n  timeout: 5 * 1000,\n\n  /* Configure projects for major browsers */\n  projects,\n\n  /* Run your local dev server before starting the tests */\n  webServer: webServerConfig,\n})\n"
  },
  {
    "path": "playwright.js",
    "content": "#!/usr/bin/env node\nimport { spawn } from 'child_process'\n\n// Parse arguments\nconst args = process.argv.slice(2)\nconst webkitIndex = args.indexOf('--webkit')\nconst firefoxIndex = args.indexOf('--firefox')\n\n// Replace --webkit or --firefox with --project <browser>\nif (webkitIndex !== -1) {\n  args.splice(webkitIndex, 1, '--project', 'webkit')\n} else if (firefoxIndex !== -1) {\n  args.splice(firefoxIndex, 1, '--project', 'firefox')\n} else {\n  // Default to chromium if no browser flag\n  args.unshift('--project', 'chromium')\n}\n\n// Run playwright with modified args\nconst playwright = spawn('npx', ['playwright', 'test', ...args], {\n  env: process.env,\n  stdio: 'inherit',\n})\n\nplaywright.on('close', (code) => {\n  process.exit(code)\n})\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - packages/*\n  - packages/*/test-app\n  - playgrounds/*\n  - tests/app\n\nonlyBuiltDependencies:\n  - '@tailwindcss/oxide'\n  - esbuild\n"
  },
  {
    "path": "prettier.config.js",
    "content": "export default {\n  printWidth: 120,\n  semi: false,\n  singleQuote: true,\n  tabWidth: 2,\n  trailingComma: 'all',\n  plugins: ['prettier-plugin-svelte', 'prettier-plugin-organize-imports', 'prettier-plugin-tailwindcss'],\n  endOfLine: 'lf',\n  overrides: [\n    {\n      files: '*.svelte',\n      options: {\n        parser: 'svelte',\n      },\n    },\n    {\n      files: 'composer.json',\n      options: {\n        tabWidth: 4,\n      },\n    },\n  ],\n}\n"
  },
  {
    "path": "release.sh",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\n# Ensure we are on master and the working tree is clean\nCURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)\nif [ \"$CURRENT_BRANCH\" != \"master\" ]; then\n  echo \"Error: must be on master branch (current: $CURRENT_BRANCH)\" >&2\n  exit 1\nfi\n\nif [ -n \"$(git status --porcelain)\" ]; then\n  echo \"Error: working tree is not clean. Commit or stash changes before releasing.\" >&2\n  git status --porcelain\n  exit 1\nfi\n\necho\necho \"Current version: $(node -p \"require('./package.json').version\")\"\necho\n\necho \"Select version bump type:\"\necho \"1) patch (bug fixes)\"\necho \"2) minor (new features)\"\necho \"3) major (breaking changes)\"\necho\n\nread -p \"Enter your choice (1-3): \" choice\n\ncase $choice in\n    1)\n        RELEASE_TYPE=\"patch\"\n        ;;\n    2)\n        RELEASE_TYPE=\"minor\"\n        ;;\n    3)\n        RELEASE_TYPE=\"major\"\n        ;;\n    *)\n        echo \"❌ Invalid choice. Exiting.\"\n        exit 1\n        ;;\nesac\n\n# Bump version in each package without creating git tags\nNEW_VERSION=\"\"\nfor pkg_json in packages/*/package.json; do\n  pkg_dir=$(dirname \"$pkg_json\")\n  echo \"Bumping $pkg_dir to $RELEASE_TYPE...\"\n  cd \"$pkg_dir\"\n  echo \"Current directory: $(pwd)\"\n  OUT=$(pnpm version \"$RELEASE_TYPE\" --no-git-tag-version)\n  if [ -z \"$NEW_VERSION\" ]; then\n    # Capture the first reported version; strip leading 'v' if present\n    OUT_LAST=$(echo \"$OUT\" | tail -n1 | tr -d '\\r')\n    NEW_VERSION=${OUT_LAST#v}\n  fi\n  cd ..\n  cd ..\ndone\n\nTAG=\"v$NEW_VERSION\"\necho \"New version resolved as $TAG\"\n\npnpm install\n\n# Commit changes and create tag\ngit add .\ngit commit -m \"$TAG\"\ngit tag -a \"$TAG\" -m \"$TAG\"\ngit push\ngit push --tags\n\ngh release create \"$TAG\" --generate-notes\n\necho \"\"\necho \"✅ Release $TAG completed successfully, publishing kicked off in CI.\"\necho \"🔗 https://github.com/inertiajs/inertia/releases/tag/$TAG\"\n"
  },
  {
    "path": "tests/app/eloquent.js",
    "content": "function makeUser(id) {\n  return {\n    id,\n    name: `User ${id}`,\n  }\n}\n\nexport function getUserNames() {\n  return [\n    'Adelle Crona DVM',\n    'Alison Walter PhD',\n    'Aliza Langosh II',\n    'Amara DuBuque',\n    'Amaya Lang',\n    'Angelica Rodriguez',\n    'Anjali Windler',\n    'Ansley Gusikowski',\n    'Asha Welch II',\n    'Bailee Zulauf',\n    'Barrett Heathcote',\n    'Beryl Morar',\n    'Bethany Grant',\n    'Braden Mayert II',\n    'Breana Herzog',\n    'Camylle Metz Sr.',\n    'Carmen Kerluke',\n    'Casimer McClure',\n    'Cecil Walsh',\n    'Chandler McKenzie',\n    'Chaya Rempel',\n    'Chelsey Mertz Jr.',\n    'Coralie Auer',\n    'Daniella Hoppe',\n    'Daphnee Douglas',\n    'Davonte Heathcote',\n    'Dejah Parisian',\n    'Demarco Medhurst',\n    'Dewayne Rau',\n    'Diamond Gibson PhD',\n    'Diamond Herzog',\n    'Dino Predovic I',\n    'Domingo Luettgen',\n    'Dora Runolfsdottir',\n    'Dr. Billy Larkin',\n    'Dr. Chase Green',\n    'Dr. Curtis Lehner',\n    'Einar Crona MD',\n    'Eloisa Pollich',\n    'Elsie Goldner',\n    'Emma Little Sr.',\n    'Erika Ziemann DDS',\n    'Ethan Beatty',\n    'Euna Boehm',\n    'Euna Kerluke',\n    'Felton Yost',\n    'Genesis Hand',\n    'Hailie Quitzon',\n    'Helga Waelchi',\n    'Ibrahim Jakubowski',\n    'Jack Halvorson',\n    'Jasmin Stoltenberg',\n    'Jennie Olson PhD',\n    'Jimmy Gusikowski',\n    'Joy Schimmel',\n    'Kamron Bechtelar DDS',\n    'Katarina McLaughlin',\n    'Katharina Towne',\n    'Kavon Sporer',\n    'Keshawn Langosh DDS',\n    'Lacy Johnston V',\n    'Lauren Thiel',\n    'Lelia Haley',\n    'Lonny Hermiston',\n    'Lupe Jacobs',\n    'Magdalena Rowe',\n    'Marjolaine Gleason',\n    'Mattie Bradtke',\n    'Miss Amiya Altenwerth',\n    'Miss Haven Kuhic',\n    'Miss Janie Bayer',\n    'Miss Raegan Doyle IV',\n    'Molly Murray',\n    'Niko Christiansen Jr.',\n    'Paxton Koss',\n    'Reilly Bechtelar',\n    'Rex Blanda',\n    'Riley Legros',\n    'River Pfeffer',\n    'Rory Lubowitz',\n    'Rosamond Mueller II',\n    'Rosario Nicolas Sr.',\n    'Sandrine Hammes',\n    'Tad Thompson',\n    'Talon Fahey DVM',\n    'Taylor Kuhlman IV',\n    'Tyler Zieme',\n    'Vella Price',\n    'Virginie Beatty',\n    'Wiley Donnelly',\n    'Woodrow Kuvalis',\n  ]\n}\n\nfunction getUsers(page = 1, perPage = 15, total = 40, orderByDesc = false) {\n  // orderByDesc = false\n  // page = 1 => User 1 ... 15, page = 3 => User 31 ... 40\n\n  // orderByDesc = true\n  // page = 1 => User 40 ... 26, page = 3 => User 10 ... 1\n\n  if (orderByDesc) {\n    const start = total - (page - 1) * perPage\n    const end = Math.max(start - perPage + 1, 1)\n\n    const users = []\n    for (let i = start; i >= end; i--) {\n      users.push(makeUser(i))\n    }\n\n    return users\n  } else {\n    const start = (page - 1) * perPage + 1\n    const end = Math.min(start + perPage - 1, total)\n\n    const users = []\n    for (let i = start; i <= end; i++) {\n      users.push(makeUser(i))\n    }\n\n    return users\n  }\n}\n\nexport function paginateUsers(page = 1, perPage = 15, total = 40, orderByDesc = false, pageName = 'page') {\n  const users = getUsers(page, perPage, total, orderByDesc)\n  const hasMore = getUsers(page + 1, perPage, total, orderByDesc).length > 0\n\n  return {\n    paginated: {\n      current_page: page,\n      data: users,\n      per_page: perPage,\n      to: users[users.length - 1]?.id || null,\n      total,\n    },\n    scrollProp: {\n      pageName,\n      previousPage: page > 1 ? page - 1 : null,\n      nextPage: hasMore ? page + 1 : null,\n      currentPage: page,\n      reset: false,\n    },\n  }\n}\n"
  },
  {
    "path": "tests/app/helpers.js",
    "content": "const path = require('path')\nconst fs = require('fs')\n\nconst package = process.env.PACKAGE || 'vue3'\n\nconst ssr = require('./ssr')\n\nconst buildPageData = (req, data) => ({\n  component: req.path\n    .slice(1)\n    .split('/')\n    .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n    .join('/')\n    .split('-')\n    .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n    .join(''),\n  props: {},\n  url: req.originalUrl,\n  version: null,\n  ...data,\n})\n\nmodule.exports = {\n  package,\n  render: (req, res, data) => {\n    data = buildPageData(req, data)\n\n    if (data.component.startsWith('InfiniteScroll') && req.query.absolutePageUrl) {\n      // Support absolute URL format for testing URL preservation\n      const protocol = req.protocol\n      const host = req.get('host')\n      data.url = `${protocol}://${host}${req.originalUrl}`\n    }\n\n    const partialDataHeader = req.headers['x-inertia-partial-data'] || ''\n    const partialExceptHeader = req.headers['x-inertia-partial-except'] || ''\n    const partialComponentHeader = req.headers['x-inertia-partial-component'] || ''\n\n    const isPartial = partialComponentHeader && partialComponentHeader === data.component\n\n    data.props = Object.keys(data.props)\n      .filter((key) => !isPartial || !partialDataHeader || partialDataHeader.split(',').indexOf(key) > -1)\n      .filter((key) => !isPartial || !partialExceptHeader || partialExceptHeader.split(',').indexOf(key) == -1)\n      .reduce((carry, key) => {\n        carry[key] = typeof data.props[key] === 'function' ? data.props[key](data.props) : data.props[key]\n\n        return carry\n      }, {})\n\n    if (req.get('X-Inertia')) {\n      res.header('Vary', 'Accept')\n      res.header('X-Inertia', true)\n      return res.status(200).json(data)\n    }\n\n    return res.status(200).send(\n      fs\n        .readFileSync(path.resolve(__dirname, '../../packages/', package, 'test-app/dist/index.html'))\n        .toString()\n        .replace('{{ headAttribute }}', data.component === 'Head/Dataset' ? 'data-inertia' : 'inertia')\n        .replace(\"'{{ placeholder }}'\", JSON.stringify(data)),\n    )\n  },\n  renderSSR: async (req, res, data) => {\n    data = buildPageData(req, data)\n\n    if (req.get('X-Inertia')) {\n      res.header('Vary', 'Accept')\n      res.header('X-Inertia', true)\n      return res.status(200).json(data)\n    }\n\n    const ssrResult = await ssr.render(data)\n    const htmlTemplate = fs\n      .readFileSync(path.resolve(__dirname, '../../packages/', package, 'test-app/dist/index.html'))\n      .toString()\n\n    const headContent = ssrResult.head ? ssrResult.head.join('\\n    ') : ''\n\n    const html = htmlTemplate\n      .replace('{{ headAttribute }}', 'inertia')\n      .replace(/<script>\\s*window\\.initialPage = '{{ placeholder }}'\\s*<\\/script>/, headContent)\n      .replace('<div id=\"app\"></div>', ssrResult.body)\n\n    return res.status(200).send(html)\n  },\n  location: (res, href) => res.status(409).header('X-Inertia-Location', href).send(''),\n}\n"
  },
  {
    "path": "tests/app/package.json",
    "content": "{\n  \"private\": true,\n  \"scripts\": {\n    \"serve\": \"node server.js\",\n    \"serve:watch\": \"nodemon server.js\"\n  },\n  \"devDependencies\": {\n    \"body-parser\": \"^2.2.2\",\n    \"express\": \"^5.2.1\",\n    \"multer\": \"^2.1.1\",\n    \"nodemon\": \"^3.1.14\"\n  }\n}\n"
  },
  {
    "path": "tests/app/server-status.js",
    "content": "const fs = require('fs')\nconst os = require('os')\nconst path = require('path')\n\nfunction showServerStatus(packageName, port) {\n  const url = `http://localhost:${port}/`\n  const flagFile = path.join(os.tmpdir(), `inertia-${packageName}-${port}.flag`)\n  const isFirstRun = !fs.existsSync(flagFile)\n\n  // Clean up flag file on Ctrl+C (but not on regular exit to allow nodemon restarts)\n  process.on('SIGINT', () => {\n    try {\n      if (fs.existsSync(flagFile)) {\n        fs.unlinkSync(flagFile)\n      }\n    } catch (err) {\n      // Ignore cleanup errors\n    }\n    process.exit(0)\n  })\n\n  if (isFirstRun) {\n    fs.writeFileSync(flagFile, '')\n\n    console.log('\\n' + '═'.repeat(80))\n    console.log('║' + ' '.repeat(78) + '║')\n    console.log('║' + ' 🚀 INERTIA.JS TEST SERVER '.padEnd(78) + '║')\n    console.log('║' + ' '.repeat(78) + '║')\n    console.log('║' + ` 📦 Package: ${packageName}`.padEnd(78) + '║')\n    console.log('║' + ` 🔗 URL: ${url}`.padEnd(78) + '║')\n    console.log('║' + ' '.repeat(78) + '║')\n    console.log('═'.repeat(80) + '\\n')\n  } else {\n    console.log(`🔄 Server restarted - ${packageName} test app still running on ${url}`)\n  }\n}\n\nmodule.exports = { showServerStatus }\n"
  },
  {
    "path": "tests/app/server.js",
    "content": "const path = require('path')\nconst express = require('express')\nconst inertia = require('./helpers')\nconst bodyParser = require('body-parser')\nconst multer = require('multer')\nconst { showServerStatus } = require('./server-status')\nconst { getUserNames, paginateUsers } = require('./eloquent')\n\nconst app = express()\n\n// Express v5 defaults to 'simple' query parser, but tests expect 'extended' behavior from < v5\napp.set('query parser', 'extended')\n\napp.use(bodyParser.urlencoded({ extended: true }))\napp.use(bodyParser.json())\nconst upload = multer()\n\nconst adapters = ['react', 'svelte', 'vue3']\n\nif (!adapters.includes(inertia.package)) {\n  throw new Error(`Invalid adapter package \"${inertia.package}\". Expected one of: ${adapters.join(', ')}.`)\n}\n\napp.all('/non-inertia', (req, res) =>\n  res.status(200).send(`\n    <!DOCTYPE html>\n    <html>\n      <head><title>Non-Inertia Page</title></head>\n      <body>\n        <h1>This is a page that does not have the Inertia app loaded.</h1>\n        <p><a href=\"/navigate-non-inertia\">Go to Inertia page</a></p>\n      </body>\n    </html>\n  `),\n)\n\napp.get('/non-inertia/download', (req, res) => {\n  const query = new URLSearchParams(req.query).toString()\n  res.setHeader('Content-Type', 'text/plain')\n  res.status(200).send(`query:${query}`)\n})\n\n// SSR test routes (only rendered with SSR when SSR=true)\napp.get('/ssr/page1', (req, res) =>\n  inertia.renderSSR(req, res, {\n    component: 'SSR/Page1',\n    props: {\n      user: { name: 'John Doe', email: 'john@example.com' },\n      items: ['Item 1', 'Item 2', 'Item 3'],\n      count: 42,\n    },\n  }),\n)\n\napp.get('/ssr/page2', (req, res) =>\n  inertia.renderSSR(req, res, {\n    component: 'SSR/Page2',\n    props: {\n      navigatedTo: true,\n    },\n  }),\n)\n\napp.get('/ssr/page-with-script-element', (req, res) =>\n  inertia.renderSSR(req, res, {\n    component: 'SSR/PageWithScriptElement',\n    props: {\n      message: 'Hello from script element! Escape </script>.',\n    },\n  }),\n)\n\n// Intercepts all CSS and JS assets (including files loaded via code splitting)\napp.get(/.*\\.(?:js|css)$/, (req, res) => {\n  const filePath = path.resolve(__dirname, '../../packages/', inertia.package, 'test-app/dist', req.path.substring(1))\n  res.sendFile(filePath, (err) => {\n    if (err) {\n      res.status(404).send('Not found')\n    }\n  })\n})\n\n/**\n * Used for testing the Inertia plugin is registered.\n * @see plugin.test.js\n */\napp.get('/plugin/*enabled', (req, res) =>\n  inertia.render(req, res, {\n    component: 'Home',\n    props: {\n      example: 'FooBar',\n    },\n  }),\n)\n\n/**\n * Our actual 'app' routes\n */\napp.get('/', (req, res) =>\n  inertia.render(req, res, {\n    component: 'Home',\n    props: {\n      example: 'FooBar',\n    },\n  }),\n)\n\napp.get('/article', (req, res) =>\n  inertia.render(req, res, {\n    component: 'Article',\n    props: {},\n    encryptHistory: true,\n  }),\n)\n\napp.get('/scroll-after-render/:page', (req, res) =>\n  inertia.render(req, res, {\n    component: 'ScrollAfterRender',\n    props: { page: parseInt(req.params.page) },\n  }),\n)\n\napp.get('/scroll-smooth/:page', (req, res) =>\n  inertia.render(req, res, {\n    component: 'ScrollSmooth',\n    props: { page: req.params.page },\n  }),\n)\n\napp.get('/links/partial-reloads', (req, res) =>\n  inertia.render(req, res, {\n    component: 'Links/PartialReloads',\n    props: {\n      headers: req.headers,\n      foo: Number.parseInt(req.query.foo || 0) + 1,\n      bar: (props) => props.foo + 1,\n      baz: (props) => props.foo + 2,\n    },\n  }),\n)\napp.all('/error-modal', (req, res) =>\n  inertia.render(req, res, { component: 'ErrorModal', props: { dialog: !!req.query.dialog } }),\n)\napp.all('/links/preserve-state-page-two', (req, res) =>\n  inertia.render(req, res, { component: 'Links/PreserveState', props: { foo: req.query.foo } }),\n)\napp.all('/links/preserve-scroll-page-two', (req, res) =>\n  inertia.render(req, res, { component: 'Links/PreserveScroll', props: { foo: req.query.foo } }),\n)\napp.all('/links/preserve-scroll-false-page-two', (req, res) =>\n  inertia.render(req, res, { component: 'Links/PreserveScrollFalse', props: { foo: req.query.foo } }),\n)\napp.get('/links/preserve-url', (req, res) => {\n  const page = parseInt(req.query.page || '1')\n  const itemsPerPage = 3\n\n  const allItems = Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`)\n  const startIndex = (page - 1) * itemsPerPage\n  const data = allItems.slice(startIndex, startIndex + itemsPerPage)\n\n  const hasNextPage = startIndex + itemsPerPage < allItems.length\n  const nextPageUrl = hasNextPage ? `/links/preserve-url?page=${page + 1}` : null\n\n  return inertia.render(req, res, {\n    component: 'Links/PreserveUrl',\n    props: {\n      foo: req.query.foo || 'default',\n      items: {\n        data,\n        next_page_url: nextPageUrl,\n      },\n    },\n    deepMergeProps: ['items'],\n  })\n})\napp.all('/links/preserve-url-page-two', (req, res) =>\n  inertia.render(req, res, { component: 'Links/PreserveUrl', props: { foo: req.query.foo } }),\n)\napp.get('/links/as-warning/:method', (req, res) =>\n  inertia.render(req, res, { component: 'Links/AsWarning', props: { method: req.params.method } }),\n)\napp.get('/links/as-warning-false/:method', (req, res) =>\n  inertia.render(req, res, { component: 'Links/AsWarningFalse', props: { method: req.params.method } }),\n)\napp.get('/links/headers/version', (req, res) =>\n  inertia.render(req, res, { component: 'Links/Headers', version: 'example-version-header' }),\n)\napp.get('/links/data-loading', (req, res) => inertia.render(req, res, { component: 'Links/DataLoading' }))\napp.get('/links/prop-update', (req, res) => inertia.render(req, res, { component: 'Links/PropUpdate' }))\napp.get('/links/sub', (req, res) => inertia.render(req, res, { component: 'Links/PathTraversal' }))\napp.get('/links/sub/sub', (req, res) => inertia.render(req, res, { component: 'Links/PathTraversal' }))\napp.get('/links/reactivity', (req, res) => inertia.render(req, res, { component: 'Links/Reactivity' }))\napp.get('/links/as-component/:page', (req, res) =>\n  inertia.render(req, res, { component: 'Links/AsComponent', props: { page: req.params.page } }),\n)\napp.get('/links/as-element/:page', (req, res) =>\n  inertia.render(req, res, { component: 'Links/AsElement', props: { page: req.params.page } }),\n)\napp.get('/links/cancel-sync-request/:page', (req, res) => {\n  const page = req.params.page\n  setTimeout(\n    () => inertia.render(req, res, { component: 'Links/CancelSyncRequest', props: { page } }),\n    page == 3 ? 500 : 0,\n  )\n})\napp.get('/links/scroll-region-list', (req, res) =>\n  inertia.render(req, res, {\n    component: 'Links/ScrollRegionList',\n    props: { user_id: req.query.user_id },\n    url: req.originalUrl,\n  }),\n)\napp.get('/links/scroll-region-list/user/:id', (req, res) =>\n  res.redirect(303, `/links/scroll-region-list?user_id=${req.params.id}`),\n)\n\napp.get('/scroll-region-preserve-url/:page', (req, res) =>\n  inertia.render(req, res, {\n    component: 'ScrollRegionPreserveUrl',\n    props: { page: parseInt(req.params.page) },\n  }),\n)\n\napp.get('/client-side-visit', (req, res) =>\n  inertia.render(req, res, {\n    component: 'ClientSideVisit/Page1',\n    props: { foo: 'foo from server', bar: 'bar from server' },\n  }),\n)\n\napp.get('/client-side-visit/props', (req, res) =>\n  inertia.render(req, res, {\n    component: 'ClientSideVisit/Props',\n    props: {\n      items: ['item1', 'item2'],\n      tags: [\n        { id: 1, name: 'tag1' },\n        { id: 2, name: 'tag2' },\n      ],\n      user: { name: 'John Doe', age: 30 },\n      count: 5,\n      singleValue: 'hello',\n      undefinedValue: undefined,\n    },\n  }),\n)\n\napp.get('/client-side-visit/sequential', (req, res) =>\n  inertia.render(req, res, {\n    component: 'ClientSideVisit/Sequential',\n    props: {\n      foo: 'foo',\n      bar: 'bar',\n    },\n  }),\n)\n\napp.get('/visits/proxy', (req, res) => {\n  const timeout = req.headers['x-inertia-partial-data'] ? 250 : 0\n  const statuses = ['pending', 'running', 'success', 'failed', 'canceled']\n\n  const sites = [1, 2, 3, 4, 5].map(function (id) {\n    const site = { id }\n\n    site.latestDeployment = { id: id * 10, statuses: [statuses[id % statuses.length]] }\n\n    return site\n  })\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'Visits/Proxy',\n        props: req.headers['x-inertia-partial-data'] === 'sites' ? { sites } : { foo: new Date().toISOString() },\n        deferredProps: req.headers['x-inertia-partial-data'] ? {} : { default: ['sites'] },\n      }),\n    timeout,\n  )\n})\n\napp.post('/visits/proxy', (req, res) => res.redirect(303, '/visits/proxy'))\n\napp.get('/visits/partial-reloads', (req, res) =>\n  inertia.render(req, res, {\n    component: 'Visits/PartialReloads',\n    props: {\n      headers: req.headers,\n      foo: Number.parseInt(req.query.foo || 0) + 1,\n      bar: (props) => props.foo + 1,\n      baz: (props) => props.foo + 2,\n    },\n  }),\n)\napp.all('/visits/preserve-state-page-two', (req, res) =>\n  inertia.render(req, res, { component: 'Visits/PreserveState', props: { foo: req.query.foo } }),\n)\napp.all('/visits/preserve-scroll-page-two', (req, res) =>\n  inertia.render(req, res, { component: 'Visits/PreserveScroll', props: { foo: req.query.foo } }),\n)\napp.all('/visits/preserve-scroll-false-page-two', (req, res) =>\n  inertia.render(req, res, { component: 'Visits/PreserveScrollFalse', props: { foo: req.query.foo } }),\n)\napp.post('/visits/events-errors', (req, res) =>\n  inertia.render(req, res, { component: 'Visits/Events', props: { errors: { foo: 'bar' } } }),\n)\napp.get('/visits/headers/version', (req, res) =>\n  inertia.render(req, res, { component: 'Visits/Headers', version: 'example-version-header' }),\n)\napp.get('/visits/after-error/:page', (req, res) => inertia.render(req, res, { component: 'Visits/AfterError' }))\n\napp.post('/remember/form-helper/default', (req, res) =>\n  inertia.render(req, res, {\n    component: 'Remember/FormHelper/Default',\n    props: { errors: { name: 'Some name error', handle: 'The Handle was invalid' } },\n  }),\n)\napp.post('/remember/form-helper/remember', (req, res) =>\n  inertia.render(req, res, {\n    component: 'Remember/FormHelper/Remember',\n    props: { errors: { name: 'Some name error', handle: 'The Handle was invalid' } },\n  }),\n)\n\napp.post('/form-helper/data', (req, res) =>\n  inertia.render(req, res, {\n    component: 'FormHelper/Data',\n    props: { errors: { name: 'Some name error', handle: 'The Handle was invalid' } },\n  }),\n)\n\napp.post('/form-helper/data/redirect-back', (req, res) => res.redirect(303, '/form-helper/data'))\n\napp.get('/form-helper/nested', (req, res) =>\n  inertia.render(req, res, {\n    component: 'FormHelper/Nested',\n  }),\n)\n\napp.get('/form-helper/dirty', (req, res) =>\n  inertia.render(req, res, {\n    component: 'FormHelper/Dirty',\n    props: {},\n  }),\n)\n\napp.post('/form-helper/effect-count', (req, res) =>\n  inertia.render(req, res, {\n    component: 'FormHelper/EffectCount',\n  }),\n)\n\napp.post('/form-helper/dirty', (req, res) => res.redirect(303, '/form-helper/dirty'))\napp.post('/form-helper/dirty/redirect-back', (req, res) => res.redirect(303, '/form-helper/dirty'))\n\napp.post('/form-helper/errors', (req, res) =>\n  inertia.render(req, res, {\n    component: 'FormHelper/Errors',\n    props: { errors: { name: 'Some name error', handle: 'The Handle was invalid' } },\n  }),\n)\n\napp.get('/form-helper/errors/clear-on-resubmit', (req, res) =>\n  inertia.render(req, res, { component: 'FormHelper/ErrorsClearOnResubmit' }),\n)\n\napp.post('/form-helper/errors/clear-on-resubmit', (req, res) => {\n  const name = req.body['name']\n  const handle = req.body['handle']\n  const errors = {}\n\n  if (!name || name.length < 3) {\n    errors.name = 'The name must be at least 3 characters.'\n  }\n\n  if (!handle || handle.length < 3) {\n    errors.handle = 'The handle must be at least 3 characters.'\n  }\n\n  inertia.render(req, res, {\n    component: 'FormHelper/ErrorsClearOnResubmit',\n    props: { errors },\n  })\n})\n\napp.post('/form-helper/events/errors', (req, res) => {\n  setTimeout(() => {\n    inertia.render(req, res, {\n      component: 'FormHelper/Events',\n      props: { errors: { name: 'Some name error', handle: 'The Handle was invalid' } },\n    })\n  }, 250)\n})\n\n//\nconst isValidEmail = (email) => /\\S+@\\S+\\.\\S+/.test(email)\n\napp.post('/precognition/default', upload.any(), (req, res) => {\n  if (!req.headers['precognition']) {\n    return renderDump(req, res)\n  }\n\n  setTimeout(\n    () => {\n      const only = req.headers['precognition-validate-only'] ? req.headers['precognition-validate-only'].split(',') : []\n      const name = req.body['name']\n      const email = req.body['email']\n      const errors = {}\n\n      if (!name) {\n        errors.name = 'The name field is required.'\n      }\n\n      if (name && name.length < 3) {\n        errors.name = 'The name must be at least 3 characters.'\n      }\n\n      if (!email) {\n        errors.email = 'The email field is required.'\n      }\n\n      if (email && !isValidEmail(email)) {\n        errors.email = 'The email must be a valid email address.'\n      }\n\n      if (only.length) {\n        Object.keys(errors).forEach((key) => {\n          if (!only.includes(key)) {\n            delete errors[key]\n          }\n        })\n      }\n\n      res.header('Precognition', 'true')\n      res.header('Vary', 'Precognition')\n\n      if (Object.keys(errors).length) {\n        return res.status(422).json({ errors })\n      }\n\n      return res.status(204).header('Precognition-Success', 'true').send()\n    },\n    !!req.query['slow'] ? 2000 : 250,\n  )\n})\n\napp.post('/precognition/transform-keys', upload.any(), (req, res) => {\n  if (!req.headers['precognition']) {\n    return renderDump(req, res)\n  }\n\n  setTimeout(() => {\n    const only = req.headers['precognition-validate-only'] ? req.headers['precognition-validate-only'].split(',') : []\n    // After transform, the email is at customer.email (not document.customer.email)\n    const email = req.body['customer']?.email\n    const errors = {}\n\n    if (!email) {\n      errors['customer.email'] = 'The email field is required.'\n    }\n\n    if (email && !isValidEmail(email)) {\n      errors['customer.email'] = 'The email must be a valid email address.'\n    }\n\n    if (only.length) {\n      Object.keys(errors).forEach((key) => {\n        if (!only.includes(key)) {\n          delete errors[key]\n        }\n      })\n    }\n\n    res.header('Precognition', 'true')\n    res.header('Vary', 'Precognition')\n\n    if (Object.keys(errors).length) {\n      return res.status(422).json({ errors })\n    }\n\n    return res.status(204).header('Precognition-Success', 'true').send()\n  }, 250)\n})\n\napp.post('/precognition/with-all-errors', (req, res) => {\n  setTimeout(() => {\n    const only = req.headers['precognition-validate-only'] ? req.headers['precognition-validate-only'].split(',') : []\n    const name = req.body['name']\n    const email = req.body['email']\n    const errors = {}\n\n    if (!name) {\n      errors.name = ['The name field is required.']\n    }\n\n    if (name && name.length < 3) {\n      errors.name = ['The name must be at least 3 characters.', 'The name contains invalid characters.']\n    }\n\n    if (!email) {\n      errors.email = ['The email field is required.']\n    }\n\n    if (email && !isValidEmail(email)) {\n      errors.email = ['The email must be a valid email address.', 'The email format is incorrect.']\n    }\n\n    if (only.length) {\n      Object.keys(errors).forEach((key) => {\n        if (!only.includes(key)) {\n          delete errors[key]\n        }\n      })\n    }\n\n    res.header('Precognition', 'true')\n    res.header('Vary', 'Precognition')\n\n    if (Object.keys(errors).length) {\n      return res.status(422).json({ errors })\n    }\n\n    return res.status(204).header('Precognition-Success', 'true').send()\n  }, 250)\n})\n\napp.post('/precognition/files', upload.any(), (req, res) => {\n  setTimeout(() => {\n    const only = req.headers['precognition-validate-only'] ? req.headers['precognition-validate-only'].split(',') : []\n    const name = req.body['name']\n    const hasAvatar = req.files && req.files.avatar\n    const errors = {}\n\n    if (!name) {\n      errors.name = 'The name field is required.'\n    }\n\n    if (name && name.length < 3) {\n      errors.name = 'The name must be at least 3 characters.'\n    }\n\n    if (!hasAvatar) {\n      errors.avatar = 'The avatar field is required.'\n    }\n\n    if (only.length) {\n      Object.keys(errors).forEach((key) => {\n        if (!only.includes(key)) {\n          delete errors[key]\n        }\n      })\n    }\n\n    res.header('Precognition', 'true')\n    res.header('Vary', 'Precognition')\n\n    if (Object.keys(errors).length) {\n      return res.status(422).json({ errors })\n    }\n\n    return res.status(204).header('Precognition-Success', 'true').send()\n  }, 250)\n})\n\napp.post('/precognition/headers', (req, res) => {\n  setTimeout(() => {\n    const customHeader = req.headers['x-custom-header']\n    const name = req.body['name']\n    const errors = {}\n\n    // Show error when custom header IS present (to prove it was sent)\n    if (customHeader === 'custom-value') {\n      errors.name = 'Custom header received: custom-value'\n    } else if (!name) {\n      errors.name = 'The name field is required.'\n    } else if (name.length < 3) {\n      errors.name = 'The name must be at least 3 characters.'\n    }\n\n    res.header('Precognition', 'true')\n    res.header('Vary', 'Precognition')\n\n    if (Object.keys(errors).length) {\n      return res.status(422).json({ errors })\n    }\n\n    return res.status(204).header('Precognition-Success', 'true').send()\n  }, 250)\n})\n\napp.post('/precognition/dynamic-array-inputs', upload.any(), (req, res) => {\n  setTimeout(() => {\n    const only = req.headers['precognition-validate-only'] ? req.headers['precognition-validate-only'].split(',') : []\n    const items = req.body['items'] || []\n    const errors = {}\n\n    if (Array.isArray(items)) {\n      items.forEach((item, index) => {\n        if (!item.name || item.name.length < 3) {\n          errors[`items.${index}.name`] = 'The name must be at least 3 characters.'\n        }\n      })\n    }\n\n    if (only.length) {\n      Object.keys(errors).forEach((key) => {\n        if (!only.includes(key)) {\n          delete errors[key]\n        }\n      })\n    }\n\n    res.header('Precognition', 'true')\n    res.header('Vary', 'Precognition')\n\n    if (Object.keys(errors).length) {\n      return res.status(422).json({ errors })\n    }\n\n    return res.status(204).header('Precognition-Success', 'true').send()\n  }, 250)\n})\n\napp.post('/precognition/error-sync', upload.any(), (req, res) => {\n  const isPrecognition = req.headers['precognition'] === 'true'\n\n  setTimeout(() => {\n    const only = req.headers['precognition-validate-only'] ? req.headers['precognition-validate-only'].split(',') : []\n    const name = req.body['name']\n    const email = req.body['email']\n    const errors = {}\n\n    // Validate name\n    if (!name || name.trim() === '') {\n      errors.name = 'The name field is required.'\n    }\n\n    // Validate email\n    if (!email || email.trim() === '') {\n      errors.email = 'The email field is required.'\n    } else if (!isValidEmail(email)) {\n      errors.email = 'The email must be a valid email address.'\n    }\n\n    // For precognition, filter to only requested fields\n    if (isPrecognition && only.length) {\n      Object.keys(errors).forEach((key) => {\n        if (!only.includes(key)) {\n          delete errors[key]\n        }\n      })\n    }\n\n    if (isPrecognition) {\n      res.header('Precognition', 'true')\n      res.header('Vary', 'Precognition')\n\n      if (Object.keys(errors).length) {\n        return res.status(422).json({ errors })\n      }\n\n      return res.status(204).header('Precognition-Success', 'true').send()\n    }\n\n    // Non-precognition: regular form submission with Inertia error response\n    // Detect which component to return based on referer\n    const referer = req.headers['referer'] || ''\n    const isFormHelper = referer.includes('/form-helper/')\n    const component = isFormHelper ? 'FormHelper/Precognition/ErrorSync' : 'FormComponent/Precognition/ErrorSync'\n\n    if (Object.keys(errors).length) {\n      return inertia.render(req, res, {\n        component,\n        props: { errors },\n      })\n    }\n\n    // Success - redirect\n    return res.redirect(303, '/')\n  }, 100)\n})\n\nconst methods = ['get', 'post', 'put', 'patch', 'delete']\nconst renderDump = (req, res) =>\n  inertia.render(req, res, {\n    component: 'Dump',\n    props: {\n      headers: req.headers,\n      method: req.method?.toLowerCase(),\n      form: req.body || {},\n      query: req.query,\n      files: req.files,\n      url: req.originalUrl,\n    },\n  })\n\nmethods.forEach((method) => app[method](`/dump/${method}`, upload.any(), (req, res) => renderDump(req, res)))\n\napp.get('/visits/reload-on-mount', upload.any(), (req, res) => {\n  if (req.headers['x-inertia-partial-data']) {\n    return inertia.render(req, res, {\n      component: 'Visits/ReloadOnMount',\n      props: { name: 'mounted!' },\n    })\n  }\n\n  inertia.render(req, res, {\n    component: 'Visits/ReloadOnMount',\n    props: { name: 'not mounted!' },\n  })\n})\n\napp.get('/persistent-layouts/shorthand/simple/page-a', (req, res) =>\n  inertia.render(req, res, { props: { foo: 'bar', baz: 'example' } }),\n)\napp.get('/persistent-layouts/shorthand/nested/page-a', (req, res) =>\n  inertia.render(req, res, { props: { foo: 'bar', baz: 'example' } }),\n)\n\napp.post('/events/errors', (req, res) =>\n  inertia.render(req, res, { component: 'Events', props: { errors: { foo: 'bar' } } }),\n)\n\napp.get('/poll/hook', (req, res) => inertia.render(req, res, { component: 'Poll/Hook', props: {} }))\napp.get('/poll/hook/manual', (req, res) => inertia.render(req, res, { component: 'Poll/HookManual', props: {} }))\napp.get('/poll/router/manual', (req, res) => inertia.render(req, res, { component: 'Poll/RouterManual', props: {} }))\napp.get('/poll/unchanged-data', (req, res) =>\n  inertia.render(req, res, { component: 'Poll/UnchangedData', props: { custom_prop: 'unchanged' } }),\n)\napp.get('/poll/unchanged-data/encrypted', (req, res) =>\n  inertia.render(req, res, {\n    component: 'Poll/UnchangedData',\n    props: { custom_prop: 'unchanged' },\n    encryptHistory: true,\n  }),\n)\n\napp.get('/prefetch/after-error', (req, res) => {\n  inertia.render(req, res, { component: 'Prefetch/AfterError' })\n})\n\napp.get('/prefetch/test-page', (req, res) =>\n  inertia.render(req, res, {\n    component: 'Prefetch/TestPage',\n  }),\n)\n\napp.get('/prefetch/form', (req, res) =>\n  inertia.render(req, res, {\n    component: 'Prefetch/Form',\n    props: {\n      randomValue: Math.floor(Math.random() * 1000000),\n    },\n  }),\n)\n\napp.post('/prefetch/form', (req, res) => res.redirect(303, '/prefetch/form'))\napp.post('/prefetch/redirect-back', (req, res) => res.redirect(303, '/prefetch/form'))\n\napp.get('/prefetch/wayfinder', (req, res) => {\n  inertia.render(req, res, {\n    component: 'Prefetch/Wayfinder',\n  })\n})\n\napp.get('/prefetch/preserve-state', (req, res) => {\n  inertia.render(req, res, {\n    component: 'Prefetch/PreserveState',\n    props: {\n      page: parseInt(req.query.page || '1'),\n      timestamp: Date.now(),\n    },\n  })\n})\n\napp.get('/prefetch/:pageNumber', (req, res) => {\n  inertia.render(req, res, {\n    component: 'Prefetch/Page',\n    props: {\n      pageNumber: req.params.pageNumber,\n      lastLoaded: Date.now(),\n    },\n  })\n})\n\napp.get('/prefetch/swr/:pageNumber', (req, res) => {\n  const page = () => {\n    inertia.render(req, res, {\n      component: 'Prefetch/SWR',\n      props: {\n        pageNumber: req.params.pageNumber,\n        lastLoaded: Date.now(),\n      },\n    })\n  }\n\n  if (req.params.pageNumber === '4' || req.params.pageNumber === '5') {\n    setTimeout(page, 1500)\n  } else {\n    page()\n  }\n})\n\napp.get('/prefetch/tags/:pageNumber{/:propType}', (req, res) => {\n  inertia.render(req, res, {\n    component: 'Prefetch/Tags',\n    props: {\n      pageNumber: req.params.pageNumber,\n      lastLoaded: Date.now(),\n      propType: req.params.propType || 'array',\n    },\n  })\n})\n\napp.get('/history/:pageNumber', (req, res) => {\n  inertia.render(req, res, {\n    component: 'History/Page',\n    props: {\n      pageNumber: req.params.pageNumber,\n      multiByte: req.params.pageNumber === '5' ? '😃' : 'n/a',\n    },\n    encryptHistory: req.params.pageNumber === '3' || req.params.pageNumber === '5',\n    clearHistory: req.params.pageNumber === '4',\n  })\n})\n\napp.get('/history/version/:pageNumber', (req, res) => {\n  inertia.render(req, res, {\n    component: 'History/Version',\n    props: {\n      pageNumber: req.params.pageNumber,\n    },\n    version: req.params.pageNumber === '1' ? 'version-1' : 'version-2',\n  })\n})\n\napp.get('/history-quota/:pageNumber', (req, res) => {\n  const pageNumber = parseInt(req.params.pageNumber)\n  const size = 8 * 1024 * 1024 // 8 MB\n\n  const largeData = pageNumber < 8 ? 'x'.repeat(size) : 'x'.repeat(size - 2137)\n\n  inertia.render(req, res, {\n    component: 'HistoryQuota/Page',\n    props: {\n      pageNumber,\n      largeData,\n    },\n  })\n})\n\napp.get('/when-visible', (req, res) => {\n  const page = () =>\n    inertia.render(req, res, {\n      component: 'WhenVisible',\n      props: {},\n    })\n\n  if (req.headers['x-inertia-partial-data'] || req.query.count) {\n    setTimeout(page, 250)\n  } else {\n    page()\n  }\n})\n\napp.get('/when-visible-reload', (req, res) => {\n  const page = () =>\n    inertia.render(req, res, {\n      component: 'WhenVisibleReload',\n      props: {},\n    })\n\n  if (req.headers['x-inertia-partial-data']) {\n    setTimeout(() => {\n      inertia.render(req, res, {\n        component: 'WhenVisibleReload',\n        props: {\n          lazyData: {\n            text: 'This is lazy loaded data!',\n          },\n        },\n      })\n    }, 250)\n  } else {\n    page()\n  }\n})\n\napp.get('/when-visible-array-reload', (req, res) => {\n  const page = () =>\n    inertia.render(req, res, {\n      component: 'WhenVisibleArrayReload',\n      props: {},\n    })\n\n  if (req.headers['x-inertia-partial-data']) {\n    setTimeout(() => {\n      inertia.render(req, res, {\n        component: 'WhenVisibleArrayReload',\n        props: {\n          firstData: {\n            text: 'First lazy data loaded!',\n          },\n          secondData: {\n            text: 'Second lazy data loaded!',\n          },\n        },\n      })\n    }, 250)\n  } else {\n    page()\n  }\n})\n\napp.get('/when-visible-back-button', (req, res) => {\n  const page = () =>\n    inertia.render(req, res, {\n      component: 'WhenVisibleBackButton',\n      props: {},\n    })\n\n  if (req.headers['x-inertia-partial-data']) {\n    setTimeout(() => {\n      inertia.render(req, res, {\n        component: 'WhenVisibleBackButton',\n        props: {\n          lazyData: {\n            text: 'This is lazy loaded data!',\n          },\n        },\n      })\n    }, 250)\n  } else {\n    page()\n  }\n})\n\napp.get('/when-visible-fetching', (req, res) => {\n  if (req.headers['x-inertia-partial-data']) {\n    setTimeout(() => {\n      inertia.render(req, res, {\n        component: 'WhenVisibleFetching',\n        props: {\n          lazyData: { text: 'Lazy data loaded!' },\n        },\n      })\n    }, 500)\n  } else {\n    inertia.render(req, res, {\n      component: 'WhenVisibleFetching',\n      props: {},\n    })\n  }\n})\n\napp.get('/when-visible-merge-params', (req, res) => {\n  const partialData = req.headers['x-inertia-partial-data']\n\n  if (partialData) {\n    const props = {}\n    const partialProps = partialData.split(',')\n\n    if (partialProps.includes('dataOnlyProp')) {\n      props.dataOnlyProp = { text: 'Data only success!' }\n    }\n    if (partialProps.includes('mergedProp')) {\n      props.mergedProp = { text: `Merged success! extra=${req.query.extra}` }\n    }\n    if (partialProps.includes('mergedWithCallbackProp')) {\n      props.mergedWithCallbackProp = { text: `Merged with callback success! page=${req.query.page}` }\n    }\n\n    setTimeout(() => {\n      inertia.render(req, res, {\n        component: 'WhenVisibleMergeParams',\n        props,\n      })\n    }, 100)\n  } else {\n    inertia.render(req, res, {\n      component: 'WhenVisibleMergeParams',\n      props: {},\n    })\n  }\n})\n\napp.get('/when-visible-params-update', (req, res) => {\n  if (req.headers['x-inertia-partial-data']) {\n    setTimeout(() => {\n      inertia.render(req, res, {\n        component: 'WhenVisibleParamsUpdate',\n        props: {\n          lazyData: { text: `Loaded with paramValue=${req.query.paramValue}` },\n        },\n      })\n    }, 100)\n  } else {\n    inertia.render(req, res, {\n      component: 'WhenVisibleParamsUpdate',\n      props: {},\n    })\n  }\n})\n\napp.get('/progress/:pageNumber', (req, res) => {\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'Progress',\n        props: { pageNumber: req.params.pageNumber },\n      }),\n    500,\n  )\n})\n\napp.get('/progress-component', (req, res) => inertia.render(req, res, { component: 'ProgressComponent' }))\n\napp.get('/merge-props', (req, res) => {\n  inertia.render(req, res, {\n    component: 'MergeProps',\n    props: {\n      bar: new Array(5).fill(1),\n      foo: new Array(5).fill(1),\n    },\n    ...(req.headers['x-inertia-reset'] ? {} : { mergeProps: ['foo'] }),\n  })\n})\n\napp.get('/merge-nested-props/:strategy', (req, res) => {\n  const perPage = 3\n  const page = parseInt(req.query.page ?? 1)\n  const shouldAppend = req.params.strategy === 'append'\n\n  const users = new Array(perPage).fill(1).map((_, index) => ({\n    id: index + 1 + (page - 1) * perPage,\n    name: `User ${index + 1 + (page - 1) * perPage}`,\n  }))\n\n  inertia.render(req, res, {\n    component: 'MergeNestedProps',\n    props: {\n      users: {\n        data: shouldAppend ? users : users.slice().reverse(),\n        meta: {\n          perPage,\n          page,\n        },\n      },\n    },\n    ...(req.headers['x-inertia-reset']\n      ? {}\n      : shouldAppend\n        ? { mergeProps: ['users.data'] }\n        : { prependProps: ['users.data'] }),\n  })\n})\n\napp.get('/merge-nested-props-with-match/:strategy', (req, res) => {\n  const page = parseInt(req.query.page ?? 1)\n  const shouldAppend = req.params.strategy === 'append'\n\n  let users\n\n  if (page === 1) {\n    users = (shouldAppend ? [1, 2, 3, 4, 5] : [4, 5, 6, 7, 8]).map((id) => ({ id, name: `User ${id} - initial` }))\n  } else {\n    users = (shouldAppend ? [4, 5, 6, 7, 8] : [1, 2, 3, 4, 5]).map((id) => ({ id, name: `User ${id} - subsequent` }))\n  }\n\n  inertia.render(req, res, {\n    component: 'MergeNestedProps',\n    props: {\n      users: {\n        data: users,\n        meta: {\n          perPage: 5,\n          page,\n        },\n      },\n    },\n    ...(req.headers['x-inertia-reset']\n      ? {}\n      : shouldAppend\n        ? { mergeProps: ['users.data'], matchPropsOn: ['users.data.id'] }\n        : { prependProps: ['users.data'], matchPropsOn: ['users.data.id'] }),\n  })\n})\n\napp.get('/deep-merge-props', (req, res) => {\n  const labels = ['first', 'second', 'third', 'fourth', 'fifth']\n\n  const page = parseInt(req.query.page ?? -1, 10) + 1\n\n  inertia.render(req, res, {\n    component: 'DeepMergeProps',\n    props: {\n      bar: new Array(5).fill(1),\n      baz: new Array(5).fill(1),\n      foo: {\n        data: new Array(5).fill(1),\n        page,\n        per_page: 5,\n        meta: {\n          label: labels[page],\n        },\n      },\n    },\n    ...(req.headers['x-inertia-reset'] ? {} : { deepMergeProps: ['foo', 'baz'] }),\n  })\n})\n\napp.get('/complex-merge-selective', (req, res) => {\n  const isReload = req.headers['x-inertia-partial-component'] || req.headers['x-inertia-partial-data']\n\n  inertia.render(req, res, {\n    component: 'ComplexMergeSelective',\n    props: {\n      mixed: {\n        name: isReload ? 'Jane' : 'John',\n        users: isReload ? ['d', 'e', 'f'] : ['a', 'b', 'c'],\n        chat: {\n          data: isReload ? [4, 5, 6] : [1, 2, 3],\n        },\n        post: {\n          id: 1,\n          comments: {\n            allowed: isReload ? false : true,\n            data: isReload ? ['D', 'E', 'F'] : ['A', 'B', 'C'],\n          },\n        },\n      },\n    },\n    mergeProps: ['mixed.chat.data', 'mixed.post.comments.data'],\n  })\n})\n\napp.get('/match-props-on-key', (req, res) => {\n  const labels = ['first', 'second', 'third', 'fourth', 'fifth']\n\n  const perPage = 5\n  const page = parseInt(req.query.page ?? -1, 10) + 1\n\n  const users = new Array(perPage).fill(1).map((_, index) => ({\n    id: index + 1,\n    name: `User ${index + 1}`,\n  }))\n\n  const companies = new Array(perPage).fill(1).map((_, index) => ({\n    otherId: index + 1,\n    name: `Company ${index + 1}`,\n  }))\n\n  const teams = new Array(perPage).fill(1).map((_, index) => ({\n    uuid: (Math.random() + 1).toString(36).substring(7),\n    name: `Team ${perPage * page + index + 1}`,\n  }))\n\n  inertia.render(req, res, {\n    component: 'MatchPropsOnKey',\n    props: {\n      bar: new Array(perPage).fill(1),\n      baz: new Array(perPage).fill(1),\n      foo: {\n        data: users,\n        companies,\n        teams,\n        page,\n        per_page: 5,\n        meta: {\n          label: labels[page],\n        },\n      },\n    },\n    ...(req.headers['x-inertia-reset']\n      ? {}\n      : {\n          deepMergeProps: ['foo', 'baz'],\n          matchPropsOn: ['foo.data.id', 'foo.companies.otherId', 'foo.teams.uuid'],\n        }),\n  })\n})\n\napp.get('/deferred-props/page-1', (req, res) => {\n  if (!req.headers['x-inertia-partial-data']) {\n    return inertia.render(req, res, {\n      component: 'DeferredProps/Page1',\n      deferredProps: {\n        default: ['foo', 'bar'],\n      },\n      props: {},\n    })\n  }\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'DeferredProps/Page1',\n        props: {\n          foo: req.headers['x-inertia-partial-data']?.includes('foo') ? { text: 'foo value' } : undefined,\n          bar: req.headers['x-inertia-partial-data']?.includes('bar') ? { text: 'bar value' } : undefined,\n        },\n      }),\n    500,\n  )\n})\n\napp.get('/deferred-props/with-partial-reload/:mode', (req, res) => {\n  if (!req.headers['x-inertia-partial-data']) {\n    return inertia.render(req, res, {\n      component: 'DeferredProps/WithPartialReload',\n      deferredProps: {\n        default: ['users'],\n      },\n      props: {\n        withOnly: (() => {\n          if (req.params.mode === 'only') {\n            return ['users']\n          }\n\n          if (req.params.mode === 'only-other') {\n            return ['other']\n          }\n\n          return []\n        })(),\n        withExcept: (() => {\n          if (req.params.mode === 'except') {\n            return ['users']\n          }\n\n          if (req.params.mode === 'except-other') {\n            return ['other']\n          }\n\n          return []\n        })(),\n      },\n    })\n  }\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'DeferredProps/WithPartialReload',\n        props: {\n          users: req.headers['x-inertia-partial-data']?.includes('users') ? [{ id: 1, name: 'John Doe' }] : undefined,\n        },\n      }),\n    500,\n  )\n})\n\napp.get('/deferred-props/page-2', (req, res) => {\n  if (!req.headers['x-inertia-partial-data']) {\n    return inertia.render(req, res, {\n      component: 'DeferredProps/Page2',\n      deferredProps: {\n        default: ['baz'],\n        other: ['qux'],\n      },\n      props: {},\n    })\n  }\n\n  if (req.headers['x-inertia-partial-data']?.includes('baz')) {\n    setTimeout(\n      () =>\n        inertia.render(req, res, {\n          component: 'DeferredProps/Page2',\n          props: {\n            baz: 'baz value',\n          },\n        }),\n      500,\n    )\n  }\n\n  if (req.headers['x-inertia-partial-data']?.includes('qux')) {\n    setTimeout(\n      () =>\n        inertia.render(req, res, {\n          component: 'DeferredProps/Page2',\n          props: {\n            qux: 'qux value',\n          },\n        }),\n      750,\n    )\n  }\n})\n\napp.get('/deferred-props/page-3', (req, res) => {\n  if (!req.headers['x-inertia-partial-data']) {\n    return inertia.render(req, res, {\n      component: 'DeferredProps/Page3',\n      deferredProps: {\n        default: ['alpha', 'beta'],\n      },\n      props: {},\n    })\n  }\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'DeferredProps/Page3',\n        props: {\n          alpha: req.headers['x-inertia-partial-data']?.includes('alpha') ? 'alpha value' : undefined,\n          beta: req.headers['x-inertia-partial-data']?.includes('beta') ? 'beta value' : undefined,\n        },\n      }),\n    500,\n  )\n})\n\napp.get('/deferred-props/many-groups', (req, res) => {\n  const props = ['foo', 'bar', 'baz', 'qux', 'quux']\n  const requestedProps = req.headers['x-inertia-partial-data']\n  const delay = requestedProps ? (props.indexOf(requestedProps) + 3) * 100 : 500\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'DeferredProps/ManyGroups',\n        props: requestedProps ? { [requestedProps]: { text: `${requestedProps} value` } } : {},\n        deferredProps: requestedProps\n          ? {}\n          : props.reduce((groups, prop) => {\n              groups[prop] = [prop]\n              return groups\n            }, {}),\n      }),\n    delay,\n  )\n})\n\napp.get('/deferred-props/instant-reload', (req, res) => {\n  const requestedProps = req.headers['x-inertia-partial-data']\n  const delay = requestedProps === 'bar' ? 300 : 0\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'DeferredProps/InstantReload',\n        props: requestedProps\n          ? {\n              [requestedProps]: {\n                text: `${requestedProps} value`,\n              },\n            }\n          : {},\n        deferredProps: requestedProps ? {} : { default: ['bar'] },\n      }),\n    delay,\n  )\n})\n\napp.get('/deferred-props/with-query-params', (req, res) => {\n  const filter = req.query.filter || 'none'\n  const requestedProps = req.headers['x-inertia-partial-data']\n\n  if (!requestedProps) {\n    return inertia.render(req, res, {\n      component: 'DeferredProps/WithQueryParams',\n      deferredProps: {\n        default: ['users'],\n      },\n      props: {\n        filter,\n      },\n    })\n  }\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'DeferredProps/WithQueryParams',\n        props: {\n          users: requestedProps.includes('users') ? { text: `users data for ${filter}` } : undefined,\n        },\n      }),\n    500,\n  )\n})\n\napp.get('/deferred-props/rapid-navigation{/:id}', (req, res) => {\n  const id = req.params.id || 'none'\n  const requestedProps = req.headers['x-inertia-partial-data']\n\n  if (!requestedProps) {\n    return inertia.render(req, res, {\n      component: 'DeferredProps/RapidNavigation',\n      deferredProps: {\n        group1: ['users'],\n        group2: ['stats'],\n        group3: ['activity'],\n      },\n      props: {\n        id,\n      },\n    })\n  }\n\n  // Simulate slow deferred prop loading\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'DeferredProps/RapidNavigation',\n        props: {\n          id,\n          users: requestedProps.includes('users') ? { text: `users data for ${id}` } : undefined,\n          stats: requestedProps.includes('stats') ? { text: `stats data for ${id}` } : undefined,\n          activity: requestedProps.includes('activity') ? { text: `activity data for ${id}` } : undefined,\n        },\n      }),\n    600,\n  )\n})\n\napp.get('/deferred-props/partial-reloads', (req, res) => {\n  if (!req.headers['x-inertia-partial-data']) {\n    return inertia.render(req, res, {\n      component: 'DeferredProps/PartialReloads',\n      deferredProps: {\n        default: ['foo', 'bar'],\n      },\n      props: {},\n    })\n  }\n\n  const requestedProps = req.headers['x-inertia-partial-data']\n  const props = {}\n\n  if (requestedProps.includes('foo')) {\n    props.foo = {\n      timestamp: new Date().toISOString(),\n    }\n  }\n\n  if (requestedProps.includes('bar')) {\n    props.bar = {\n      timestamp: new Date().toISOString(),\n    }\n  }\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'DeferredProps/PartialReloads',\n        props: props,\n      }),\n    500,\n  )\n})\n\nlet deferredPropsWithErrorsState = {}\n\napp.get('/deferred-props/with-errors', (req, res) => {\n  const errors = { ...deferredPropsWithErrorsState }\n\n  deferredPropsWithErrorsState = {}\n\n  if (!req.headers['x-inertia-partial-data']) {\n    return inertia.render(req, res, {\n      component: 'DeferredProps/WithErrors',\n      deferredProps: {\n        default: ['foo'],\n      },\n      props: {\n        errors,\n      },\n    })\n  }\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'DeferredProps/WithErrors',\n        props: {\n          foo: req.headers['x-inertia-partial-data']?.includes('foo') ? { text: 'foo value' } : undefined,\n          errors: {},\n        },\n      }),\n    250,\n  )\n})\n\napp.post('/deferred-props/with-errors', (req, res) => {\n  deferredPropsWithErrorsState = { name: 'The name field is required.' }\n\n  res.redirect(303, '/deferred-props/with-errors')\n})\n\napp.get('/deferred-props/with-reload', (req, res) => {\n  const page = parseInt(req.query.page) || 1\n\n  if (!req.headers['x-inertia-partial-data']) {\n    return inertia.render(req, res, {\n      component: 'DeferredProps/WithReload',\n      url: req.originalUrl,\n      deferredProps: {\n        default: ['results'],\n      },\n      props: {},\n    })\n  }\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'DeferredProps/WithReload',\n        url: req.originalUrl,\n        props: {\n          results: req.headers['x-inertia-partial-data']?.includes('results')\n            ? { data: [`Item ${page}-1`, `Item ${page}-2`, `Item ${page}-3`], page }\n            : undefined,\n        },\n      }),\n    300,\n  )\n})\n\napp.get('/deferred-props/reload-without-optional-chaining', (req, res) => {\n  const page = parseInt(req.query.page) || 1\n\n  if (!req.headers['x-inertia-partial-data']) {\n    return inertia.render(req, res, {\n      component: 'DeferredProps/ReloadWithoutOptionalChaining',\n      url: req.originalUrl,\n      deferredProps: {\n        default: ['results'],\n      },\n      props: {},\n    })\n  }\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'DeferredProps/ReloadWithoutOptionalChaining',\n        url: req.originalUrl,\n        props: {\n          results: req.headers['x-inertia-partial-data']?.includes('results')\n            ? { data: [`Item ${page}-1`, `Item ${page}-2`, `Item ${page}-3`], page }\n            : undefined,\n        },\n      }),\n    300,\n  )\n})\n\napp.get('/svelte/props-and-page-store', (req, res) =>\n  inertia.render(req, res, { component: 'Svelte/PropsAndPageStore', props: { foo: req.query.foo || 'default' } }),\n)\n\napp.get('/remember/users', (req, res) => {\n  const users = [\n    { id: 1, name: 'User One', email: 'user1@example.com' },\n    { id: 2, name: 'User Two', email: 'user2@example.com' },\n    { id: 3, name: 'User Three', email: 'user3@example.com' },\n  ]\n  inertia.render(req, res, { component: 'FormHelper/RememberIndex', props: { users } })\n})\n\napp.get('/remember/users/:id/edit', (req, res) => {\n  const users = {\n    1: { id: 1, name: 'User One', email: 'user1@example.com' },\n    2: { id: 2, name: 'User Two', email: 'user2@example.com' },\n    3: { id: 3, name: 'User Three', email: 'user3@example.com' },\n  }\n  const user = users[req.params.id]\n  inertia.render(req, res, {\n    component: 'FormHelper/RememberEdit',\n    props: { user },\n  })\n})\n\napp.get('/preserve-equal-props', (req, res) => {\n  inertia.render(req, res, {\n    component: 'PreserveEqualProps',\n    props: { nestedA: { count: 1 }, nestedB: { date: Date.now() } },\n  })\n})\napp.post('/preserve-equal-props/back', (req, res) => res.redirect(303, '/preserve-equal-props'))\n\napp.all('/sleep', (req, res) => setTimeout(() => res.send(''), 2000))\napp.post('/redirect', (req, res) => res.redirect(303, '/dump/get'))\n\napp.get('/location', ({ res }) => inertia.location(res, '/dump/get'))\napp.post('/redirect-external', (req, res) => inertia.location(res, '/non-inertia'))\napp.post('/disconnect', (req, res) => res.socket.destroy())\napp.post('/json', (req, res) => res.status(200).json({ foo: 'bar' }))\n\napp.get('/form-component/child-component', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/ChildComponent' }),\n)\n\nlet defaultValueForErrors = {}\n\napp.get('/form-component/default-value', (req, res) => {\n  const errors = { ...defaultValueForErrors }\n  defaultValueForErrors = {}\n\n  return inertia.render(req, res, {\n    component: 'FormComponent/DefaultValue',\n    props: { user: { name: 'John Doe' }, errors },\n  })\n})\napp.patch('/form-component/default-value', (req, res) => {\n  if (!req.body.name || req.body.name.length < 10) {\n    defaultValueForErrors = { 'user.name': 'The name must be at least 10 characters.' }\n    return res.redirect(303, '/form-component/default-value')\n  }\n\n  return res.redirect(303, '/')\n})\n\napp.get('/form-component/elements', (req, res) =>\n  inertia.render(req, res, {\n    component: 'FormComponent/Elements',\n    props: {\n      queryStringArrayFormat: req.query.queryStringArrayFormat || 'brackets',\n    },\n  }),\n)\napp.get('/form-component/errors', (req, res) => inertia.render(req, res, { component: 'FormComponent/Errors' }))\napp.post('/form-component/errors', (req, res) =>\n  inertia.render(req, res, {\n    component: 'FormComponent/Errors',\n    props: { errors: { name: 'Some name error', handle: 'The Handle was invalid' } },\n  }),\n)\napp.post('/form-component/errors/bag', (req, res) =>\n  inertia.render(req, res, {\n    component: 'FormComponent/Errors',\n    props: { errors: { bag: { name: 'Some name error', handle: 'The Handle was invalid' } } },\n  }),\n)\n\napp.get('/form-component/events', (req, res) => inertia.render(req, res, { component: 'FormComponent/Events' }))\napp.post('/form-component/events/delay', upload.any(), async (req, res) =>\n  setTimeout(() => inertia.render(req, res, { component: 'FormComponent/Events' }), 500),\n)\napp.get('/form-component/disable-while-processing/:disable', upload.any(), async (req, res) =>\n  inertia.render(req, res, {\n    component: 'FormComponent/DisableWhileProcessing',\n    props: {\n      disable: req.params.disable === 'yes',\n    },\n  }),\n)\napp.post('/form-component/disable-while-processing/:disable/submit', upload.any(), async (req, res) =>\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'FormComponent/DisableWhileProcessing',\n        props: {\n          disable: req.params.disable === 'yes',\n        },\n      }),\n    500,\n  ),\n)\napp.post('/form-component/events/success', async (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/Events' }),\n)\napp.post('/form-component/events/errors', async (req, res) =>\n  inertia.render(req, res, {\n    component: 'FormComponent/Events',\n    props: { errors: { field: 'Something went wrong' } },\n  }),\n)\n\napp.get('/form-component/headers', (req, res) => inertia.render(req, res, { component: 'FormComponent/Headers' }))\napp.get('/form-component/options', (req, res) => inertia.render(req, res, { component: 'FormComponent/Options' }))\napp.get('/form-component/progress', (req, res) => inertia.render(req, res, { component: 'FormComponent/Progress' }))\napp.post('/form-component/progress', async (req, res) =>\n  setTimeout(() => inertia.render(req, res, { component: 'FormComponent/Progress' }), 500),\n)\n\napp.get('/form-component/submit-complete/reset', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/SubmitComplete/Reset' }),\n)\napp.get('/form-component/submit-complete/defaults', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/SubmitComplete/Defaults' }),\n)\napp.post('/form-component/submit-complete/reset', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/SubmitComplete/Reset' }),\n)\napp.post('/form-component/submit-complete/defaults', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/SubmitComplete/Defaults' }),\n)\n\napp.get('/form-component/state', (req, res) => inertia.render(req, res, { component: 'FormComponent/State' }))\napp.get('/form-component/dotted-keys', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/DottedKeys' }),\n)\napp.get('/form-component/ref', (req, res) => inertia.render(req, res, { component: 'FormComponent/Ref' }))\napp.get('/form-component/reset', (req, res) => inertia.render(req, res, { component: 'FormComponent/Reset' }))\napp.get('/form-component/submit-button', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/SubmitButton' }),\n)\napp.get('/form-component/uppercase-method', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/UppercaseMethod' }),\n)\n\napp.get('/form-component/reset-on-error', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/ResetAttributes/ResetOnError' }),\n)\napp.post('/form-component/reset-on-error', (req, res) =>\n  inertia.render(req, res, {\n    component: 'FormComponent/ResetAttributes/ResetOnError',\n    props: { errors: { name: 'Some name error' } },\n  }),\n)\n\napp.get('/form-component/reset-on-success', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/ResetAttributes/ResetOnSuccess' }),\n)\napp.post('/form-component/reset-on-success', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/ResetAttributes/ResetOnSuccess' }),\n)\n\napp.get('/form-component/reset-on-error-fields', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/ResetAttributes/ResetOnErrorFields' }),\n)\napp.post('/form-component/reset-on-error-fields', (req, res) =>\n  inertia.render(req, res, {\n    component: 'FormComponent/ResetAttributes/ResetOnErrorFields',\n    props: { errors: { name: 'Some name error' } },\n  }),\n)\n\napp.get('/form-component/reset-on-success-fields', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/ResetAttributes/ResetOnSuccessFields' }),\n)\napp.post('/form-component/reset-on-success-fields', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/ResetAttributes/ResetOnSuccessFields' }),\n)\n\napp.get('/form-component/set-defaults-on-success', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/SetDefaultsOnSuccess' }),\n)\napp.post('/form-component/set-defaults-on-success', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/SetDefaultsOnSuccess' }),\n)\n\napp.get('/form-component/url/with/segements', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/EmptyAction' }),\n)\napp.post('/form-component/url/with/segements', async (req, res) =>\n  inertia.render(req, res, {\n    component: 'FormComponent/EmptyAction',\n    props: { errors: { name: 'Something went wrong' } },\n  }),\n)\n\napp.get('/form-component/submit-complete/redirect', (req, res) =>\n  inertia.render(req, res, { component: 'FormComponent/SubmitComplete/Redirect' }),\n)\napp.post('/form-component/submit-complete/redirect', (req, res) => res.redirect(303, '/'))\napp.post('/form-component/wayfinder', (req, res) => {\n  inertia.render(req, res, { component: 'FormComponent/Wayfinder' })\n})\napp.get('/form-component/invalidate-tags/:propType', (req, res) =>\n  inertia.render(req, res, {\n    component: 'FormComponent/InvalidateTags',\n    props: { lastLoaded: Date.now(), propType: req.params.propType },\n  }),\n)\napp.post('/form-component/view-transition', (req, res) =>\n  inertia.render(req, res, { component: 'ViewTransition/PageB' }),\n)\n\nfunction renderInfiniteScroll(req, res, component, total = 40, orderByDesc = false, perPage = 15) {\n  const page = req.query.page ? parseInt(req.query.page) : 1\n  const partialReload = !!req.headers['x-inertia-partial-data']\n  const shouldAppend = req.headers['x-inertia-infinite-scroll-merge-intent'] !== 'prepend'\n  const { paginated, scrollProp } = paginateUsers(page, perPage, total, orderByDesc)\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component,\n        props: { users: paginated },\n        [shouldAppend ? 'mergeProps' : 'prependProps']: ['users.data'],\n        scrollProps: { users: scrollProp },\n      }),\n    partialReload ? 250 : 0,\n  )\n}\n\napp.get('/infinite-scroll', (req, res) => inertia.render(req, res, { component: 'InfiniteScroll/Links' }))\napp.get('/infinite-scroll-with-link', (req, res) =>\n  renderInfiniteScroll(req, res, 'InfiniteScroll/InfiniteScrollWithLink'),\n)\napp.get('/infinite-scroll/manual', (req, res) => renderInfiniteScroll(req, res, 'InfiniteScroll/Manual'))\napp.get('/infinite-scroll/manual-after', (req, res) => renderInfiniteScroll(req, res, 'InfiniteScroll/ManualAfter', 60))\napp.get('/infinite-scroll/remember-state', (req, res) =>\n  renderInfiniteScroll(req, res, 'InfiniteScroll/RememberState', 60),\n)\napp.get('/infinite-scroll/toggles', (req, res) => renderInfiniteScroll(req, res, 'InfiniteScroll/Toggles'))\napp.get('/infinite-scroll/trigger-both', (req, res) => renderInfiniteScroll(req, res, 'InfiniteScroll/TriggerBoth'))\napp.get('/infinite-scroll/trigger-end-buffer', (req, res) =>\n  renderInfiniteScroll(req, res, 'InfiniteScroll/TriggerEndBuffer'),\n)\napp.get('/infinite-scroll/trigger-start-buffer', (req, res) =>\n  renderInfiniteScroll(req, res, 'InfiniteScroll/TriggerStartBuffer'),\n)\napp.get('/infinite-scroll/reverse', (req, res) => renderInfiniteScroll(req, res, 'InfiniteScroll/Reverse', 40, true))\napp.get('/infinite-scroll/reverse-short-content', (req, res) =>\n  renderInfiniteScroll(req, res, 'InfiniteScroll/ReverseShortContent', 40, true, 5),\n)\napp.get('/infinite-scroll/manual-reverse', (req, res) =>\n  renderInfiniteScroll(req, res, 'InfiniteScroll/ManualReverse', 40, true),\n)\napp.get('/infinite-scroll/update-query-string', (req, res) =>\n  renderInfiniteScroll(req, res, 'InfiniteScroll/UpdateQueryString'),\n)\napp.get('/infinite-scroll/custom-element', (req, res) => renderInfiniteScroll(req, res, 'InfiniteScroll/CustomElement'))\napp.get('/infinite-scroll/preserve-url', (req, res) => renderInfiniteScroll(req, res, 'InfiniteScroll/PreserveUrl'))\napp.get('/infinite-scroll/scroll-container', (req, res) =>\n  renderInfiniteScroll(req, res, 'InfiniteScroll/ScrollContainer'),\n)\napp.get('/infinite-scroll/grid', (req, res) => renderInfiniteScroll(req, res, 'InfiniteScroll/Grid', 240, false, 60))\napp.get('/infinite-scroll/data-table', (req, res) =>\n  renderInfiniteScroll(req, res, 'InfiniteScroll/DataTable', 1000, false, 250),\n)\napp.get('/infinite-scroll/horizontal-scroll', (req, res) =>\n  renderInfiniteScroll(req, res, 'InfiniteScroll/HorizontalScroll'),\n)\napp.get('/infinite-scroll/overflow-x', (req, res) =>\n  renderInfiniteScroll(req, res, 'InfiniteScroll/OverflowX', 150, false, 15),\n)\napp.get('/infinite-scroll/empty', (req, res) => renderInfiniteScroll(req, res, 'InfiniteScroll/Empty', 0))\napp.get('/infinite-scroll/custom-triggers-ref', (req, res) =>\n  renderInfiniteScroll(req, res, 'InfiniteScroll/CustomTriggersRef'),\n)\napp.get('/infinite-scroll/custom-triggers-selector', (req, res) =>\n  renderInfiniteScroll(req, res, 'InfiniteScroll/CustomTriggersSelector'),\n)\napp.get('/infinite-scroll/custom-triggers-ref-object', (req, res) =>\n  renderInfiniteScroll(req, res, 'InfiniteScroll/CustomTriggersRefObject'),\n)\napp.get('/infinite-scroll/programmatic-ref', (req, res) =>\n  renderInfiniteScroll(req, res, 'InfiniteScroll/ProgrammaticRef'),\n)\napp.get('/infinite-scroll/short-content', (req, res) =>\n  renderInfiniteScroll(req, res, 'InfiniteScroll/ShortContent', 100, false, 5),\n)\napp.get('/infinite-scroll/invisible-first-child', (req, res) =>\n  renderInfiniteScroll(req, res, 'InfiniteScroll/InvisibleFirstChild'),\n)\napp.get('/infinite-scroll/reload-unrelated', (req, res) => {\n  const page = req.query.page ? parseInt(req.query.page) : 1\n  const partialReload = !!req.headers['x-inertia-partial-data']\n  const shouldAppend = req.headers['x-inertia-infinite-scroll-merge-intent'] !== 'prepend'\n  const { paginated, scrollProp } = paginateUsers(page, 15, 40, false)\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'InfiniteScroll/ReloadUnrelated',\n        props: {\n          time: Date.now(),\n          users: paginated,\n        },\n        ...(req.headers['x-inertia-partial-data'] === 'users'\n          ? { [shouldAppend ? 'mergeProps' : 'prependProps']: ['users.data'] }\n          : {}),\n        ...(req.headers['x-inertia-partial-data'] === 'time' ? {} : { scrollProps: { users: scrollProp } }),\n      }),\n    partialReload ? 250 : 0,\n  )\n})\napp.get('/infinite-scroll/dual-containers', (req, res) => {\n  const users1Page = req.query.users1 ? parseInt(req.query.users1) : 1\n  const users2Page = req.query.users2 ? parseInt(req.query.users2) : 1\n  const partialReload = !!req.headers['x-inertia-partial-data']\n  const shouldAppend = req.headers['x-inertia-infinite-scroll-merge-intent'] !== 'prepend'\n\n  const { paginated: users1Paginated, scrollProp: users1ScrollProp } = paginateUsers(\n    users1Page,\n    15,\n    40,\n    false,\n    'users1',\n  )\n  const { paginated: users2Paginated, scrollProp: users2ScrollProp } = paginateUsers(\n    users2Page,\n    15,\n    60,\n    false,\n    'users2',\n  )\n\n  const props = {}\n  const scrollProps = {}\n\n  if (!partialReload || req.headers['x-inertia-partial-data']?.includes('users1')) {\n    props.users1 = users1Paginated\n    scrollProps.users1 = users1ScrollProp\n  }\n\n  if (!partialReload || req.headers['x-inertia-partial-data']?.includes('users2')) {\n    props.users2 = users2Paginated\n    scrollProps.users2 = users2ScrollProp\n  }\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'InfiniteScroll/DualContainers',\n        props,\n        [shouldAppend ? 'mergeProps' : 'prependProps']: ['users1.data', 'users2.data'],\n        scrollProps,\n      }),\n    partialReload ? 250 : 0,\n  )\n})\napp.get('/infinite-scroll/dual-sibling', (req, res) => {\n  const users1Page = req.query.users1 ? parseInt(req.query.users1) : 1\n  const users2Page = req.query.users2 ? parseInt(req.query.users2) : 1\n  const partialReload = !!req.headers['x-inertia-partial-data']\n  const shouldAppend = req.headers['x-inertia-infinite-scroll-merge-intent'] !== 'prepend'\n\n  const { paginated: users1Paginated, scrollProp: users1ScrollProp } = paginateUsers(\n    users1Page,\n    15,\n    40,\n    false,\n    'users1',\n  )\n  const { paginated: users2Paginated, scrollProp: users2ScrollProp } = paginateUsers(\n    users2Page,\n    15,\n    60,\n    false,\n    'users2',\n  )\n\n  const props = {}\n  const scrollProps = {}\n\n  if (!partialReload || req.headers['x-inertia-partial-data']?.includes('users1')) {\n    props.users1 = users1Paginated\n    scrollProps.users1 = users1ScrollProp\n  }\n\n  if (!partialReload || req.headers['x-inertia-partial-data']?.includes('users2')) {\n    props.users2 = users2Paginated\n    scrollProps.users2 = users2ScrollProp\n  }\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'InfiniteScroll/DualSibling',\n        props,\n        [shouldAppend ? 'mergeProps' : 'prependProps']: ['users1.data', 'users2.data'],\n        scrollProps,\n      }),\n    partialReload ? 250 : 0,\n  )\n})\n\nfunction renderInfiniteScrollWithTag(req, res, component, total = 40, orderByDesc = false, perPage = 15) {}\n\napp.get('/infinite-scroll/filtering/:preserveState', (req, res) => {\n  const filter = req.query.filter || ''\n  const search = req.query.search || ''\n\n  let users = getUserNames()\n\n  if (search) {\n    users = users.filter((user) => user.toLowerCase().includes(search.toLowerCase()))\n  }\n\n  if (filter === 'a-m') {\n    users = users.filter((user) => user.toLowerCase() >= 'a' && user.toLowerCase() <= 'm')\n  } else if (filter === 'n-z') {\n    users = users.filter((user) => user.toLowerCase() >= 'n' && user.toLowerCase() <= 'z')\n  }\n\n  const perPage = 15\n  const page = req.query.page ? parseInt(req.query.page) : 1\n\n  const partialReload = !!req.headers['x-inertia-partial-data']\n  const shouldAppend = req.headers['x-inertia-infinite-scroll-merge-intent'] !== 'prepend'\n  const { paginated, scrollProp } = paginateUsers(page, perPage, users.length)\n\n  if (page > 1) {\n    users = users.slice((page - 1) * perPage, page * perPage)\n  }\n\n  paginated.data = paginated.data.map((user, i) => ({ ...user, name: users[i] }))\n\n  if (req.headers['x-inertia-reset']) {\n    scrollProp.reset = true\n  }\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'InfiniteScroll/Filtering',\n        props: { users: paginated, filter, search, preserveState: req.params.preserveState === 'preserve-state' },\n        ...(req.headers['x-inertia-reset'] ? {} : { [shouldAppend ? 'mergeProps' : 'prependProps']: ['users.data'] }),\n        scrollProps: { users: scrollProp },\n      }),\n    partialReload ? 250 : 0,\n  )\n})\n\napp.get('/infinite-scroll/filtering-reset', (req, res) => {\n  const search = req.query.search || ''\n\n  let users = getUserNames()\n\n  if (search) {\n    users = users.filter((user) => user.toLowerCase().includes(search.toLowerCase()))\n  }\n\n  const perPage = 15\n  const page = req.query.page ? parseInt(req.query.page) : 1\n\n  const partialReload = !!req.headers['x-inertia-partial-data']\n  const shouldAppend = req.headers['x-inertia-infinite-scroll-merge-intent'] !== 'prepend'\n  const { paginated, scrollProp } = paginateUsers(page, perPage, users.length)\n\n  if (page > 1) {\n    users = users.slice((page - 1) * perPage, page * perPage)\n  }\n\n  paginated.data = paginated.data.map((user, i) => ({ ...user, name: users[i] }))\n\n  if (req.headers['x-inertia-reset']) {\n    scrollProp.reset = true\n  }\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'InfiniteScroll/FilteringReset',\n        props: { users: paginated, search },\n        ...(req.headers['x-inertia-reset'] ? {} : { [shouldAppend ? 'mergeProps' : 'prependProps']: ['users.data'] }),\n        scrollProps: { users: scrollProp },\n      }),\n    partialReload ? 250 : 0,\n  )\n})\n\napp.get('/infinite-scroll/filtering-manual', (req, res) => {\n  const search = req.query.search || ''\n  const perPage = 15\n  const page = req.query.page ? parseInt(req.query.page) : 1\n\n  let users = getUserNames()\n\n  if (search) {\n    users = users.filter((user) => user.toLowerCase().includes(search.toLowerCase()))\n  }\n\n  const partialReload = !!req.headers['x-inertia-partial-data']\n  const shouldAppend = req.headers['x-inertia-infinite-scroll-merge-intent'] !== 'prepend'\n  const { paginated, scrollProp } = paginateUsers(page, perPage, users.length)\n\n  if (page > 1) {\n    users = users.slice((page - 1) * perPage, page * perPage)\n  }\n\n  paginated.data = paginated.data.map((user, i) => ({ ...user, name: users[i] }))\n\n  if (req.headers['x-inertia-reset']) {\n    scrollProp.reset = true\n  }\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'InfiniteScroll/FilteringManual',\n        props: { users: paginated, search, preserveState: true },\n        ...(req.headers['x-inertia-reset'] ? {} : { [shouldAppend ? 'mergeProps' : 'prependProps']: ['users.data'] }),\n        scrollProps: { users: scrollProp },\n      }),\n    partialReload ? 250 : 0,\n  )\n})\n\n// Deferred scroll props test - simulates Inertia::scroll()->defer()\napp.get('/infinite-scroll/deferred', (req, res) => {\n  const page = req.query.page ? parseInt(req.query.page) : 1\n  const partialReload = !!req.headers['x-inertia-partial-data']\n  const shouldAppend = req.headers['x-inertia-infinite-scroll-merge-intent'] !== 'prepend'\n  const { paginated, scrollProp } = paginateUsers(page, 15, 40, false)\n\n  if (!partialReload) {\n    // Initial page load - defer the users prop, no scrollProps yet\n    return inertia.render(req, res, {\n      component: 'InfiniteScroll/Deferred',\n      props: {},\n      deferredProps: { default: ['users'] },\n    })\n  }\n\n  // Deferred props request - send both the data AND scrollProps\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'InfiniteScroll/Deferred',\n        props: { users: paginated },\n        [shouldAppend ? 'mergeProps' : 'prependProps']: ['users.data'],\n        scrollProps: { users: scrollProp },\n      }),\n    250,\n  )\n})\n\napp.post('/view-transition/form-errors', (req, res) =>\n  inertia.render(req, res, {\n    component: 'ViewTransition/FormErrors',\n    props: { errors: { name: 'The name field is required.' } },\n  }),\n)\n\napp.get('/flash/events', (req, res) => inertia.render(req, res, { component: 'Flash/Events' }))\napp.post('/flash/events/with-data', (req, res) =>\n  inertia.render(req, res, {\n    component: 'Flash/Events',\n    flash: { foo: 'bar' },\n  }),\n)\napp.post('/flash/events/without-data', (req, res) => inertia.render(req, res, { component: 'Flash/Events' }))\napp.get('/flash/client-side-visits', (req, res) => inertia.render(req, res, { component: 'Flash/ClientSideVisits' }))\napp.get('/flash/router-flash', (req, res) => inertia.render(req, res, { component: 'Flash/RouterFlash' }))\napp.get('/flash/initial', (req, res) =>\n  inertia.render(req, res, {\n    component: 'Flash/InitialFlash',\n    flash: { message: 'Hello from server' },\n  }),\n)\napp.get('/flash/with-infinite-scroll', (req, res) => {\n  const page = req.query.page ? parseInt(req.query.page) : 1\n  const partialReload = !!req.headers['x-inertia-partial-data']\n  const shouldAppend = req.headers['x-inertia-infinite-scroll-merge-intent'] !== 'prepend'\n  const { paginated, scrollProp } = paginateUsers(page, 15, 40, false)\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'Flash/WithInfiniteScroll',\n        props: { users: paginated },\n        [shouldAppend ? 'mergeProps' : 'prependProps']: ['users.data'],\n        scrollProps: { users: scrollProp },\n        flash: partialReload ? {} : { message: 'Flash with infinite scroll' },\n      }),\n    partialReload ? 250 : 0,\n  )\n})\napp.get('/flash/with-deferred', (req, res) => {\n  if (!req.headers['x-inertia-partial-data']) {\n    return inertia.render(req, res, {\n      component: 'Flash/WithDeferred',\n      deferredProps: {\n        default: ['data'],\n      },\n      props: {},\n      flash: { message: 'Flash with deferred' },\n    })\n  }\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'Flash/WithDeferred',\n        props: {\n          data: req.headers['x-inertia-partial-data']?.includes('data') ? 'Deferred data loaded' : undefined,\n        },\n      }),\n    250,\n  )\n})\napp.get('/flash/partial', (req, res) => {\n  const count = parseInt(req.query.count || '0')\n  const flashType = req.query.flashType || 'same'\n\n  let flash = { message: 'Initial flash' }\n  if (req.headers['x-inertia-partial-data']) {\n    flash = flashType === 'different' ? { message: `Updated flash ${count}` } : { message: 'Initial flash' }\n  }\n\n  inertia.render(req, res, {\n    component: 'Flash/Partial',\n    props: { count },\n    flash,\n  })\n})\nconst getOncePropsData = (req, prop = 'foo') => {\n  const isInertiaRequest = !!req.headers['x-inertia']\n  const partialData = req.headers['x-inertia-partial-data']?.split(',') ?? []\n  const loadedOnceProps = req.headers['x-inertia-except-once-props']?.split(',') ?? []\n  const isPartialRequest = partialData.includes(prop)\n  const hasPropAlready = loadedOnceProps.includes(prop)\n  const shouldResolveProp = !isInertiaRequest || isPartialRequest || !hasPropAlready\n\n  return {\n    isInertiaRequest,\n    partialData,\n    loadedOnceProps,\n    isPartialRequest,\n    hasPropAlready,\n    shouldResolveProp,\n  }\n}\n\napp.get('/once-props/page-a', (req, res) => {\n  const { shouldResolveProp } = getOncePropsData(req)\n\n  inertia.render(req, res, {\n    component: 'OnceProps/PageA',\n    props: {\n      foo: shouldResolveProp ? 'foo-a-' + Date.now() : undefined,\n      bar: 'bar-a',\n    },\n    onceProps: { foo: { prop: 'foo', expiresAt: null } },\n  })\n})\n\napp.get('/once-props/page-b', (req, res) => {\n  const { shouldResolveProp } = getOncePropsData(req)\n\n  inertia.render(req, res, {\n    component: 'OnceProps/PageB',\n    props: {\n      foo: shouldResolveProp ? 'foo-b-' + Date.now() : undefined,\n      bar: 'bar-b',\n    },\n    onceProps: { foo: { prop: 'foo', expiresAt: null } },\n  })\n})\n\napp.get('/once-props/page-c', (req, res) => {\n  inertia.render(req, res, {\n    component: 'OnceProps/PageC',\n  })\n})\n\napp.get('/once-props/page-d', (req, res) => {\n  const { shouldResolveProp } = getOncePropsData(req)\n\n  inertia.render(req, res, {\n    component: 'OnceProps/PageD',\n    props: {\n      foo: shouldResolveProp ? 'foo-d-' + Date.now() : undefined,\n      bar: 'bar-d',\n    },\n    onceProps: { foo: { prop: 'foo', expiresAt: null } },\n  })\n})\n\napp.get('/once-props/page-e', (req, res) => {\n  const { shouldResolveProp } = getOncePropsData(req)\n\n  inertia.render(req, res, {\n    component: 'OnceProps/PageE',\n    props: {\n      foo: shouldResolveProp ? 'foo-e-' + Date.now() : undefined,\n      bar: 'bar-e',\n    },\n    onceProps: { foo: { prop: 'foo', expiresAt: null } },\n  })\n})\n\napp.get('/once-props/partial-reload/:page', (req, res) => {\n  const page = req.params.page\n  const fooData = getOncePropsData(req, 'foo')\n  const barData = getOncePropsData(req, 'bar')\n\n  const isPartialReload = fooData.partialData.length > 0\n  const onceProps = {}\n\n  if (!isPartialReload || fooData.isPartialRequest) {\n    onceProps.foo = { prop: 'foo', expiresAt: null }\n  }\n\n  if (!isPartialReload || barData.isPartialRequest) {\n    onceProps.bar = { prop: 'bar', expiresAt: null }\n  }\n\n  inertia.render(req, res, {\n    component: `OnceProps/PartialReload${page.toUpperCase()}`,\n    props: {\n      foo: fooData.shouldResolveProp ? `foo-${page}-` + Date.now() : undefined,\n      bar: barData.shouldResolveProp ? `bar-${page}-` + Date.now() : undefined,\n    },\n    onceProps,\n  })\n})\n\napp.get('/once-props/deferred/:page', (req, res) => {\n  const { isPartialRequest, hasPropAlready } = getOncePropsData(req)\n  const page = req.params.page\n\n  if (isPartialRequest) {\n    return setTimeout(() => {\n      inertia.render(req, res, {\n        component: `OnceProps/DeferredPage${page.toUpperCase()}`,\n        props: {\n          foo: { text: `foo-${page}-` + Date.now() },\n          bar: `bar-${page}`,\n        },\n        onceProps: { foo: { prop: 'foo', expiresAt: null } },\n      })\n    }, 250)\n  }\n\n  inertia.render(req, res, {\n    component: `OnceProps/DeferredPage${page.toUpperCase()}`,\n    props: {\n      bar: `bar-${page}`,\n    },\n    deferredProps: hasPropAlready ? {} : { default: ['foo'] },\n    onceProps: { foo: { prop: 'foo', expiresAt: null } },\n  })\n})\n\napp.get('/once-props/slow-deferred/:page', (req, res) => {\n  const fooData = getOncePropsData(req, 'foo')\n  const barData = getOncePropsData(req, 'bar')\n  const page = req.params.page\n\n  // foo is deferred (slow), bar is not\n  if (fooData.isPartialRequest) {\n    return setTimeout(() => {\n      inertia.render(req, res, {\n        component: `OnceProps/SlowDeferredPage${page.toUpperCase()}`,\n        props: {\n          foo: `foo-${page}-` + Date.now(),\n          bar: barData.shouldResolveProp ? `bar-${page}-` + Date.now() : undefined,\n        },\n        onceProps: {\n          foo: { prop: 'foo', expiresAt: null },\n          bar: { prop: 'bar', expiresAt: null },\n        },\n      })\n    }, 1000)\n  }\n\n  inertia.render(req, res, {\n    component: `OnceProps/SlowDeferredPage${page.toUpperCase()}`,\n    props: {\n      bar: barData.shouldResolveProp ? `bar-${page}-` + Date.now() : undefined,\n    },\n    deferredProps: fooData.hasPropAlready ? {} : { default: ['foo'] },\n    onceProps: {\n      foo: { prop: 'foo', expiresAt: null },\n      bar: { prop: 'bar', expiresAt: null },\n    },\n  })\n})\n\napp.get('/once-props/ttl/:page', (req, res) => {\n  const { shouldResolveProp } = getOncePropsData(req)\n  const page = req.params.page\n  const expiresAt = Date.now() + 2000\n\n  inertia.render(req, res, {\n    component: `OnceProps/TtlPage${page.toUpperCase()}`,\n    props: {\n      foo: shouldResolveProp ? `foo-${page}-` + Date.now() : undefined,\n      bar: `bar-${page}`,\n    },\n    onceProps: { foo: { prop: 'foo', expiresAt } },\n  })\n})\n\napp.get('/once-props/optional/:page', (req, res) => {\n  const { isPartialRequest, hasPropAlready } = getOncePropsData(req)\n  const page = req.params.page\n\n  inertia.render(req, res, {\n    component: `OnceProps/OptionalPage${page.toUpperCase()}`,\n    props: {\n      foo: isPartialRequest ? `foo-${page}-` + Date.now() : undefined,\n      bar: `bar-${page}`,\n    },\n    onceProps: isPartialRequest || hasPropAlready ? { foo: { prop: 'foo', expiresAt: null } } : {},\n  })\n})\n\napp.get('/once-props/merge/:page', (req, res) => {\n  const { shouldResolveProp } = getOncePropsData(req, 'items')\n  const page = req.params.page\n\n  inertia.render(req, res, {\n    component: `OnceProps/MergePage${page.toUpperCase()}`,\n    props: {\n      items: shouldResolveProp ? new Array(3).fill(page) : undefined,\n      bar: `bar-${page}`,\n    },\n    mergeProps: ['items'],\n    onceProps: { items: { prop: 'items', expiresAt: null } },\n  })\n})\n\napp.get('/once-props/custom-key/:page', (req, res) => {\n  const page = req.params.page\n  const propName = page === 'a' ? 'userPermissions' : 'permissions'\n  const { shouldResolveProp } = getOncePropsData(req, 'user-permissions')\n\n  inertia.render(req, res, {\n    component: `OnceProps/CustomKeyPage${page.toUpperCase()}`,\n    props: {\n      [propName]: shouldResolveProp ? `perms-${page}-` + Date.now() : undefined,\n      bar: `bar-${page}`,\n    },\n    onceProps: { 'user-permissions': { prop: propName, expiresAt: null } },\n  })\n})\n\napp.get('/once-props/client-side-visit', (req, res) => {\n  const { shouldResolveProp } = getOncePropsData(req)\n\n  inertia.render(req, res, {\n    component: 'OnceProps/ClientSideVisit',\n    props: {\n      foo: shouldResolveProp ? 'foo-initial' : undefined,\n      bar: 'bar-initial',\n    },\n    onceProps: { foo: { prop: 'foo', expiresAt: null } },\n  })\n})\n\napp.get('/deferred-props/back-button/a', (req, res) => {\n  if (!req.headers['x-inertia-partial-data']) {\n    return inertia.render(req, res, {\n      component: 'DeferredProps/BackButton/PageA',\n      deferredProps: {\n        fast: ['fastProp'],\n        slow: ['slowProp'],\n      },\n      props: {},\n    })\n  }\n\n  const delay = req.headers['x-inertia-partial-data']?.includes('fastProp') ? 100 : 600\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'DeferredProps/BackButton/PageA',\n        props: {\n          fastProp: req.headers['x-inertia-partial-data']?.includes('fastProp') ? 'Fast prop loaded' : undefined,\n          slowProp: req.headers['x-inertia-partial-data']?.includes('slowProp') ? 'Slow prop loaded' : undefined,\n        },\n      }),\n    delay,\n  )\n})\n\napp.get('/deferred-props/back-button/b', (req, res) => {\n  if (!req.headers['x-inertia-partial-data']) {\n    return inertia.render(req, res, {\n      component: 'DeferredProps/BackButton/PageB',\n      deferredProps: {\n        default: ['data'],\n      },\n      props: {},\n    })\n  }\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'DeferredProps/BackButton/PageB',\n        props: {\n          data: req.headers['x-inertia-partial-data']?.includes('data') ? 'Page B data loaded' : undefined,\n        },\n      }),\n    400,\n  )\n})\n\napp.get('/reload/concurrent', (req, res) => {\n  const partialData = req.headers['x-inertia-partial-data']\n\n  if (!partialData) {\n    return inertia.render(req, res, {\n      component: 'Reload/Concurrent',\n      props: {\n        foo: 'initial foo',\n        bar: 'initial bar',\n      },\n    })\n  }\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'Reload/Concurrent',\n        props: {\n          foo: partialData.includes('foo') ? `foo reloaded at ${Date.now()}` : undefined,\n          bar: partialData.includes('bar') ? `bar reloaded at ${Date.now()}` : undefined,\n        },\n      }),\n    600,\n  )\n})\n\napp.get('/reload/concurrent-with-data', (req, res) => {\n  const partialData = req.headers['x-inertia-partial-data']\n  const timeframe = req.query.timeframe || 'day'\n\n  if (!partialData) {\n    return inertia.render(req, res, {\n      component: 'Reload/ConcurrentWithData',\n      props: {\n        foo: 'initial foo',\n        bar: 'initial bar',\n        timeframe,\n      },\n    })\n  }\n\n  setTimeout(\n    () =>\n      inertia.render(req, res, {\n        component: 'Reload/ConcurrentWithData',\n        props: {\n          foo: partialData.includes('foo') ? `foo reloaded (${timeframe}) at ${Date.now()}` : undefined,\n          bar: partialData.includes('bar') ? `bar reloaded (${timeframe}) at ${Date.now()}` : undefined,\n          timeframe,\n        },\n      }),\n    600,\n  )\n})\n\napp.get('/network-error', (req, res) => inertia.render(req, res, { component: 'NetworkError' }))\n\napp.all('*page', (req, res) => inertia.render(req, res))\n\n// Send errors to the console (instead of crashing the server)\napp.use((err, req, res, next) => {\n  console.error('❌ Express Error:', err)\n  res.status(500).send('Internal Server Error')\n})\n\nconst adapterPorts = {\n  vue3: 13715,\n  react: 13716,\n  svelte: 13717,\n}\n\nshowServerStatus(inertia.package, adapterPorts[inertia.package])\n\napp.listen(adapterPorts[inertia.package])\n"
  },
  {
    "path": "tests/app/ssr.js",
    "content": "const http = require('http')\n\nconst SSR_PORT = 13714\n\nmodule.exports = {\n  render(pageData) {\n    return new Promise((resolve, reject) => {\n      const postData = JSON.stringify(pageData)\n\n      const req = http.request(\n        {\n          hostname: 'localhost',\n          port: SSR_PORT,\n          path: '/render',\n          method: 'POST',\n          headers: {\n            'Content-Type': 'application/json',\n            'Content-Length': Buffer.byteLength(postData),\n          },\n        },\n        (res) => {\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 SSR response: ${data}`))\n            }\n          })\n        },\n      )\n\n      req.on('error', (e) => reject(new Error(`SSR server error: ${e.message}`)))\n      req.write(postData)\n      req.end()\n    })\n  },\n}\n"
  },
  {
    "path": "tests/client-side-visits-props.spec.ts",
    "content": "import test, { expect } from '@playwright/test'\nimport { requests } from './support'\n\ntest.describe('Client-side visits with props manipulation', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/client-side-visit/props')\n    requests.listen(page)\n  })\n\n  test.describe('replaceProp', () => {\n    test('replaceProp replaces a string prop', async ({ page }) => {\n      await expect(page.getByText('User: John Doe (Age: 30)')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Replace user.name' }).click()\n      await expect(page.getByText('User: Jane Smith (Age: 30)')).toBeVisible()\n      expect(requests.requests.length).toBe(0)\n    })\n\n    test('replaceProp replaces a number prop', async ({ page }) => {\n      await expect(page.getByText('Count: 5')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Replace count', exact: true }).click()\n      await expect(page.getByText('Count: 10')).toBeVisible()\n      expect(requests.requests.length).toBe(0)\n    })\n\n    test('replaceProp works with functions', async ({ page }) => {\n      await expect(page.getByText('Count: 5')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Replace count (function)' }).click()\n      await expect(page.getByText('Count: 10')).toBeVisible()\n      expect(requests.requests.length).toBe(0)\n    })\n  })\n\n  test.describe('appendToProp', () => {\n    test('appendToProp appends single item to array', async ({ page }) => {\n      await expect(page.getByText('Items: [\"item1\",\"item2\"]')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Append to items (single)' }).click()\n      await expect(page.getByText('Items: [\"item1\",\"item2\",\"item3\"]')).toBeVisible()\n      expect(requests.requests.length).toBe(0)\n    })\n\n    test('appendToProp appends multiple items to array', async ({ page }) => {\n      await expect(page.getByText('Items: [\"item1\",\"item2\"]')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Append to items (multiple)' }).click()\n      await expect(page.getByText('Items: [\"item1\",\"item2\",[\"item4\",\"item5\"]]')).toBeVisible()\n      expect(requests.requests.length).toBe(0)\n    })\n\n    test('appendToProp works with functions', async ({ page }) => {\n      await expect(page.getByText('Tags: [{\"id\":1,\"name\":\"tag1\"},{\"id\":2,\"name\":\"tag2\"}]')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Append to tags (function)' }).click()\n      await expect(\n        page.getByText('Tags: [{\"id\":1,\"name\":\"tag1\"},{\"id\":2,\"name\":\"tag2\"},{\"id\":3,\"name\":\"tag3\"}]'),\n      ).toBeVisible()\n      expect(requests.requests.length).toBe(0)\n    })\n\n    test('appendToProp handles array to array', async ({ page }) => {\n      await expect(page.getByText('Tags: [{\"id\":1,\"name\":\"tag1\"},{\"id\":2,\"name\":\"tag2\"}]')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Append array to array (objects)' }).click()\n      await expect(\n        page.getByText(\n          'Tags: [{\"id\":1,\"name\":\"tag1\"},{\"id\":2,\"name\":\"tag2\"},[{\"id\":3,\"name\":\"tag3\"},{\"id\":4,\"name\":\"tag4\"}]]',\n        ),\n      ).toBeVisible()\n      expect(requests.requests.length).toBe(0)\n    })\n  })\n\n  test.describe('prependToProp', () => {\n    test('prependToProp prepends single item to array', async ({ page }) => {\n      await expect(page.getByText('Items: [\"item1\",\"item2\"]')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Prepend to items (single)' }).click()\n      await expect(page.getByText('Items: [\"item0\",\"item1\",\"item2\"]')).toBeVisible()\n      expect(requests.requests.length).toBe(0)\n    })\n\n    test('prependToProp prepends multiple items to array', async ({ page }) => {\n      await expect(page.getByText('Items: [\"item1\",\"item2\"]')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Prepend to items (multiple)' }).click()\n      await expect(page.getByText('Items: [[\"itemA\",\"itemB\"],\"item1\",\"item2\"]')).toBeVisible()\n      expect(requests.requests.length).toBe(0)\n    })\n\n    test('prependToProp works with functions', async ({ page }) => {\n      await expect(page.getByText('Tags: [{\"id\":1,\"name\":\"tag1\"},{\"id\":2,\"name\":\"tag2\"}]')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Prepend to tags (function)' }).click()\n      await expect(\n        page.getByText('Tags: [{\"id\":0,\"name\":\"tag0\"},{\"id\":1,\"name\":\"tag1\"},{\"id\":2,\"name\":\"tag2\"}]'),\n      ).toBeVisible()\n      expect(requests.requests.length).toBe(0)\n    })\n  })\n\n  test.describe('edge cases', () => {\n    test('appendToProp handles single + single values (mergeArrays)', async ({ page }) => {\n      await expect(page.getByText('Single Value: \"hello\"')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Append to non-array (single + single)' }).click()\n      await expect(page.getByText('Single Value: [\"hello\",\"world\"]')).toBeVisible()\n      expect(requests.requests.length).toBe(0)\n    })\n\n    test('prependToProp handles single + single values (mergeArrays)', async ({ page }) => {\n      await expect(page.getByText('Single Value: \"hello\"')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Prepend to non-array (single + single)' }).click()\n      await expect(page.getByText('Single Value: [\"hey\",\"hello\"]')).toBeVisible()\n      expect(requests.requests.length).toBe(0)\n    })\n\n    test('appendToProp handles array to non-array', async ({ page }) => {\n      await expect(page.getByText('Single Value: \"hello\"')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Append array to non-array (single + array)' }).click()\n      await expect(page.getByText('Single Value: [\"hello\",[\"there\",\"world\"]]')).toBeVisible()\n      expect(requests.requests.length).toBe(0)\n    })\n\n    test('prependToProp handles array to non-array', async ({ page }) => {\n      await expect(page.getByText('Single Value: \"hello\"')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Prepend array to non-array (array + single)' }).click()\n      await expect(page.getByText('Single Value: [[\"hey\",\"hi\"],\"hello\"]')).toBeVisible()\n      expect(requests.requests.length).toBe(0)\n    })\n\n    test('appendToProp handles undefined values', async ({ page }) => {\n      await expect(page.locator('text=Undefined Value:')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Append to undefined' }).click()\n      await expect(page.getByText('Undefined Value: [\"new value\"]')).toBeVisible()\n      expect(requests.requests.length).toBe(0)\n    })\n\n    test('prependToProp handles undefined values', async ({ page }) => {\n      await expect(page.locator('text=Undefined Value:')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Prepend to undefined' }).click()\n      await expect(page.getByText('Undefined Value: [\"start value\"]')).toBeVisible()\n      expect(requests.requests.length).toBe(0)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/client-side-visits-sequential.spec.ts",
    "content": "import test, { expect } from '@playwright/test'\nimport { requests } from './support'\n\ntest.describe('Client-side visits with sequential prop updates', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/client-side-visit/sequential')\n    requests.listen(page)\n  })\n\n  test('replaceProp called sequentially applies all changes', async ({ page }) => {\n    await expect(page.getByText('Foo: foo')).toBeVisible()\n    await expect(page.getByText('Bar: bar')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Replace foo and bar sequentially' }).click()\n\n    await expect(page.getByText('Foo: baz')).toBeVisible()\n    await expect(page.getByText('Bar: qux')).toBeVisible()\n    expect(requests.requests.length).toBe(0)\n  })\n})\n"
  },
  {
    "path": "tests/client-side-visits.spec.ts",
    "content": "import test, { expect } from '@playwright/test'\nimport { pageLoads, requests } from './support'\n\ntest('replaces the page client side', async ({ page, browserName }) => {\n  pageLoads.watch(page)\n\n  await page.goto('/client-side-visit')\n\n  requests.listen(page)\n\n  await expect(page.getByText('foo from server')).toBeVisible()\n  await expect(page.getByText('bar from server')).toBeVisible()\n  await expect(page.getByText('foo from client')).not.toBeVisible()\n  await expect(page.getByText('Finished: 0')).toBeVisible()\n  await expect(page.getByText('Success: 0')).toBeVisible()\n\n  await page.getByRole('button', { name: 'Replace', exact: true }).click()\n\n  await expect(page).toHaveURL('/client-side-visit')\n  await expect(page.getByText('foo from server')).not.toBeVisible()\n  await expect(page.getByText('foo from client')).toBeVisible()\n  await expect(page.getByText('bar from server')).toBeVisible()\n  await expect(page.getByText('Finished: 1')).toBeVisible()\n  await expect(page.getByText('Success: 1')).toBeVisible()\n\n  await expect(requests.requests.length).toBe(0)\n\n  const historyLength = await page.evaluate(() => window.history.length)\n  // Firefox doesn't count the initial about:blank page in history.length\n  await expect(historyLength).toBe(browserName === 'firefox' ? 1 : 2)\n})\n\ntest('preserves the state based on the errors object', async ({ page }) => {\n  await page.goto('/client-side-visit')\n  const randomValue = await page.locator('#random').innerText()\n\n  await page.getByRole('button', { name: 'Replace with errors' }).click()\n  const randomValueAfter = await page.locator('#random').innerText()\n  await expect(randomValueAfter).toBe(randomValue)\n\n  await page.getByRole('button', { name: 'Replace without errors' }).click()\n  const randomValueAfterSecond = await page.locator('#random').innerText()\n  await expect(randomValueAfterSecond).not.toBe(randomValue)\n})\n\ntest('fires an onError callback when the props has errors', async ({ page }) => {\n  pageLoads.watch(page)\n\n  await page.goto('/client-side-visit')\n\n  requests.listen(page)\n\n  await expect(page.getByText('Errors: 0')).toBeVisible()\n  await expect(page.getByText('Finished: 0')).toBeVisible()\n  await expect(page.getByText('Success: 0')).toBeVisible()\n\n  await page.getByRole('button', { name: 'Errors (default)' }).click()\n\n  await expect(page.getByText('Finished: 1')).toBeVisible()\n  await expect(page.getByText('Errors: 2')).toBeVisible()\n  await expect(page.getByText('Success: 0')).toBeVisible()\n\n  await expect(requests.requests.length).toBe(0)\n})\n\ntest('fires an onError callback when the props has errors in a custom bag', async ({ page }) => {\n  pageLoads.watch(page)\n\n  await page.goto('/client-side-visit')\n\n  requests.listen(page)\n\n  await expect(page.getByText('Errors: 0')).toBeVisible()\n  await expect(page.getByText('Finished: 0')).toBeVisible()\n  await expect(page.getByText('Success: 0')).toBeVisible()\n\n  await page.getByRole('button', { name: 'Errors (bag)' }).click()\n\n  await expect(page.getByText('Finished: 1')).toBeVisible()\n  await expect(page.getByText('Errors: 1')).toBeVisible()\n  await expect(page.getByText('Success: 0')).toBeVisible()\n  await expect(requests.requests.length).toBe(0)\n})\n\ntest('pushes the page client side', async ({ page, browserName }) => {\n  pageLoads.watch(page)\n\n  await page.goto('/client-side-visit')\n\n  requests.listen(page)\n\n  await expect(page.getByText('foo from server')).toBeVisible()\n  await expect(page.getByText('bar from server')).toBeVisible()\n  await expect(page.getByText('baz from client')).not.toBeVisible()\n\n  await page.getByRole('button', { name: 'Push' }).click()\n\n  await expect(page).toHaveURL('/client-side-visit-2')\n  await expect(page.getByText('foo from server')).not.toBeVisible()\n  await expect(page.getByText('bar from server')).not.toBeVisible()\n  await expect(page.getByText('baz from client')).toBeVisible()\n\n  await expect(requests.requests.length).toBe(0)\n\n  const historyLength = await page.evaluate(() => window.history.length)\n  // Firefox doesn't count the initial about:blank page in history.length\n  await expect(historyLength).toBe(browserName === 'firefox' ? 2 : 3)\n})\n"
  },
  {
    "path": "tests/config.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport { requests, shouldBeDumpPage } from './support'\n\ntest.describe('passing defaults to createInertiaApp', () => {\n  test('applies visitOptions from app defaults', async ({ page }) => {\n    await page.goto('/?withAppDefaults=true')\n    await page.evaluate(() => window.testing.Inertia.visit('/dump/get'))\n\n    const dump = await shouldBeDumpPage(page, 'get')\n\n    await expect(dump.headers).toMatchObject({\n      'x-from-app-defaults': 'test',\n    })\n  })\n})\n\ntest.describe('updating config via config instance', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/custom-config')\n  })\n\n  test('visit options', async ({ page }) => {\n    await page.getByRole('button', { name: 'Post Dump' }).click()\n    const dump = await shouldBeDumpPage(page, 'post')\n\n    await expect(dump.headers).toMatchObject({\n      'x-from-link': 'foo',\n      'x-from-callback': 'bar',\n    })\n  })\n\n  test('prefetch duration', async ({ page }) => {\n    const link = await page.getByRole('link', { name: 'Prefetch Link' })\n    const prefetchPromise = page.waitForResponse(\n      (response) => response.url().includes('/dump/get') && response.request().headers().purpose === 'prefetch',\n    )\n\n    // Wait for the page to be prefetched\n    await link.hover()\n    await prefetchPromise\n\n    // Wait two seconds\n    await page.waitForTimeout(2020)\n\n    // Now click the link and ensure a new request is made\n    requests.listen(page)\n    await link.click()\n    await shouldBeDumpPage(page, 'get')\n    await expect.poll(() => requests.requests.length).toBe(1)\n  })\n\n  test('recently successful duration', async ({ page }) => {\n    const link = await page.getByRole('button', { name: 'Submit Form' })\n    const message = page.getByText('Form was recently successful!')\n    await link.click()\n    await message.waitFor()\n\n    await page.waitForTimeout(1020)\n    await expect(message).toBeHidden()\n  })\n})\n"
  },
  {
    "path": "tests/core/config.test.ts",
    "content": "import test, { expect } from '@playwright/test'\nimport { Config } from '../../packages/core/src/config'\n\ntype TestConfig = {\n  form: {\n    recentlySuccessfulDuration: number\n  }\n  prefetch: {\n    cacheFor: number\n    cacheTags: string[]\n  }\n  nested: {\n    deep: {\n      value: string\n    }\n  }\n  optional?: boolean\n}\n\nfunction createConfig(): Config<TestConfig> {\n  return new Config<TestConfig>({\n    form: {\n      recentlySuccessfulDuration: 2_000,\n    },\n    prefetch: {\n      cacheFor: 30_000,\n      cacheTags: [],\n    },\n    nested: {\n      deep: {\n        value: 'default',\n      },\n    },\n  })\n}\n\ntest.describe('config.ts', () => {\n  test.describe('Config class', () => {\n    test('returns defaults and custom values, falling back as needed', () => {\n      const config = createConfig()\n\n      expect(config.get('form.recentlySuccessfulDuration')).toBe(2_000)\n      expect(config.get('prefetch.cacheFor')).toBe(30_000)\n\n      config.set('prefetch.cacheFor', 60_000)\n\n      expect(config.get('prefetch.cacheFor')).toBe(60_000)\n      expect(config.get('prefetch.cacheTags')).toEqual([])\n      expect(config.get('form.recentlySuccessfulDuration')).toBe(2_000)\n    })\n\n    test('sets values using dot notation and preserves siblings', () => {\n      const config = createConfig()\n\n      config.set('form.recentlySuccessfulDuration', 3_000)\n      expect(config.get('form.recentlySuccessfulDuration')).toBe(3_000)\n\n      config.set('prefetch.cacheFor', 60_000)\n      expect(config.get('prefetch.cacheFor')).toBe(60_000)\n      expect(config.get('prefetch.cacheTags')).toEqual([])\n    })\n\n    test('sets multiple values using object notation', () => {\n      const config = createConfig()\n\n      config.set({\n        'form.recentlySuccessfulDuration': 3_000,\n        'prefetch.cacheFor': 60_000,\n      })\n\n      expect(config.get('form.recentlySuccessfulDuration')).toBe(3_000)\n      expect(config.get('prefetch.cacheFor')).toBe(60_000)\n      expect(config.get('prefetch.cacheTags')).toEqual([])\n    })\n\n    test('replaces the entire config', () => {\n      const config = createConfig()\n\n      config.set({\n        'form.recentlySuccessfulDuration': 3_000,\n        'prefetch.cacheFor': 60_000,\n      })\n\n      config.replace({\n        prefetch: {\n          cacheFor: 120_000,\n          cacheTags: ['tag1', 'tag2'],\n        },\n      })\n\n      expect(config.get('form.recentlySuccessfulDuration')).toBe(2_000)\n      expect(config.get('prefetch.cacheFor')).toBe(120_000)\n      expect(config.get('prefetch.cacheTags')).toEqual(['tag1', 'tag2'])\n    })\n\n    test('extends type and defaults without overriding user config', () => {\n      type BaseConfig = {\n        base: { value: number }\n      }\n\n      type ExtendedConfig = {\n        extended: { value: string }\n      }\n\n      const config = new Config<BaseConfig>({\n        base: { value: 1 },\n      })\n\n      config.set('base.value', 5)\n      expect(config.get('base.value')).toBe(5)\n\n      const extended = config.extend<ExtendedConfig>({\n        extended: { value: 'test' },\n      })\n\n      expect(extended.get('base.value')).toBe(5)\n      expect(extended.get('extended.value')).toBe('test')\n    })\n\n    test('returns undefined for invalid keys', () => {\n      const config = createConfig()\n\n      // @ts-expect-error - Testing invalid key\n      expect(config.get('nonexistent')).toBeUndefined()\n      // @ts-expect-error - Testing invalid nested key\n      expect(config.get('form.nonexistent')).toBeUndefined()\n    })\n\n    test('returns undefined for optional keys not set', () => {\n      const config = createConfig()\n\n      expect(config.get('optional')).toBeUndefined()\n    })\n  })\n})\n"
  },
  {
    "path": "tests/core/formObject.test.ts",
    "content": "import test, { expect } from '@playwright/test'\nimport { formDataToObject } from '../../packages/core/src/formObject'\n\nfunction makeFormData(entries: [string, string | Blob][] = []): FormData {\n  const formData = new FormData()\n  for (const [key, value] of entries) {\n    formData.append(key, value)\n  }\n  return formData\n}\n\ntest.describe('formObject.ts', () => {\n  test.describe('formDataToObject', () => {\n    test('returns an empty object when no fields are present', () => {\n      const formData = new FormData()\n      expect(formDataToObject(formData)).toEqual({})\n    })\n\n    test('converts flat key-value pairs into an object', () => {\n      const formData = makeFormData([\n        ['name', 'John'],\n        ['email', 'john@example.com'],\n      ])\n\n      expect(formDataToObject(formData)).toEqual({\n        name: 'John',\n        email: 'john@example.com',\n      })\n    })\n\n    test('creates nested objects using bracket notation', () => {\n      const formData = makeFormData([\n        ['user[name]', 'John'],\n        ['user[email]', 'john@example.com'],\n        ['user[address][city]', 'Paris'],\n      ])\n\n      expect(formDataToObject(formData)).toEqual({\n        user: {\n          name: 'John',\n          email: 'john@example.com',\n          address: { city: 'Paris' },\n        },\n      })\n    })\n\n    test('creates arrays from keys using empty bracket notation', () => {\n      const formData = makeFormData([\n        ['tags[]', 'one'],\n        ['tags[]', 'two'],\n        ['tags[]', 'three'],\n      ])\n\n      expect(formDataToObject(formData)).toEqual({\n        tags: ['one', 'two', 'three'],\n      })\n    })\n\n    test('overwrites earlier values when keys are repeated without brackets', () => {\n      const formData = makeFormData([\n        ['category', 'books'],\n        ['category', 'movies'],\n      ])\n\n      expect(formDataToObject(formData)).toEqual({\n        category: 'movies',\n      })\n    })\n\n    test('builds indexed arrays of nested objects', () => {\n      const formData = makeFormData([\n        ['items[0][name]', 'A'],\n        ['items[0][price]', '10'],\n        ['items[1][name]', 'B'],\n        ['items[1][price]', '20'],\n      ])\n\n      expect(formDataToObject(formData)).toEqual({\n        items: [\n          { name: 'A', price: '10' },\n          { name: 'B', price: '20' },\n        ],\n      })\n    })\n\n    test('excludes empty files from the final result', () => {\n      const emptyFile = new File([], '')\n      const formData = makeFormData([['avatar', emptyFile]])\n\n      expect(formDataToObject(formData)).toEqual({})\n    })\n\n    test('includes non-empty files as File instances', () => {\n      const file = new File(['hello'], 'hello.txt', { type: 'text/plain' })\n      const formData = makeFormData([['avatar', file]])\n\n      const result = formDataToObject(formData)\n      expect(result.avatar).toBeInstanceOf(File)\n      expect(result.avatar.name).toBe('hello.txt')\n    })\n\n    test('collects multiple files from file[] input into an array', () => {\n      const fileA = new File(['A'], 'a.txt')\n      const fileB = new File(['B'], 'b.txt')\n      const formData = makeFormData([\n        ['documents[]', fileA],\n        ['documents[]', fileB],\n      ])\n\n      const result = formDataToObject(formData)\n      expect(result.documents).toHaveLength(2)\n      expect(result.documents[0].name).toBe('a.txt')\n      expect(result.documents[1].name).toBe('b.txt')\n    })\n\n    test('omits file[] keys if all files are empty', () => {\n      const emptyA = new File([], '')\n      const emptyB = new File([], '')\n      const formData = makeFormData([\n        ['documents[]', emptyA],\n        ['documents[]', emptyB],\n      ])\n\n      expect(formDataToObject(formData)).toEqual({})\n    })\n\n    test('handles a combination of nested structures, arrays, and scalars', () => {\n      const formData = makeFormData([\n        ['user[name]', 'Jane'],\n        ['user[roles][]', 'admin'],\n        ['user[roles][]', 'editor'],\n        ['settings[notifications][email]', '1'],\n        ['settings[notifications][sms]', '0'],\n        ['token', 'abc123'],\n      ])\n\n      expect(formDataToObject(formData)).toEqual({\n        user: {\n          name: 'Jane',\n          roles: ['admin', 'editor'],\n        },\n        settings: {\n          notifications: {\n            email: '1',\n            sms: '0',\n          },\n        },\n        token: 'abc123',\n      })\n    })\n\n    test('handles numeric string values correctly', () => {\n      const formData = makeFormData([\n        ['count', '0'],\n        ['price', '123.45'],\n      ])\n\n      expect(formDataToObject(formData)).toEqual({\n        count: '0',\n        price: '123.45',\n      })\n    })\n\n    test('supports mixed-type arrays: string and file', () => {\n      const file = new File(['content'], 'file.txt')\n      const formData = makeFormData([\n        ['attachments[]', 'note'],\n        ['attachments[]', file],\n      ])\n\n      const result = formDataToObject(formData)\n      expect(Array.isArray(result.attachments)).toBe(true)\n      expect(result.attachments[0]).toBe('note')\n      expect(result.attachments[1]).toBeInstanceOf(File)\n      expect(result.attachments[1].name).toBe('file.txt')\n    })\n\n    test('converts dotted keys into nested objects', () => {\n      const formData = makeFormData([\n        ['user.name', 'John'],\n        ['user.email', 'john@example.com'],\n        ['user.address.city', 'Paris'],\n        ['user.address.country', 'France'],\n      ])\n\n      expect(formDataToObject(formData)).toEqual({\n        user: {\n          name: 'John',\n          email: 'john@example.com',\n          address: {\n            city: 'Paris',\n            country: 'France',\n          },\n        },\n      })\n    })\n\n    test('handles escaped dots as literal characters in keys', () => {\n      const formData = makeFormData([\n        ['user\\\\.name', 'Literal key'],\n        ['config.app\\\\.version', '1.0.0'],\n        ['deeply\\\\.nested\\\\.key\\\\.with\\\\.escapes', 'value'],\n      ])\n\n      expect(formDataToObject(formData)).toEqual({\n        'user.name': 'Literal key',\n        config: {\n          'app.version': '1.0.0',\n        },\n        'deeply.nested.key.with.escapes': 'value',\n      })\n    })\n\n    test('handles complex mixed dotted and bracket notation', () => {\n      const formData = makeFormData([\n        ['users.company[address].street', '123 Main St'],\n        ['users.company[address].number', '42'],\n        ['users.profile.settings[theme].mode', 'dark'],\n        ['data.items[0].tags[]', 'urgent'],\n        ['data.items[0].tags[]', 'important'],\n        ['data.items[1].name', 'Second Item'],\n      ])\n\n      expect(formDataToObject(formData)).toEqual({\n        users: {\n          company: {\n            address: {\n              street: '123 Main St',\n              number: '42',\n            },\n          },\n          profile: {\n            settings: {\n              theme: {\n                mode: 'dark',\n              },\n            },\n          },\n        },\n        data: {\n          items: [\n            {\n              tags: ['urgent', 'important'],\n            },\n            {\n              name: 'Second Item',\n            },\n          ],\n        },\n      })\n    })\n\n    test('handles mixed numeric and string keys as objects', () => {\n      const formData = makeFormData([\n        ['fields[entries][100][name]', 'John Doe'],\n        ['fields[entries][100][email]', 'john@example.com'],\n        ['fields[entries][new:1][name]', 'Jane Smith'],\n        ['fields[entries][new:1][email]', 'jane@example.com'],\n      ])\n\n      const result = formDataToObject(formData)\n\n      expect(Array.isArray(result.fields.entries)).toBe(false)\n      expect(typeof result.fields.entries).toBe('object')\n\n      expect(Object.keys(result.fields.entries)).toHaveLength(2)\n\n      expect(result.fields.entries['100']).toEqual({\n        name: 'John Doe',\n        email: 'john@example.com',\n      })\n\n      expect(result.fields.entries['new:1']).toEqual({\n        name: 'Jane Smith',\n        email: 'jane@example.com',\n      })\n    })\n\n    test('still creates arrays for sequential numeric indices', () => {\n      const formData = makeFormData([\n        ['items[0][name]', 'First'],\n        ['items[1][name]', 'Second'],\n        ['items[2][name]', 'Third'],\n      ])\n\n      const result = formDataToObject(formData)\n\n      // Should create an array for sequential indices\n      expect(Array.isArray(result.items)).toBe(true)\n      expect(result.items).toEqual([{ name: 'First' }, { name: 'Second' }, { name: 'Third' }])\n    })\n\n    test('creates objects for non-sequential numeric keys', () => {\n      const formData = makeFormData([\n        ['items[0][name]', 'First'],\n        ['items[5][name]', 'Sixth'],\n        ['items[10][name]', 'Eleventh'],\n      ])\n\n      const result = formDataToObject(formData)\n\n      expect(Array.isArray(result.items)).toBe(false)\n      expect(typeof result.items).toBe('object')\n      expect(Object.keys(result.items)).toHaveLength(3)\n      expect(result.items['0']).toEqual({ name: 'First' })\n      expect(result.items['5']).toEqual({ name: 'Sixth' })\n      expect(result.items['10']).toEqual({ name: 'Eleventh' })\n    })\n\n    test('creates objects when mixing numeric and string keys', () => {\n      const formData = makeFormData([\n        ['users[123][name]', 'User 123'],\n        ['users[admin][name]', 'Admin User'],\n        ['users[0][name]', 'User 0'],\n      ])\n\n      const result = formDataToObject(formData)\n\n      expect(Array.isArray(result.users)).toBe(false)\n      expect(typeof result.users).toBe('object')\n      expect(Object.keys(result.users)).toHaveLength(3)\n      expect(result.users['123']).toEqual({ name: 'User 123' })\n      expect(result.users['admin']).toEqual({ name: 'Admin User' })\n      expect(result.users['0']).toEqual({ name: 'User 0' })\n    })\n\n    test('handles explicit indexed arrays correctly', () => {\n      const formData = makeFormData([\n        ['emails[1]', 'second@example.com'],\n        ['emails[0]', 'first@example.com'],\n        ['emails[2]', 'third@example.com'],\n      ])\n\n      const result = formDataToObject(formData)\n\n      expect(Array.isArray(result.emails)).toBe(true)\n      expect(result.emails).toEqual(['first@example.com', 'second@example.com', 'third@example.com'])\n    })\n\n    test('handles mixed empty bracket and explicit index notation - empty brackets first', () => {\n      const formData = makeFormData([\n        ['tags[]', 'tag1'],\n        ['tags[]', 'tag2'],\n        ['tags[2]', 'tag3'],\n        ['tags[3]', 'tag4'],\n      ])\n\n      const result = formDataToObject(formData)\n\n      expect(Array.isArray(result.tags)).toBe(true)\n      expect(result.tags).toEqual(['tag1', 'tag2', 'tag3', 'tag4'])\n    })\n\n    test('handles mixed empty bracket and explicit index notation - explicit indices first', () => {\n      const formData = makeFormData([\n        ['tags[2]', 'tag1'],\n        ['tags[3]', 'tag2'],\n        ['tags[]', 'tag3'],\n        ['tags[]', 'tag4'],\n      ])\n\n      const result = formDataToObject(formData)\n\n      expect(Array.isArray(result.tags)).toBe(true)\n      expect(result.tags).toEqual(['tag1', 'tag2', 'tag3', 'tag4'])\n    })\n\n    test('handles mixed empty bracket and explicit index notation - mixed', () => {\n      const formData = makeFormData([\n        ['tags[2]', 'tag1'],\n        ['tags[3]', 'tag2'],\n        ['tags[]', 'tag3'],\n        ['tags[]', 'tag4'],\n        ['tags[4]', 'tag5'],\n        ['tags[5]', 'tag6'],\n      ])\n\n      const result = formDataToObject(formData)\n\n      expect(Array.isArray(result.tags)).toBe(true)\n      expect(result.tags).toEqual(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])\n    })\n  })\n})\n"
  },
  {
    "path": "tests/core/objectUtils.test.ts",
    "content": "import test, { expect } from '@playwright/test'\nimport { objectsAreEqual } from '../../packages/core/src/objectUtils'\n\ntest.describe('objectUtils.ts', () => {\n  test.describe('objectsAreEqual', () => {\n    test.describe('basic equality', () => {\n      test('returns true for identical objects', () => {\n        const obj1 = { a: 1, b: 2, c: 3 }\n        const obj2 = { a: 1, b: 2, c: 3 }\n\n        expect(objectsAreEqual(obj1, obj2, [])).toBe(true)\n      })\n\n      test('returns true for same reference', () => {\n        const obj = { a: 1, b: 2 }\n\n        expect(objectsAreEqual(obj, obj, [])).toBe(true)\n      })\n\n      test('returns true for empty objects', () => {\n        expect(objectsAreEqual({}, {}, [])).toBe(true)\n      })\n\n      test('returns false for objects with different values', () => {\n        const obj1 = { a: 1, b: 2 }\n        const obj2 = { a: 1, b: 3 }\n\n        expect(objectsAreEqual(obj1, obj2, [])).toBe(false)\n      })\n    })\n\n    test.describe('asymmetric objects', () => {\n      test('returns false when second object has additional keys', () => {\n        const obj1 = { a: 1, b: 2 }\n        const obj2 = { a: 1, b: 2, c: 3 }\n\n        expect(objectsAreEqual(obj1, obj2, [])).toBe(false)\n      })\n\n      test('returns false when first object has additional keys', () => {\n        const obj1 = { a: 1, b: 2, c: 3 }\n        const obj2 = { a: 1, b: 2 }\n\n        expect(objectsAreEqual(obj1, obj2, [])).toBe(false)\n      })\n\n      test('handles objects with overlapping and unique keys', () => {\n        const obj1 = {\n          name: 'test',\n          type: 'example',\n          config: { option: 'value' },\n        }\n\n        const obj2 = {\n          name: 'test',\n          type: 'example',\n          config: { option: 'value' },\n          extra: ['additional'],\n        }\n\n        expect(objectsAreEqual(obj1, obj2, [])).toBe(false)\n      })\n    })\n\n    test.describe('key exclusion', () => {\n      test('ignores excluded keys', () => {\n        const obj1 = { a: 1, b: 2, ignore: 'foo' }\n        const obj2 = { a: 1, b: 2, ignore: 'bar' }\n\n        expect(objectsAreEqual(obj1, obj2, ['ignore'])).toBe(true)\n      })\n\n      test('does not ignore non-excluded keys', () => {\n        const obj1 = { a: 1, b: 2, keep: 'foo' }\n        const obj2 = { a: 1, b: 2, keep: 'bar' }\n\n        // @ts-expect-error - Ignore key doesn't exist in obj1\n        expect(objectsAreEqual(obj1, obj2, ['ignore'])).toBe(false)\n      })\n\n      test('handles asymmetric objects with excluded keys', () => {\n        const obj1 = { a: 1, b: 2 }\n        const obj2 = { a: 1, b: 2, ignore: 'value' }\n\n        // Should be true because the extra key is excluded\n        // @ts-expect-error - Ignore key doesn't exist in obj1\n        expect(objectsAreEqual(obj1, obj2, ['ignore'])).toBe(true)\n      })\n\n      test('handles asymmetric objects with non-excluded keys', () => {\n        const obj1 = { a: 1, b: 2 }\n        const obj2 = { a: 1, b: 2, keep: 'value' }\n\n        // Should be false because the extra key is not excluded\n        // @ts-expect-error - Keep key doesn't exist in obj1\n        expect(objectsAreEqual(obj1, obj2, ['ignore'])).toBe(false)\n      })\n    })\n\n    test.describe('value types', () => {\n      test('handles undefined values', () => {\n        const obj1 = { a: 1, b: undefined }\n        const obj2 = { a: 1, b: undefined }\n\n        expect(objectsAreEqual(obj1, obj2, [])).toBe(true)\n      })\n\n      test('handles null values', () => {\n        const obj1 = { a: 1, b: null }\n        const obj2 = { a: 1, b: null }\n\n        expect(objectsAreEqual(obj1, obj2, [])).toBe(true)\n      })\n\n      test('distinguishes between undefined and null', () => {\n        const obj1 = { a: 1, b: undefined }\n        const obj2 = { a: 1, b: null }\n\n        // @ts-expect-error - Different types for key 'b'\n        expect(objectsAreEqual(obj1, obj2, [])).toBe(false)\n      })\n\n      test('handles boolean values', () => {\n        const obj1 = { a: true, b: false }\n        const obj2 = { a: true, b: false }\n\n        expect(objectsAreEqual(obj1, obj2, [])).toBe(true)\n      })\n\n      test('handles string values', () => {\n        const obj1 = { a: 'hello', b: 'world' }\n        const obj2 = { a: 'hello', b: 'world' }\n\n        expect(objectsAreEqual(obj1, obj2, [])).toBe(true)\n      })\n\n      test('handles array values', () => {\n        const obj1 = { a: [1, 2, 3], b: ['x', 'y'] }\n        const obj2 = { a: [1, 2, 3], b: ['x', 'y'] }\n\n        expect(objectsAreEqual(obj1, obj2, [])).toBe(true)\n      })\n\n      test('detects different array values', () => {\n        const obj1 = { a: [1, 2, 3] }\n        const obj2 = { a: [1, 2, 4] }\n\n        expect(objectsAreEqual(obj1, obj2, [])).toBe(false)\n      })\n\n      test('handles nested objects', () => {\n        const obj1 = { a: 1, nested: { x: 1, y: 2 } }\n        const obj2 = { a: 1, nested: { x: 1, y: 2 } }\n\n        expect(objectsAreEqual(obj1, obj2, [])).toBe(true)\n      })\n\n      test('detects different nested objects', () => {\n        const obj1 = { a: 1, nested: { x: 1, y: 2 } }\n        const obj2 = { a: 1, nested: { x: 1, y: 3 } }\n\n        expect(objectsAreEqual(obj1, obj2, [])).toBe(false)\n      })\n\n      test('handles functions', () => {\n        const fn = () => 'test'\n        const obj1 = { a: 1, fn }\n        const obj2 = { a: 1, fn }\n\n        expect(objectsAreEqual(obj1, obj2, [])).toBe(true)\n      })\n\n      test('detects different functions', () => {\n        const obj1 = { a: 1, fn: () => 'test1' }\n        const obj2 = { a: 1, fn: () => 'test2' }\n\n        expect(objectsAreEqual(obj1, obj2, [])).toBe(false)\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "tests/core/url.test.ts",
    "content": "import test, { expect } from '@playwright/test'\nimport { config } from '../../packages/core/src/config'\nimport {\n  isSameUrlWithoutHash,\n  isSameUrlWithoutQueryOrHash,\n  mergeDataIntoQueryString,\n  transformUrlAndData,\n  urlHasProtocol,\n} from '../../packages/core/src/url'\n\ntest.describe('url.ts', () => {\n  test.describe('urlHasProtocol', () => {\n    const trueCases = [\n      ['https://example.com', 'https protocol'],\n      ['http://example.com', 'http protocol'],\n      ['ftp://files.example.com', 'ftp protocol'],\n      ['custom-scheme://app', 'custom scheme with hyphen'],\n      ['scheme123://app', 'scheme with numbers'],\n      ['//example.com', 'protocol-relative URL'],\n      ['//example.com/path', 'protocol-relative URL with path'],\n      ['//example.com:8080', 'protocol-relative URL with port'],\n      ['//localhost', 'protocol-relative localhost'],\n    ] as const\n\n    const falseCases = [\n      ['/path', 'absolute path'],\n      ['/path/to/page', 'nested absolute path'],\n      ['path/to/page', 'relative path'],\n      ['./path', 'relative path with dot'],\n      ['../path', 'relative path with double dot'],\n      ['?query=value', 'query string only'],\n      ['#hash', 'hash only'],\n      ['', 'empty string'],\n      ['///path', 'triple slash'],\n      ['///', 'triple slash only'],\n      ['//', 'double slash only'],\n    ] as const\n\n    trueCases.forEach(([url, description]) => {\n      test(`returns true for ${description}: ${url}`, () => {\n        expect(urlHasProtocol(url)).toBe(true)\n      })\n    })\n\n    falseCases.forEach(([url, description]) => {\n      test(`returns false for ${description}: ${url}`, () => {\n        expect(urlHasProtocol(url)).toBe(false)\n      })\n    })\n  })\n\n  test.describe('mergeDataIntoQueryString', () => {\n    test.describe('GET request', () => {\n      test('appends data to a URL without an existing query string', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '/search', { q: 'foo' })\n\n        expect(href).toBe('/search?q=foo')\n        expect(data).toEqual({})\n      })\n\n      test('returns the FormData instance when passed as data', () => {\n        const formData = new FormData()\n        formData.append('q', 'foo')\n\n        const [href, data] = mergeDataIntoQueryString('post', '/search', formData)\n\n        expect(href).toBe('/search')\n        expect(data).toEqual(formData)\n      })\n\n      test('merges new data into an existing query string', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '/search?lang=en', { q: 'bar' })\n\n        expect(href).toBe('/search?lang=en&q=bar')\n        expect(data).toEqual({})\n      })\n\n      test('merges data into URL with existing brackets notation arrays', () => {\n        const originalHref = '/search?frameworks[]=react&frameworks[]=vue'\n        const additionalData = { q: 'bar' }\n\n        const [hrefBrackts, dataBrackets] = mergeDataIntoQueryString('get', originalHref, additionalData, 'brackets')\n\n        expect(hrefBrackts).toBe('/search?frameworks[]=react&frameworks[]=vue&q=bar')\n        expect(dataBrackets).toEqual({})\n\n        const [hrefIndices, dataIndices] = mergeDataIntoQueryString('get', originalHref, additionalData, 'indices')\n\n        expect(hrefIndices).toBe('/search?frameworks[0]=react&frameworks[1]=vue&q=bar')\n        expect(dataIndices).toEqual({})\n      })\n\n      test('merges data into URL with existing indices notation arrays', () => {\n        const originalHref = '/search?frameworks[0]=react&frameworks[1]=vue'\n        const additionalData = { q: 'bar' }\n\n        const [hrefBrackts, dataBrackets] = mergeDataIntoQueryString('get', originalHref, additionalData, 'brackets')\n\n        expect(hrefBrackts).toBe('/search?frameworks[0]=react&frameworks[1]=vue&q=bar')\n        expect(dataBrackets).toEqual({})\n\n        const [hrefIndices, dataIndices] = mergeDataIntoQueryString('get', originalHref, additionalData, 'indices')\n\n        expect(hrefIndices).toBe('/search?frameworks[0]=react&frameworks[1]=vue&q=bar')\n        expect(dataIndices).toEqual({})\n      })\n\n      test('merges data into URL with existing nested brackets notation arrays', () => {\n        const originalHref = '/search?filters[tags][]=a&filters[tags][]=b'\n        const additionalData = { q: 'bar' }\n\n        const [hrefBrackets, dataBrackets] = mergeDataIntoQueryString('get', originalHref, additionalData, 'brackets')\n\n        expect(hrefBrackets).toBe('/search?filters[tags][]=a&filters[tags][]=b&q=bar')\n        expect(dataBrackets).toEqual({})\n\n        const [hrefIndices, dataIndices] = mergeDataIntoQueryString('get', originalHref, additionalData, 'indices')\n\n        expect(hrefIndices).toBe('/search?filters[tags][0]=a&filters[tags][1]=b&q=bar')\n        expect(dataIndices).toEqual({})\n      })\n\n      test('merges data into URL with existing nested indices notation arrays', () => {\n        const originalHref = '/search?filters[tags][0]=a&filters[tags][1]=b'\n        const additionalData = { q: 'bar' }\n\n        const [hrefBrackets, dataBrackets] = mergeDataIntoQueryString('get', originalHref, additionalData, 'brackets')\n\n        expect(hrefBrackets).toBe('/search?filters[tags][0]=a&filters[tags][1]=b&q=bar')\n        expect(dataBrackets).toEqual({})\n\n        const [hrefIndices, dataIndices] = mergeDataIntoQueryString('get', originalHref, additionalData, 'indices')\n\n        expect(hrefIndices).toBe('/search?filters[tags][0]=a&filters[tags][1]=b&q=bar')\n        expect(dataIndices).toEqual({})\n      })\n\n      test('merges data into URL with single item at index 0', () => {\n        const originalHref = '/search?items[0]=first'\n        const additionalData = { q: 'bar' }\n\n        const [hrefBrackets, dataBrackets] = mergeDataIntoQueryString('get', originalHref, additionalData, 'brackets')\n\n        expect(hrefBrackets).toBe('/search?items[0]=first&q=bar')\n        expect(dataBrackets).toEqual({})\n\n        const [hrefIndices, dataIndices] = mergeDataIntoQueryString('get', originalHref, additionalData, 'indices')\n\n        expect(hrefIndices).toBe('/search?items[0]=first&q=bar')\n        expect(dataIndices).toEqual({})\n      })\n\n      test('merges data into URL with sparse array indices', () => {\n        const originalHref = '/search?a[0]=x&a[5]=y'\n        const additionalData = { q: 'bar' }\n\n        const [hrefBrackets, dataBrackets] = mergeDataIntoQueryString('get', originalHref, additionalData, 'brackets')\n\n        expect(hrefBrackets).toBe('/search?a[0]=x&a[5]=y&q=bar')\n        expect(dataBrackets).toEqual({})\n\n        const [hrefIndices, dataIndices] = mergeDataIntoQueryString('get', originalHref, additionalData, 'indices')\n\n        expect(hrefIndices).toBe('/search?a[0]=x&a[5]=y&q=bar')\n        expect(dataIndices).toEqual({})\n      })\n\n      test('merges data into URL with objects at array indices', () => {\n        const originalHref = '/search?items[0][id]=1&items[0][name]=foo&items[1][id]=2'\n        const additionalData = { q: 'bar' }\n\n        const [hrefBrackets, dataBrackets] = mergeDataIntoQueryString('get', originalHref, additionalData, 'brackets')\n\n        expect(hrefBrackets).toBe('/search?items[0][id]=1&items[0][name]=foo&items[1][id]=2&q=bar')\n        expect(dataBrackets).toEqual({})\n\n        const [hrefIndices, dataIndices] = mergeDataIntoQueryString('get', originalHref, additionalData, 'indices')\n\n        expect(hrefIndices).toBe('/search?items[0][id]=1&items[0][name]=foo&items[1][id]=2&q=bar')\n        expect(dataIndices).toEqual({})\n      })\n\n      test('merges data into URL with URL-encoded indices notation', () => {\n        const originalHref = '/search?items%5B0%5D%5Bname%5D=foo&items%5B1%5D%5Bname%5D=bar'\n        const additionalData = { q: 'baz' }\n\n        const [href, data] = mergeDataIntoQueryString('get', originalHref, additionalData, 'brackets')\n\n        expect(href).toBe('/search?items[0][name]=foo&items[1][name]=bar&q=baz')\n        expect(data).toEqual({})\n      })\n\n      test('overwrites existing keys in the query string when they also exist in the data', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '/search?q=old', { q: 'new' })\n\n        expect(href).toBe('/search?q=new')\n        expect(data).toEqual({})\n      })\n\n      test('keeps key when new value is null', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '/page?foo=bar&keep=yes', { foo: null })\n\n        expect(href).toBe('/page?foo=&keep=yes')\n        expect(data).toEqual({})\n      })\n\n      test('removes query string keys when their corresponding data value is undefined', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '/search?q=keep&remove=me', { remove: undefined })\n\n        expect(href).toBe('/search?q=keep')\n        expect(data).toEqual({})\n      })\n\n      test('serializes arrays using bracket notation by default', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '/filter', { tag: ['foo', 'bar'] })\n\n        expect(href).toBe('/filter?tag[]=foo&tag[]=bar')\n        expect(data).toEqual({})\n      })\n\n      test('serializes arrays using index notation when specified', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '/filter', { tag: ['foo', 'bar'] }, 'indices')\n\n        expect(href).toBe('/filter?tag[0]=foo&tag[1]=bar')\n        expect(data).toEqual({})\n      })\n\n      test('preserves the full origin when the URL is absolute', () => {\n        const [href, data] = mergeDataIntoQueryString('get', 'https://example.com/search', { q: 'foo' })\n\n        expect(href).toBe('https://example.com/search?q=foo')\n        expect(data).toEqual({})\n      })\n\n      test('maintains hash fragments when appending query parameters', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '/docs#section', { page: '1' })\n\n        expect(href).toBe('/docs?page=1#section')\n        expect(data).toEqual({})\n      })\n\n      test('replaces previous array values completely when using index notation', () => {\n        // See: https://github.com/inertiajs/inertia/pull/2416\n        const [href, data] = mergeDataIntoQueryString('get', '/edit?items[0]=a&items[1]=b', { items: ['c'] }, 'indices')\n\n        expect(href).toBe('/edit?items[0]=c')\n        expect(data).toEqual({})\n      })\n\n      test('replaces nested objects without merging with existing keys', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '/filter?filters[type]=a&filters[category]=b', {\n          filters: { type: 'x' },\n        })\n\n        expect(href).toBe('/filter?filters[type]=x')\n        expect(data).toEqual({})\n      })\n\n      test('retains indexed object keys in the query string during parsing and stringification', () => {\n        // See: https://github.com/inertiajs/inertia/issues/2404\n        const [href, data] = mergeDataIntoQueryString('get', '/search?filter[12]=213', { q: 'bar' })\n\n        expect(href).toBe('/search?filter[12]=213&q=bar')\n        expect(data).toEqual({})\n      })\n\n      test('handles empty arrays and objects', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '/filter', { tags: [], filters: {} })\n\n        expect(href).toBe('/filter')\n        expect(data).toEqual({})\n      })\n\n      test('handles nested arrays within objects', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '/filter', {\n          filters: { tags: ['red', 'blue'], categories: ['A', 'B'] },\n        })\n\n        expect(href).toBe(\n          '/filter?filters[tags][]=red&filters[tags][]=blue&filters[categories][]=A&filters[categories][]=B',\n        )\n        expect(data).toEqual({})\n      })\n\n      test('handles deep nesting of objects', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '/api', {\n          user: { profile: { settings: { theme: 'dark' } } },\n        })\n\n        expect(href).toBe('/api?user[profile][settings][theme]=dark')\n        expect(data).toEqual({})\n      })\n\n      test('handles URLs with fragments containing query-like syntax', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '/docs#section?param=value', { page: 2 })\n\n        expect(href).toBe('/docs?page=2#section?param=value')\n        expect(data).toEqual({})\n      })\n\n      test('handles query strings with keys but no values', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '/search?flag&other=value', { new: 'param' })\n\n        expect(href).toBe('/search?flag=&other=value&new=param')\n        expect(data).toEqual({})\n      })\n\n      test('handles URLs that are only query strings', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '?existing=value', { new: 'param' })\n\n        expect(href).toBe('?existing=value&new=param')\n        expect(data).toEqual({})\n      })\n\n      test('handles URLs that are only hash fragments', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '#section', { param: 'value' })\n\n        expect(href).toBe('?param=value#section')\n        expect(data).toEqual({})\n      })\n\n      test('handles already encoded values in URLs', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '/search?q=hello%20world', { filter: 'café' })\n\n        expect(href).toBe('/search?q=hello%20world&filter=caf%C3%A9')\n        expect(data).toEqual({})\n      })\n\n      test('handles arrays with mixed data types', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '/filter', {\n          mixed: [1, 'string', true, null],\n        })\n\n        expect(href).toBe('/filter?mixed[]=1&mixed[]=string&mixed[]=true&mixed[]=')\n        expect(data).toEqual({})\n      })\n\n      test('handles objects with numeric keys', () => {\n        const [href, data] = mergeDataIntoQueryString('get', '/api', {\n          items: { 0: 'first', 1: 'second', 10: 'tenth' },\n        })\n\n        expect(href).toBe('/api?items[0]=first&items[1]=second&items[10]=tenth')\n        expect(data).toEqual({})\n      })\n\n      test('handles URL objects as input', () => {\n        const url = new URL('https://example.com/search?existing=value')\n        const [href, data] = mergeDataIntoQueryString('get', url, { new: 'param' })\n\n        expect(href).toBe('https://example.com/search?existing=value&new=param')\n        expect(data).toEqual({})\n      })\n    })\n\n    test.describe('non-GET request', () => {\n      test('leaves the href unchanged when data is present', () => {\n        const [href, data] = mergeDataIntoQueryString('post', '/submit', { name: 'foo' })\n\n        expect(href).toBe('/submit')\n        expect(data).toEqual({ name: 'foo' })\n      })\n\n      test('retains the original query string and returns data untouched', () => {\n        const [href, data] = mergeDataIntoQueryString('put', '/update?active=true', { name: 'bar' })\n\n        expect(href).toBe('/update?active=true')\n        expect(data).toEqual({ name: 'bar' })\n      })\n\n      test('preserves hash fragments in the href', () => {\n        const [href, data] = mergeDataIntoQueryString('patch', '/docs#install', { step: '2' })\n\n        expect(href).toBe('/docs#install')\n        expect(data).toEqual({ step: '2' })\n      })\n\n      test('does not modify the query string even if data includes keys already present in the href', () => {\n        const [href, data] = mergeDataIntoQueryString('delete', '/delete?confirm=yes', { confirm: 'no' })\n\n        expect(href).toBe('/delete?confirm=yes')\n        expect(data).toEqual({ confirm: 'no' })\n      })\n\n      test('handles absolute URLs without modifying the query string', () => {\n        const [href, data] = mergeDataIntoQueryString('post', 'https://example.com/submit?token=abc', { token: 'xyz' })\n\n        expect(href).toBe('https://example.com/submit?token=abc')\n        expect(data).toEqual({ token: 'xyz' })\n      })\n\n      test('preserves complex data structures unchanged', () => {\n        const complexData = {\n          user: { profile: { settings: { theme: 'dark' } } },\n          tags: ['red', 'blue'],\n          active: true,\n          count: 42,\n        }\n        const [href, data] = mergeDataIntoQueryString('post', '/api/update', complexData)\n\n        expect(href).toBe('/api/update')\n        expect(data).toEqual(complexData)\n      })\n\n      test('handles URL objects as input for non-GET requests', () => {\n        const url = new URL('https://example.com/api?existing=value#section')\n        const [href, data] = mergeDataIntoQueryString('put', url, { new: 'data' })\n\n        expect(href).toBe('https://example.com/api?existing=value#section')\n        expect(data).toEqual({ new: 'data' })\n      })\n\n      test('handles a URL that is an empty string', () => {\n        const [href, data] = mergeDataIntoQueryString('post', '', { name: 'foo' })\n\n        expect(href).toBe('/')\n        expect(data).toEqual({ name: 'foo' })\n      })\n    })\n  })\n\n  test.describe('transformUrlAndData', () => {\n    test('accepts string URL as href parameter', () => {\n      const inputUrl = 'https://example.com/page'\n      const [url, data] = transformUrlAndData(inputUrl, { foo: 'bar' }, 'post', false, 'brackets')\n\n      expect(url).toBeInstanceOf(URL)\n      expect(url.href).toBe('https://example.com/page')\n    })\n\n    test('converts data to FormData when it contains files', () => {\n      const file = new File(['content'], 'test.txt', { type: 'text/plain' })\n      const [url, data] = transformUrlAndData('https://example.com/upload', { file }, 'post', false, 'brackets')\n\n      expect(data).toBeInstanceOf(FormData)\n      expect((data as FormData).get('file')).toEqual(file)\n    })\n\n    test('converts data to FormData when forceFormData is true', () => {\n      const [url, data] = transformUrlAndData('https://example.com/submit', { name: 'test' }, 'post', true, 'brackets')\n\n      expect(data).toBeInstanceOf(FormData)\n      expect((data as FormData).get('name')).toBe('test')\n    })\n\n    test('returns FormData unchanged when data is already FormData', () => {\n      const formData = new FormData()\n      formData.append('key', 'value')\n      const [url, data] = transformUrlAndData('https://example.com/submit', formData, 'post', false, 'brackets')\n\n      expect(data).toBe(formData)\n      expect(data).toBeInstanceOf(FormData)\n    })\n\n    test('does not convert to FormData when forceFormData is false and no files present', () => {\n      const [url, data] = transformUrlAndData('https://example.com/submit', { name: 'test' }, 'post', false, 'brackets')\n\n      expect(data).not.toBeInstanceOf(FormData)\n      expect(data).toEqual({ name: 'test' })\n    })\n\n    test('forces indices notation when converting arrays to FormData by default', () => {\n      const [url, data] = transformUrlAndData(\n        'https://example.com/submit',\n        { tags: ['a', 'b'] },\n        'post',\n        true,\n        'brackets',\n      )\n\n      expect(data).toBeInstanceOf(FormData)\n      expect((data as FormData).get('tags[0]')).toBe('a')\n      expect((data as FormData).get('tags[1]')).toBe('b')\n    })\n\n    test('can opt-out of forcing indices notation when converting arrays to FormData by default', () => {\n      config.set('form.forceIndicesArrayFormatInFormData', false)\n\n      const [url, data] = transformUrlAndData(\n        'https://example.com/submit',\n        { tags: ['a', 'b'] },\n        'post',\n        true,\n        'brackets',\n      )\n\n      expect(data).toBeInstanceOf(FormData)\n      expect((data as FormData).getAll('tags[]')).toEqual(['a', 'b'])\n    })\n\n    test('uses index notation when converting arrays to FormData with indices format', () => {\n      const [url, data] = transformUrlAndData(\n        'https://example.com/submit',\n        { tags: ['a', 'b'] },\n        'post',\n        true,\n        'indices',\n      )\n\n      expect(data).toBeInstanceOf(FormData)\n      expect((data as FormData).get('tags[0]')).toBe('a')\n      expect((data as FormData).get('tags[1]')).toBe('b')\n    })\n\n    test('handles nested objects when forceFormData is true', () => {\n      const [url, data] = transformUrlAndData(\n        'https://example.com/submit',\n        { user: { name: 'John', age: 30 } },\n        'post',\n        true,\n        'brackets',\n      )\n\n      expect(data).toBeInstanceOf(FormData)\n      expect((data as FormData).get('user[name]')).toBe('John')\n      expect((data as FormData).get('user[age]')).toBe('30')\n    })\n\n    test('returns FormData with file and does not merge into query string', () => {\n      const file = new File(['content'], 'test.txt', { type: 'text/plain' })\n      const [url, data] = transformUrlAndData(\n        'https://example.com/upload',\n        { file, name: 'test' },\n        'get',\n        false,\n        'brackets',\n      )\n\n      expect(data).toBeInstanceOf(FormData)\n      expect(url.search).toBe('')\n      expect((data as FormData).get('file')).toEqual(file)\n      expect((data as FormData).get('name')).toBe('test')\n    })\n\n    test('handles absolute URLs with protocol', () => {\n      const [url, data] = transformUrlAndData('https://example.com/page', { foo: 'bar' }, 'post', false, 'brackets')\n\n      expect(url.protocol).toBe('https:')\n      expect(url.host).toBe('example.com')\n      expect(url.pathname).toBe('/page')\n    })\n\n    test('preserves existing query parameters and hash when returning FormData', () => {\n      const [url, data] = transformUrlAndData(\n        'https://example.com/page?existing=value#section',\n        { name: 'test' },\n        'post',\n        true,\n        'brackets',\n      )\n\n      expect(url.search).toBe('?existing=value')\n      expect(url.hash).toBe('#section')\n      expect(data).toBeInstanceOf(FormData)\n    })\n  })\n\n  test.describe('isSameUrlWithoutHash', () => {\n    const sameCases = [\n      ['/page', '/page', 'identical paths'],\n      ['/page', '/page#section', 'path vs path with hash'],\n      ['/page#one', '/page#two', 'same path, different hashes'],\n      ['/page?foo=bar', '/page?foo=bar', 'identical paths with query'],\n      ['/page?foo=bar', '/page?foo=bar#section', 'query vs query with hash'],\n      ['/page?foo=bar#one', '/page?foo=bar#two', 'same query, different hashes'],\n      ['https://example.com/page', 'https://example.com/page#hash', 'full URL with hash'],\n    ] as const\n\n    const differentCases = [\n      ['/page-a', '/page-b', 'different paths'],\n      ['/page', '/page?foo=bar', 'path vs path with query'],\n      ['/page?foo=bar', '/page?foo=baz', 'different query values'],\n      ['/page?a=1', '/page?b=2', 'different query params'],\n      ['https://example.com/page', 'https://other.com/page', 'different hosts'],\n    ] as const\n\n    sameCases.forEach(([url1, url2, description]) => {\n      test(`returns true for ${description}: ${url1} vs ${url2}`, () => {\n        expect(isSameUrlWithoutHash(new URL(url1, 'https://example.com'), new URL(url2, 'https://example.com'))).toBe(\n          true,\n        )\n      })\n    })\n\n    differentCases.forEach(([url1, url2, description]) => {\n      test(`returns false for ${description}: ${url1} vs ${url2}`, () => {\n        expect(isSameUrlWithoutHash(new URL(url1, 'https://example.com'), new URL(url2, 'https://example.com'))).toBe(\n          false,\n        )\n      })\n    })\n  })\n\n  test.describe('isSameUrlWithoutQueryOrHash', () => {\n    const sameCases = [\n      ['/page', '/page', 'identical paths'],\n      ['/page', '/page#section', 'path vs path with hash'],\n      ['/page#one', '/page#two', 'same path, different hashes'],\n      ['/page', '/page?foo=bar', 'path vs path with query'],\n      ['/page?foo=bar', '/page?foo=baz', 'different query values'],\n      ['/page?a=1', '/page?b=2', 'different query params'],\n      ['/page?foo=bar', '/page?foo=bar#section', 'query vs query with hash'],\n      ['/page?foo=bar#one', '/page?baz=qux#two', 'different queries and hashes'],\n      ['https://example.com/page', 'https://example.com/page?foo=bar#hash', 'full URL with query and hash'],\n    ] as const\n\n    const differentCases = [\n      ['/page-a', '/page-b', 'different paths'],\n      ['/page/one', '/page/two', 'different nested paths'],\n      ['https://example.com/page', 'https://other.com/page', 'different hosts'],\n      ['http://example.com/page', 'https://example.com/page', 'different protocols'],\n    ] as const\n\n    sameCases.forEach(([url1, url2, description]) => {\n      test(`returns true for ${description}: ${url1} vs ${url2}`, () => {\n        expect(\n          isSameUrlWithoutQueryOrHash(new URL(url1, 'https://example.com'), new URL(url2, 'https://example.com')),\n        ).toBe(true)\n      })\n    })\n\n    differentCases.forEach(([url1, url2, description]) => {\n      test(`returns false for ${description}: ${url1} vs ${url2}`, () => {\n        expect(\n          isSameUrlWithoutQueryOrHash(new URL(url1, 'https://example.com'), new URL(url2, 'https://example.com')),\n        ).toBe(false)\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "tests/deep-merge-props.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport { clickAndWaitForResponse } from './support'\n\ntest('can deep merge props', async ({ page }) => {\n  await page.goto('/deep-merge-props')\n\n  await expect(page.getByText('bar count is 5')).toBeVisible()\n  await expect(page.getByText('baz count is 5')).toBeVisible()\n  await expect(page.getByText('foo.data count is 5')).toBeVisible()\n  await expect(page.getByText('foo.page is 0')).toBeVisible()\n  await expect(page.getByText('foo.per_page is 5')).toBeVisible()\n  await expect(page.getByText('foo.meta.label is first')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Reload', '/deep-merge-props?page=0', 'button')\n\n  await expect(page.getByText('bar count is 5')).toBeVisible()\n  await expect(page.getByText('baz count is 10')).toBeVisible()\n  await expect(page.getByText('foo.data count is 10')).toBeVisible()\n  await expect(page.getByText('foo.page is 1')).toBeVisible()\n  await expect(page.getByText('foo.per_page is 5')).toBeVisible()\n  await expect(page.getByText('foo.meta.label is second')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Reload', '/deep-merge-props?page=1', 'button')\n\n  await expect(page.getByText('bar count is 5')).toBeVisible()\n  await expect(page.getByText('baz count is 15')).toBeVisible()\n  await expect(page.getByText('foo.data count is 15')).toBeVisible()\n  await expect(page.getByText('foo.page is 2')).toBeVisible()\n  await expect(page.getByText('foo.per_page is 5')).toBeVisible()\n  await expect(page.getByText('foo.meta.label is third')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Get Fresh', '/deep-merge-props', 'button')\n\n  await expect(page.getByText('bar count is 5')).toBeVisible()\n  await expect(page.getByText('baz count is 5')).toBeVisible()\n  await expect(page.getByText('foo.data count is 5')).toBeVisible()\n  await expect(page.getByText('foo.page is 0')).toBeVisible()\n  await expect(page.getByText('foo.per_page is 5')).toBeVisible()\n  await expect(page.getByText('foo.meta.label is first')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Reload', '/deep-merge-props?page=0', 'button')\n\n  await expect(page.getByText('bar count is 5')).toBeVisible()\n  await expect(page.getByText('baz count is 10')).toBeVisible()\n  await expect(page.getByText('foo.data count is 10')).toBeVisible()\n  await expect(page.getByText('foo.page is 1')).toBeVisible()\n  await expect(page.getByText('foo.per_page is 5')).toBeVisible()\n  await expect(page.getByText('foo.meta.label is second')).toBeVisible()\n})\n"
  },
  {
    "path": "tests/deferred-props-cancellation.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport { gotoPageAndWaitForContent } from './support'\n\ntest.describe('Deferred Props Cancellation', () => {\n  test('it cancels in-flight deferred props when navigating to a different URL', async ({ page }) => {\n    const cancelledFromA: string[] = []\n    const completedFromA: string[] = []\n    const completedFromB: string[] = []\n\n    page.on('requestfailed', (req) => {\n      if (req.url().includes('/a') && req.headers()['x-inertia-partial-data']) {\n        cancelledFromA.push(req.headers()['x-inertia-partial-data'])\n      }\n    })\n\n    page.on('response', (res) => {\n      const prop = res.request().headers()['x-inertia-partial-data']\n      if (prop && res.status() === 200) {\n        if (res.url().includes('/a')) {\n          completedFromA.push(prop)\n        } else if (res.url().includes('/b')) {\n          completedFromB.push(prop)\n        }\n      }\n    })\n\n    await gotoPageAndWaitForContent(page, '/deferred-props/rapid-navigation/a')\n    await expect(page.getByText('Page: a')).toBeVisible()\n    await expect(page.getByText('Loading users...')).toBeVisible()\n\n    // Navigate away before deferred props complete\n    await page.getByRole('link', { name: 'Page B' }).click()\n    await expect(page.getByText('Page: b')).toBeVisible()\n\n    // Wait for B's deferred props\n    await expect(page.getByText('users data for b')).toBeVisible()\n\n    // A's requests were cancelled, B's completed\n    expect(cancelledFromA).toHaveLength(3)\n    expect(completedFromA).toHaveLength(0)\n    expect(completedFromB).toHaveLength(3)\n  })\n\n  test('it does not cancel deferred props for same-URL operations', async ({ page }) => {\n    const cancelled: string[] = []\n\n    page.on('requestfailed', (req) => {\n      if (req.url().includes('rapid-navigation') && req.headers()['x-inertia-partial-data']) {\n        cancelled.push(req.headers()['x-inertia-partial-data'])\n      }\n    })\n\n    await gotoPageAndWaitForContent(page, '/deferred-props/rapid-navigation/a')\n    await expect(page.getByText('Loading users...')).toBeVisible()\n\n    // Trigger a reload (same URL)\n    await page.getByRole('button', { name: 'Plain reload' }).click()\n\n    // Wait for deferred props to complete\n    await expect(page.getByText('users data for a')).toBeVisible()\n\n    expect(cancelled).toHaveLength(0)\n  })\n\n  test('it preserves prefetch requests when navigating', async ({ page }) => {\n    const cancelledPrefetch: string[] = []\n    const completedPrefetch: string[] = []\n    const cancelledDeferred: string[] = []\n\n    page.on('requestfailed', (req) => {\n      if (req.headers().purpose === 'prefetch') {\n        cancelledPrefetch.push(req.url())\n      } else if (req.headers()['x-inertia-partial-data']) {\n        cancelledDeferred.push(req.headers()['x-inertia-partial-data'])\n      }\n    })\n\n    page.on('response', (res) => {\n      if (res.request().headers().purpose === 'prefetch' && res.status() === 200) {\n        completedPrefetch.push(res.url())\n      }\n    })\n\n    await gotoPageAndWaitForContent(page, '/deferred-props/rapid-navigation/a')\n    await expect(page.getByText('Loading users...')).toBeVisible()\n\n    // Start a prefetch\n    const prefetchPromise = page.waitForResponse(\n      (res) => res.url().includes('page-1') && res.request().headers().purpose === 'prefetch',\n    )\n    await page.getByRole('button', { name: 'Prefetch Page 1' }).click()\n\n    // Navigate away (should cancel deferred but not prefetch)\n    await page.getByRole('link', { name: 'Page B' }).click()\n    await expect(page.getByText('Page: b')).toBeVisible()\n\n    await prefetchPromise\n\n    // Deferred props cancelled, prefetch preserved\n    expect(cancelledDeferred.length).toBeGreaterThan(0)\n    expect(cancelledPrefetch).toHaveLength(0)\n    expect(completedPrefetch.some((url) => url.includes('page-1'))).toBe(true)\n  })\n\n  test('it does not cancel deferred props when onBefore prevents navigation', async ({ page }) => {\n    const cancelled: string[] = []\n\n    page.on('requestfailed', (req) => {\n      if (req.url().includes('rapid-navigation') && req.headers()['x-inertia-partial-data']) {\n        cancelled.push(req.headers()['x-inertia-partial-data'])\n      }\n    })\n\n    await gotoPageAndWaitForContent(page, '/deferred-props/rapid-navigation/a')\n    await expect(page.getByText('Loading users...')).toBeVisible()\n\n    // Set up dialog to cancel navigation\n    page.on('dialog', (dialog) => dialog.dismiss())\n\n    await page.getByRole('button', { name: 'Navigate with onBefore' }).click()\n\n    // Should still be on A, deferred props should complete\n    await expect(page.getByText('users data for a')).toBeVisible()\n    expect(cancelled).toHaveLength(0)\n  })\n\n  test('it cancels deferred props on back navigation', async ({ page }) => {\n    const cancelledFromB: string[] = []\n\n    page.on('requestfailed', (req) => {\n      if (req.url().includes('/b') && req.headers()['x-inertia-partial-data']) {\n        cancelledFromB.push(req.headers()['x-inertia-partial-data'])\n      }\n    })\n\n    // Load A completely first\n    await page.goto('/deferred-props/rapid-navigation/a')\n    await expect(page.getByText('users data for a')).toBeVisible()\n\n    // Navigate to B\n    await page.getByRole('link', { name: 'Page B' }).click()\n    await expect(page.getByText('Loading users...')).toBeVisible()\n\n    // Go back before B's deferred complete\n    await page.goBack()\n    await expect(page.getByText('Page: a')).toBeVisible()\n\n    // B's deferred props were cancelled\n    expect(cancelledFromB).toHaveLength(3)\n  })\n\n  test('it cancels deferred props when query parameter changes', async ({ page }) => {\n    const cancelled: string[] = []\n\n    page.on('requestfailed', (req) => {\n      if (req.url().includes('rapid-navigation') && req.headers()['x-inertia-partial-data']) {\n        cancelled.push(req.headers()['x-inertia-partial-data'])\n      }\n    })\n\n    await gotoPageAndWaitForContent(page, '/deferred-props/rapid-navigation/a')\n    await expect(page.getByText('Loading users...')).toBeVisible()\n\n    // Navigate to same path but with query param (different URL)\n    await page.getByRole('button', { name: 'Add query param' }).click()\n\n    // Wait for new deferred props to complete\n    await expect(page.getByText('users data for a')).toBeVisible()\n\n    // Original requests were cancelled (URL changed due to query param)\n    expect(cancelled).toHaveLength(3)\n  })\n\n  test('it does not cancel deferred props when only hash changes', async ({ page }) => {\n    const cancelled: string[] = []\n\n    page.on('requestfailed', (req) => {\n      if (req.url().includes('rapid-navigation') && req.headers()['x-inertia-partial-data']) {\n        cancelled.push(req.headers()['x-inertia-partial-data'])\n      }\n    })\n\n    await gotoPageAndWaitForContent(page, '/deferred-props/rapid-navigation/a')\n    await expect(page.getByText('Loading users...')).toBeVisible()\n\n    // Change only the hash (same URL per isSameUrlWithoutHash)\n    await page.evaluate(() => {\n      window.location.hash = '#section'\n    })\n\n    // Wait for deferred props to complete\n    await expect(page.getByText('users data for a')).toBeVisible()\n\n    // No requests were cancelled (hash-only change)\n    expect(cancelled).toHaveLength(0)\n  })\n})\n"
  },
  {
    "path": "tests/deferred-props.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport {\n  clickAndWaitForResponse,\n  consoleMessages,\n  gotoPageAndWaitForContent,\n  reloadAndWaitForContent,\n  requests,\n} from './support'\n\ntest('can load deferred props', async ({ page }) => {\n  await gotoPageAndWaitForContent(page, '/deferred-props/page-1')\n\n  await expect(page.getByText('Loading foo...')).toBeVisible()\n  await expect(page.getByText('Loading bar...')).toBeVisible()\n\n  await page.waitForResponse(page.url())\n\n  await expect(page.getByText('Loading foo...')).not.toBeVisible()\n  await expect(page.getByText('Loading bar...')).not.toBeVisible()\n  await expect(page.getByText('foo value')).toBeVisible()\n  await expect(page.getByText('bar value')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Page 2', '/deferred-props/page-2')\n\n  await expect(page.getByText('Loading baz...')).toBeVisible()\n  await expect(page.getByText('Loading qux...')).toBeVisible()\n  await expect(page.getByText('Loading baz and qux...')).toBeVisible()\n\n  await page.waitForResponse(page.url())\n\n  await expect(page.getByText('Loading baz...')).not.toBeVisible()\n  await expect(page.getByText('Loading qux...')).toBeVisible()\n  await expect(page.getByText('Loading baz and qux...')).toBeVisible()\n  await expect(page.getByText('baz value')).toBeVisible()\n\n  await page.waitForResponse(page.url())\n\n  await expect(page.getByText('Loading baz...')).not.toBeVisible()\n  await expect(page.getByText('Loading qux...')).not.toBeVisible()\n  await expect(page.getByText('Loading baz and qux...')).not.toBeVisible()\n  await expect(page.getByText('baz value')).toBeVisible()\n  await expect(page.getByText('qux value')).toBeVisible()\n  await expect(page.getByText('both baz value and qux value')).toBeVisible()\n})\n\ntest('we are not caching deferred props after reload', async ({ page }) => {\n  await gotoPageAndWaitForContent(page, '/deferred-props/page-1')\n\n  await expect(page.getByText('Loading foo...')).toBeVisible()\n  await expect(page.getByText('Loading bar...')).toBeVisible()\n  await expect(page.getByText('foo value')).not.toBeVisible()\n  await expect(page.getByText('bar value')).not.toBeVisible()\n\n  await page.waitForResponse(page.url())\n\n  await expect(page.getByText('Loading foo...')).not.toBeVisible()\n  await expect(page.getByText('Loading bar...')).not.toBeVisible()\n  await expect(page.getByText('foo value')).toBeVisible()\n  await expect(page.getByText('bar value')).toBeVisible()\n\n  await reloadAndWaitForContent(page)\n\n  await expect(page.getByText('Loading foo...')).toBeVisible()\n  await expect(page.getByText('Loading bar...')).toBeVisible()\n  await expect(page.getByText('foo value')).not.toBeVisible()\n  await expect(page.getByText('bar value')).not.toBeVisible()\n\n  await page.waitForResponse(page.url())\n\n  await expect(page.getByText('Loading foo...')).not.toBeVisible()\n  await expect(page.getByText('Loading bar...')).not.toBeVisible()\n  await expect(page.getByText('foo value')).toBeVisible()\n  await expect(page.getByText('bar value')).toBeVisible()\n})\n\ntest('props will re-defer if a link is clicked to go to the same page again', async ({ page }) => {\n  await gotoPageAndWaitForContent(page, '/deferred-props/page-1')\n\n  await expect(page.getByText('Loading foo...')).toBeVisible()\n  await expect(page.getByText('Loading bar...')).toBeVisible()\n\n  await page.waitForResponse(page.url())\n\n  await expect(page.getByText('Loading foo...')).not.toBeVisible()\n  await expect(page.getByText('Loading bar...')).not.toBeVisible()\n  await expect(page.getByText('foo value')).toBeVisible()\n  await expect(page.getByText('bar value')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Page 1', '/deferred-props/page-1')\n\n  await expect(page.getByText('Loading foo...')).toBeVisible()\n  await expect(page.getByText('Loading bar...')).toBeVisible()\n\n  await page.waitForResponse(page.url())\n\n  await expect(page.getByText('Loading foo...')).not.toBeVisible()\n  await expect(page.getByText('Loading bar...')).not.toBeVisible()\n  await expect(page.getByText('foo value')).toBeVisible()\n  await expect(page.getByText('bar value')).toBeVisible()\n})\n\nconst shoulReload = ['only']\n\nshoulReload.forEach((type) => {\n  test(`it will handle partial reloads properly when deferred is being reloaded (${type})`, async ({ page }) => {\n    test.skip(process.env.PACKAGE !== 'react', 'React only test')\n\n    await gotoPageAndWaitForContent(page, `/deferred-props/with-partial-reload/${type}`)\n\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await page.waitForResponse(page.url())\n\n    await expect(page.getByText('Loading...')).not.toBeVisible()\n    await expect(page.getByText('John Doe')).toBeVisible()\n\n    const responsePromise = page.waitForResponse(page.url())\n\n    await page.getByRole('button', { exact: true, name: 'Trigger a partial reload' }).click()\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await responsePromise\n\n    await expect(page.getByText('John Doe')).toBeVisible()\n  })\n})\n\nconst noReload = ['except', 'only-other', 'none', 'except-other']\n\nnoReload.forEach((type) => {\n  test(`it will handle partial reloads properly when deferred is not reloaded (${type})`, async ({ page }) => {\n    test.skip(process.env.PACKAGE !== 'react', 'React only test')\n\n    await gotoPageAndWaitForContent(page, `/deferred-props/with-partial-reload/${type}`)\n\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await page.waitForResponse(page.url())\n\n    await expect(page.getByText('Loading...')).not.toBeVisible()\n    await expect(page.getByText('John Doe')).toBeVisible()\n\n    const responsePromise = page.waitForResponse(page.url())\n    await page.getByRole('button', { exact: true, name: 'Trigger a partial reload' }).click()\n    await expect(page.getByText('Loading...')).not.toBeVisible()\n\n    await responsePromise\n\n    await expect(page.getByText('John Doe')).toBeVisible()\n  })\n})\n\ntest('it will not revert to fallback when fetching a url that is different than the current page', async ({ page }) => {\n  test.skip(process.env.PACKAGE !== 'react', 'React only test')\n\n  await gotoPageAndWaitForContent(page, `/deferred-props/with-partial-reload/only`)\n\n  await expect(page.getByText('Loading...')).toBeVisible()\n\n  await page.waitForResponse(page.url())\n\n  await expect(page.getByText('Loading...')).not.toBeVisible()\n  await expect(page.getByText('John Doe')).toBeVisible()\n\n  const responsePromise = page.waitForResponse('/deferred-props/page-1')\n\n  await page.getByRole('link', { name: 'Prefetch' }).hover()\n\n  await page.waitForTimeout(100)\n\n  await expect(page.getByText('Loading...')).not.toBeVisible()\n\n  await responsePromise\n\n  await expect(page.getByText('John Doe')).toBeVisible()\n})\n\ntest('load deferred props in multiple groups', async ({ page }) => {\n  const props = ['foo', 'bar', 'baz', 'qux', 'quux']\n\n  await gotoPageAndWaitForContent(page, '/deferred-props/many-groups')\n\n  for (const prop of props) {\n    await expect(page.getByText(`Loading ${prop}...`)).toBeVisible()\n  }\n\n  for (const prop of props) {\n    await page.waitForResponse(\n      (response) => response.request().headers()['x-inertia-partial-data'] === prop && response.status() === 200,\n    )\n  }\n\n  for (const prop of props) {\n    await expect(page.getByText(`${prop} value`)).toBeVisible()\n  }\n})\n\ntest('load deferred props with partial reload on mount', async ({ page }) => {\n  await gotoPageAndWaitForContent(page, '/deferred-props/instant-reload')\n\n  await expect(page.getByText('Loading bar...')).toBeVisible()\n\n  await expect(page.getByText('foo value')).toBeVisible()\n  await expect(page.getByText('bar value')).toBeVisible()\n})\n\ntest('deferred props preserve query parameters from original URL', async ({ page }) => {\n  await gotoPageAndWaitForContent(page, '/deferred-props/with-query-params?filter=a')\n\n  // Verify the initial page load has the correct filter\n  await expect(page.getByText('Filter: a')).toBeVisible()\n  await expect(page.getByText('Loading users...')).toBeVisible()\n\n  // Wait for and capture the deferred props request\n  const deferredRequest = await page.waitForResponse((response) => {\n    const url = response.url()\n    const headers = response.request().headers()\n    return headers['x-inertia-partial-data'] === 'users' && url.includes('/deferred-props/with-query-params')\n  })\n\n  // Assert that the deferred props request includes the query parameter\n  const requestUrl = deferredRequest.url()\n  expect(requestUrl).toContain('filter=a')\n\n  // Verify the deferred data uses the correct filter\n  await expect(page.getByText('Loading users...')).not.toBeVisible()\n  await expect(page.getByText('users data for a')).toBeVisible()\n})\n\ntest('can partial reload deferred props independently', async ({ page }) => {\n  await gotoPageAndWaitForContent(page, '/deferred-props/partial-reloads')\n\n  await expect(page.getByText('Loading foo...')).toBeVisible()\n  await expect(page.getByText('Loading bar...')).toBeVisible()\n\n  await page.waitForResponse(page.url())\n\n  await expect(page.getByText('Loading foo...')).not.toBeVisible()\n  await expect(page.getByText('Loading bar...')).not.toBeVisible()\n\n  // Capture initial timestamps\n  const initialFooTimestamp = await page.locator('#foo-timestamp').textContent()\n  const initialBarTimestamp = await page.locator('#bar-timestamp').textContent()\n\n  expect(initialFooTimestamp).toBeTruthy()\n  expect(initialBarTimestamp).toBeTruthy()\n\n  const responsePromise = page.waitForResponse(\n    (response) => response.request().headers()['x-inertia-partial-data'] === 'foo' && response.status() === 200,\n  )\n\n  await page.getByRole('button', { name: 'Reload foo only' }).click()\n  await responsePromise\n\n  // Check that only foo changed\n  const newFooTimestamp = await page.locator('#foo-timestamp').textContent()\n  const newBarTimestamp = await page.locator('#bar-timestamp').textContent()\n\n  expect(newFooTimestamp).not.toBe(initialFooTimestamp) // foo changed\n  expect(newBarTimestamp).toBe(initialBarTimestamp) // bar unchanged\n\n  const barResponsePromise = page.waitForResponse(\n    (response) => response.request().headers()['x-inertia-partial-data'] === 'bar' && response.status() === 200,\n  )\n\n  await page.getByRole('button', { name: 'Reload bar only' }).click()\n  await barResponsePromise\n\n  // Check that only bar changed\n  const finalFooTimestamp = await page.locator('#foo-timestamp').textContent()\n  const finalBarTimestamp = await page.locator('#bar-timestamp').textContent()\n\n  expect(finalFooTimestamp).toBe(newFooTimestamp) // foo unchanged\n  expect(finalBarTimestamp).not.toBe(newBarTimestamp) // bar changed\n})\n\ntest('prefetch works with deferred props without errors', async ({ page }) => {\n  consoleMessages.listen(page)\n  const prefetch = page.waitForResponse('/deferred-props/page-3')\n\n  await gotoPageAndWaitForContent(page, '/deferred-props/page-1')\n  await expect(page.getByRole('link', { name: 'Page 3' })).toBeVisible()\n\n  consoleMessages.errors = []\n\n  await page.getByRole('link', { name: 'Page 3' }).hover()\n  await prefetch\n\n  const deferred = page.waitForResponse(\n    (response) =>\n      response.url().includes('/deferred-props/page-3') && 'x-inertia-partial-data' in response.request().headers(),\n  )\n\n  await page.getByRole('link', { name: 'Page 3' }).click()\n  await page.waitForURL('/deferred-props/page-3')\n\n  await deferred\n\n  await expect(page.getByText('alpha value')).toBeVisible()\n  await expect(page.getByText('beta value')).toBeVisible()\n\n  expect(consoleMessages.errors).toHaveLength(0)\n})\n\ntest('router.reload() without only/except triggers deferred props to reload', async ({ page }) => {\n  await gotoPageAndWaitForContent(page, '/deferred-props/with-reload')\n\n  await expect(page.getByText('Loading results...')).toBeVisible()\n\n  await page.waitForResponse(\n    (response) => response.request().headers()['x-inertia-partial-data'] === 'results' && response.status() === 200,\n  )\n\n  await expect(page.getByText('Loading results...')).not.toBeVisible()\n  await expect(page.locator('#results-data')).toHaveText('Item 1-1, Item 1-2, Item 1-3')\n  await expect(page.locator('#results-page')).toHaveText('Page: 1')\n\n  const deferredResponsePromise = page.waitForResponse(\n    (response) => response.request().headers()['x-inertia-partial-data'] === 'results' && response.status() === 200,\n  )\n\n  await page.getByRole('button', { name: 'Reload with page 2' }).click()\n\n  await expect(page.getByText('Loading results...')).toBeVisible()\n\n  await deferredResponsePromise\n\n  await expect(page.getByText('Loading results...')).not.toBeVisible()\n  await expect(page.locator('#results-data')).toHaveText('Item 2-1, Item 2-2, Item 2-3')\n  await expect(page.locator('#results-page')).toHaveText('Page: 2')\n})\n\ntest('it does not render children with undefined props during reload (#2758)', async ({ page }) => {\n  consoleMessages.listen(page)\n\n  await gotoPageAndWaitForContent(page, '/deferred-props/reload-without-optional-chaining')\n\n  expect(consoleMessages.errors).toHaveLength(0)\n\n  await expect(page.getByText('Loading results...')).toBeVisible()\n\n  await page.waitForResponse(\n    (response) => response.request().headers()['x-inertia-partial-data'] === 'results' && response.status() === 200,\n  )\n\n  await expect(page.getByText('Loading results...')).not.toBeVisible()\n  await expect(page.locator('#results-data')).toHaveText('Item 1-1, Item 1-2, Item 1-3')\n  await expect(page.locator('#results-page')).toHaveText('Page: 1')\n\n  consoleMessages.errors = []\n\n  const deferredResponsePromise = page.waitForResponse(\n    (response) => response.request().headers()['x-inertia-partial-data'] === 'results' && response.status() === 200,\n  )\n\n  await page.getByRole('button', { name: 'Reload with page 2' }).click()\n\n  await deferredResponsePromise\n\n  await expect(page.locator('#results-data')).toHaveText('Item 2-1, Item 2-2, Item 2-3')\n  await expect(page.locator('#results-page')).toHaveText('Page: 2')\n\n  expect(consoleMessages.errors).toHaveLength(0)\n})\n\ntest('deferred props do not clear validation errors', async ({ page }) => {\n  await gotoPageAndWaitForContent(page, '/deferred-props/with-errors')\n\n  await expect(page.locator('#page-error')).not.toBeVisible()\n  await expect(page.locator('#form-error')).not.toBeVisible()\n  await expect(page.getByText('Loading foo...')).toBeVisible()\n\n  await page.waitForResponse(\n    (response) => response.request().headers()['x-inertia-partial-data'] === 'foo' && response.status() === 200,\n  )\n\n  await expect(page.getByText('foo value')).toBeVisible()\n\n  const deferredResponsePromise = page.waitForResponse(\n    (response) => response.request().headers()['x-inertia-partial-data'] === 'foo' && response.status() === 200,\n  )\n  const errorResponsePromise = page.waitForResponse(\n    (response) => !response.request().headers()['x-inertia-partial-data'] && response.status() === 200,\n  )\n\n  await page.getByRole('button', { name: 'Submit' }).click()\n  await errorResponsePromise\n\n  await expect(page.locator('#page-error')).toBeVisible()\n  await expect(page.locator('#page-error')).toHaveText('The name field is required.')\n  await expect(page.locator('#form-error')).toBeVisible()\n  await expect(page.locator('#form-error')).toHaveText('The name field is required.')\n  await expect(page.getByText('Loading foo...')).toBeVisible()\n\n  await deferredResponsePromise\n\n  await expect(page.locator('#page-error')).toBeVisible()\n  await expect(page.locator('#page-error')).toHaveText('The name field is required.')\n  await expect(page.locator('#form-error')).toBeVisible()\n  await expect(page.locator('#form-error')).toHaveText('The name field is required.')\n  await expect(page.getByText('foo value')).toBeVisible()\n})\n\ntest('it refetches pending deferred props after navigating back', async ({ page }) => {\n  await gotoPageAndWaitForContent(page, '/deferred-props/back-button/a')\n\n  await expect(page.getByText('Loading fast prop...')).toBeVisible()\n  await expect(page.getByText('Loading slow prop...')).toBeVisible()\n\n  // Navigate away before deferred props load\n  await page.getByRole('link', { name: 'Go to Page B' }).click()\n  await page.waitForURL('/deferred-props/back-button/b')\n\n  await page.goBack()\n  await page.waitForURL('/deferred-props/back-button/a')\n\n  // Both props should eventually load after navigating back\n  await expect(page.getByText('Fast prop loaded')).toBeVisible()\n  await expect(page.getByText('Slow prop loaded')).toBeVisible()\n})\n\ntest('it only refetches deferred props that were not loaded before navigating away', async ({ page }) => {\n  await gotoPageAndWaitForContent(page, '/deferred-props/back-button/a')\n\n  await expect(page.getByText('Loading fast prop...')).toBeVisible()\n  await expect(page.getByText('Loading slow prop...')).toBeVisible()\n\n  await expect(page.getByText('Fast prop loaded')).toBeVisible()\n  await expect(page.getByText('Loading slow prop...')).toBeVisible()\n\n  await page.getByRole('link', { name: 'Go to Page B' }).click()\n  await page.waitForURL('/deferred-props/back-button/b')\n\n  await page.goBack()\n  await page.waitForURL('/deferred-props/back-button/a')\n\n  await expect(page.getByText('Fast prop loaded')).toBeVisible()\n  await expect(page.getByText('Loading slow prop...')).toBeVisible()\n\n  await expect(page.getByText('Slow prop loaded')).toBeVisible()\n})\n\ntest('it does not refetch deferred props that were already loaded on a previous back navigation', async ({ page }) => {\n  await gotoPageAndWaitForContent(page, '/deferred-props/back-button/a')\n\n  // Quickly navigate away before deferred props load\n  await expect(page.getByText('Loading fast prop...')).toBeVisible()\n  await page.getByRole('link', { name: 'Go to Page B' }).click()\n  await page.waitForURL('/deferred-props/back-button/b')\n\n  // Go back and wait for deferred props to fully load\n  await page.goBack()\n  await page.waitForURL('/deferred-props/back-button/a')\n  await expect(page.getByText('Fast prop loaded')).toBeVisible()\n  await expect(page.getByText('Slow prop loaded')).toBeVisible()\n\n  // Navigate to Page B again and wait for its deferred props\n  await page.getByRole('link', { name: 'Go to Page B' }).click()\n  await page.waitForURL('/deferred-props/back-button/b')\n  await expect(page.getByText('Page B data loaded')).toBeVisible()\n\n  // Start listening for requests before going back\n  requests.listen(page)\n\n  // Go back to Page A - no requests should be made since props are already loaded\n  await page.goBack()\n  await page.waitForURL('/deferred-props/back-button/a')\n\n  await expect(page.getByText('Fast prop loaded')).toBeVisible()\n  await expect(page.getByText('Slow prop loaded')).toBeVisible()\n\n  expect(requests.requests).toHaveLength(0)\n})\n"
  },
  {
    "path": "tests/domUtils.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\n\ntest.describe('getScrollableParent', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/scrollable-parent')\n  })\n\n  test.describe('no scrollable parent', () => {\n    test('overflow-x: hidden is not a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-overflow-x-hidden')).toHaveText('null')\n    })\n\n    test('overflow-y: auto without height is not a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-overflow-y-auto-no-height')).toHaveText('null')\n    })\n\n    test('overflow: auto without constraints is not a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-overflow-auto-no-constraints')).toHaveText('null')\n    })\n\n    test('overflow: clip is not a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-overflow-clip')).toHaveText('null')\n    })\n\n    test('overflow-y: auto with overflow-x: hidden and no height is not a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-overflow-y-auto-overflow-x-hidden')).toHaveText('null')\n    })\n\n    test('overflow-x: auto with overflow-y: hidden and no width is not a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-overflow-x-auto-overflow-y-hidden')).toHaveText('null')\n    })\n  })\n\n  test.describe('has scrollable parent', () => {\n    test('overflow-x: scroll is a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-overflow-x-scroll')).toHaveText('scroll-container-x')\n    })\n\n    test('overflow-y: auto with height is a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-overflow-y-auto')).toHaveText('scroll-container-y')\n    })\n\n    test('overflow-x: scroll, overflow-y: hidden is a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-overflow-x-scroll-y-hidden')).toHaveText('scroll-container-x-y-hidden')\n    })\n\n    test('overflow-x: scroll with max-width is a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-horizontal-scroll-calc')).toHaveText('scroll-container-max-width')\n    })\n\n    test('overflow-y: auto with max-height is a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-vertical-scroll-max-height')).toHaveText('scroll-container-max-height')\n    })\n\n    test('finds nearest scrollable parent in nested containers', async ({ page }) => {\n      await expect(page.getByTestId('result-nested-scroll')).toHaveText('inner-scroll')\n    })\n\n    test('flex horizontal carousel is a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-flex-horizontal-carousel')).toHaveText('flex-carousel')\n    })\n\n    test('overflow-x: scroll with coerced overflow-y auto is a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-coerced-auto-no-constraint')).toHaveText('coerced-auto')\n    })\n\n    test('display: contents is skipped and finds parent scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-display-contents')).toHaveText('scroll-container-skip-contents')\n    })\n\n    test('overflow: overlay is a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-overflow-overlay')).toHaveText('scroll-container-overlay')\n    })\n\n    test('overflow-x: auto with inline width is a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-inline-width-style')).toHaveText('inline-width-container')\n    })\n\n    test('overflow: scroll in both directions is a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-both-scroll-directions')).toHaveText('both-scroll')\n    })\n\n    test('overflow-y: auto with overflow-x: visible is a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-overflow-y-auto-overflow-x-visible')).toHaveText(\n        'overflow-y-auto-x-visible',\n      )\n    })\n\n    test('overflow-y: auto with overflow-x: clip is a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-overflow-y-auto-overflow-x-clip')).toHaveText('overflow-y-auto-x-clip')\n    })\n\n    test('overflow-x: auto with overflow-y: visible is a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-overflow-x-auto-overflow-y-visible')).toHaveText(\n        'overflow-x-auto-y-visible',\n      )\n    })\n\n    test('overflow-x: auto with overflow-y: clip is a scroll container', async ({ page }) => {\n      await expect(page.getByTestId('result-overflow-x-auto-overflow-y-clip')).toHaveText('overflow-x-auto-y-clip')\n    })\n  })\n})\n"
  },
  {
    "path": "tests/error-modal.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport { pageLoads } from './support'\n\nconst elements = ['dialog', 'div']\n\nelements.forEach((element) => {\n  test.describe(`modal using the <${element}> element`, () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto(element === 'dialog' ? '/error-modal?dialog=1' : '/error-modal')\n    })\n\n    test('uses the correct element', async ({ page }) => {\n      await page.getByText('Invalid Visit', { exact: true }).click()\n\n      if (element === 'dialog') {\n        await expect(page.locator('dialog#inertia-error-dialog > iframe')).toBeVisible()\n      } else {\n        await expect(page.locator('div > iframe')).toBeVisible()\n      }\n    })\n\n    test('displays the modal containing the response as HTML when an invalid Inertia response comes back', async ({\n      page,\n    }) => {\n      await page.getByText('Invalid Visit', { exact: true }).click()\n      await expect(page.frameLocator('iframe').getByText('This is a page that does not')).toBeVisible()\n      await expect(page.frameLocator('iframe').locator('body')).toContainText(\n        'This is a page that does not have the Inertia app loaded.',\n      )\n    })\n\n    test('displays the modal with a helpful message when a regular JSON response comes back instead of an Inertia response', async ({\n      page,\n    }) => {\n      await page.getByText('Invalid Visit (JSON response)').click()\n      await expect(page.frameLocator('iframe').locator('body')).toContainText(\n        'All Inertia requests must receive a valid Inertia response, however a plain JSON response was received.',\n      )\n      await page.frameLocator('iframe').getByText('All Inertia requests must').click()\n      await expect(page.frameLocator('iframe').locator('body')).toContainText('{\"foo\":\"bar\"}')\n    })\n\n    test('can close the modal using the escape key', async ({ page }) => {\n      await page.getByText('Invalid Visit', { exact: true }).click()\n      await expect(page.frameLocator('iframe').getByText('This is a page that does not')).toBeVisible()\n      await page.locator('body').press('Escape')\n      await expect(page.frameLocator('iframe').getByText('This is a page that does not')).toBeHidden()\n    })\n\n    test('closes the modal when clicking outside of it', async ({ page }) => {\n      await page.getByText('Invalid Visit', { exact: true }).click()\n      await expect(page.frameLocator('iframe').getByText('This is a page that does not')).toBeVisible()\n      await page.mouse.click(25, 25)\n      await expect(page.frameLocator('iframe').getByText('This is a page that does not')).toBeHidden()\n    })\n  })\n})\n"
  },
  {
    "path": "tests/events.spec.ts",
    "content": "import { expect, Page, test } from '@playwright/test'\nimport { clickAndWaitForResponse, pageLoads } from './support'\n\nconst listenForGlobalMessages = async (page: Page, event, stringifyDetail = false) => {\n  await page.evaluate(\n    ({ event: eventName, stringifyDetail }) => {\n      // @ts-ignore\n      window.globalMessages = window.globalMessages || {}\n\n      // @ts-ignore\n      window.globalMessages[eventName] = []\n\n      document.addEventListener(eventName, (e) => {\n        // @ts-ignore\n        window.globalMessages[eventName].push({\n          isCustomEvent: e instanceof CustomEvent,\n          type: e.type,\n          cancelable: e.cancelable,\n          detail: stringifyDetail ? JSON.stringify(e.detail) : e.detail,\n        })\n      })\n    },\n    { event, stringifyDetail },\n  )\n}\n\nconst assertVisitObject = async (visit) => {\n  await expect(visit.url).toBeDefined()\n  await expect(visit.method).toBeDefined()\n  await expect(visit.data).toBeDefined()\n  await expect(visit.headers).toBeDefined()\n  await expect(visit.preserveState).toBeDefined()\n}\n\nconst assertPageObject = async (page) => {\n  await expect(page.component).toBeDefined()\n  await expect(page.props).toBeDefined()\n  await expect(page.url).toBeDefined()\n  await expect(page.version).toBeDefined()\n}\n\nconst assertProgressObject = async (progress) => {\n  await expect(progress.percentage).toBeDefined()\n  await expect(progress.total).toBeDefined()\n  await expect(progress.loaded).toBeDefined()\n  await expect(progress.percentage).toBeGreaterThanOrEqual(0)\n  await expect(progress.percentage).toBeLessThanOrEqual(100)\n}\n\nconst assertCancelToken = async (token) => {\n  // TODO: Fix this, result is getting mangled by playwright somewhere along the way\n  return\n  await expect(token.cancel).toBeDefined()\n}\n\nconst assertIsGlobalEvent = async (event, expectedType, cancelable) => {\n  await expect(event.isCustomEvent).toBe(true)\n  await expect(event.type).toBe(expectedType)\n  await expect(event.cancelable).toBe(cancelable)\n}\n\nconst assertGlobalErrorEvent = async (event) => {\n  await assertIsGlobalEvent(event, 'inertia:error', false)\n  await assertErrorsObject(event.detail.errors)\n}\n\nconst assertGlobalSuccessEvent = async (event) => {\n  await assertIsGlobalEvent(event, 'inertia:success', false)\n  await assertPageObject(event.detail.page)\n}\n\nconst assertErrorsObject = async (errors) => {\n  await expect(errors.foo).toBeDefined()\n  await expect(errors.foo).toBe('bar')\n}\n\nconst assertResponseObject = async (response) => {\n  await expect(response.headers).toBeDefined()\n  await expect(response.data).toBeDefined()\n  await expect(response.status).toBeDefined()\n}\n\nconst assertExceptionObject = async (detail) => {\n  await expect(detail.exception).toBeDefined()\n  await expect(detail.exception.code).toBe('ERR_NETWORK')\n}\n\nconst assertGlobalFinishEvent = async (event) => {\n  await assertIsGlobalEvent(event, 'inertia:finish', false)\n  await assertVisitObject(event.detail.visit)\n}\n\nconst waitForMessages = async (page: Page, count?: number): Promise<any[string]> => {\n  if (typeof count === 'number') {\n    await page.waitForFunction((count) => (window as any).messages.length === count, count)\n  }\n\n  return await page.evaluate(() => (window as any).messages)\n}\n\nconst waitForGlobalMessages = async (page: Page, event: string, count?: number): Promise<any[string]> => {\n  if (typeof count === 'number') {\n    await page.waitForFunction(({ count, event }) => (window as any).globalMessages[event].length === count, {\n      count,\n      event,\n    })\n  }\n\n  return await page.evaluate((event) => (window as any).globalMessages[event], event)\n}\n\ntest.describe('Events', () => {\n  test.beforeEach(async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/events')\n  })\n\n  test.describe('Listeners', () => {\n    test('does not have any listeners by default', async ({ page }) => {\n      await page.getByRole('link', { name: 'Basic Visit' }).click()\n      await waitForMessages(page, 0)\n    })\n\n    test.describe('Inertia.on', () => {\n      test('returns a callback that can be used to remove the global listener', async ({ page }) => {\n        await page.getByRole('link', { name: 'Remove Inertia Listener' }).click()\n\n        const messages = await waitForMessages(page, 3)\n\n        await expect(messages[0]).toBe('Removing Inertia.on Listener')\n        await expect(messages[1]).toBe('onBefore')\n        await expect(messages[2]).toBe('onStart')\n      })\n    })\n  })\n\n  test.describe('Hooks', () => {\n    test.describe('before', () => {\n      test('fires the event when a request is about to be made', async ({ page }) => {\n        await listenForGlobalMessages(page, 'inertia:before')\n\n        await page.getByRole('link', { exact: true, name: 'Before Event' }).click()\n\n        const messages = await waitForMessages(page)\n        const globalMessages = await page.evaluate(() => (window as any).globalMessages['inertia:before'])\n\n        // Local Event Callback\n        await expect(messages[0]).toBe('onBefore')\n        await assertVisitObject(messages[1])\n\n        // Global Inertia Event Listener\n        await expect(messages[2]).toBe('Inertia.on(before)')\n\n        await expect(globalMessages).toHaveLength(1)\n\n        await assertIsGlobalEvent(globalMessages[0], 'inertia:before', true)\n        await assertVisitObject(globalMessages[0].detail.visit)\n\n        // Ensure the listeners did not prevent the visit\n        await expect(messages[6]).toBe('onStart')\n      })\n\n      test('fires the event when a request is about to be made (link)', async ({ page }) => {\n        await page.getByRole('button', { exact: true, name: 'Before Event Link' }).click()\n\n        const messages = await waitForMessages(page)\n\n        // Link Event Callback\n        await expect(messages[0]).toBe('linkOnBefore')\n        assertVisitObject(messages[1])\n\n        // Ensure the listeners did not prevent the visit\n        await expect(messages[2]).toBe('linkOnStart')\n      })\n\n      test.describe('Local Event Callbacks', () => {\n        test('can prevent the visit by returning false', async ({ page }) => {\n          await page.getByRole('link', { exact: true, name: 'Before Event (Prevent)' }).click()\n\n          const messages = await waitForMessages(page, 1)\n          await expect(messages[0]).toBe('onBefore')\n        })\n\n        test('can prevent the visit by returning false (link)', async ({ page }) => {\n          await page.getByRole('button', { exact: true, name: 'Before Event Link (Prevent)' }).click()\n\n          const messages = await waitForMessages(page, 1)\n          await expect(messages[0]).toBe('linkOnBefore')\n        })\n      })\n\n      test.describe('Global Inertia.on', () => {\n        test('can prevent the visit by returning false ', async ({ page }) => {\n          await page\n            .getByRole('link', { exact: true, name: 'Before Event - Prevent globally using Inertia Event Listener' })\n            .click()\n\n          const messages = await waitForMessages(page, 3)\n          await expect(messages[0]).toBe('onBefore')\n          await expect(messages[1]).toBe('addEventListener(inertia:before)')\n          await expect(messages[2]).toBe('Inertia.on(before)')\n        })\n      })\n\n      test.describe('Global addEventListener', () => {\n        test('can prevent the visit by using preventDefault', async ({ page }) => {\n          await page\n            .getByRole('link', { exact: true, name: 'Before Event - Prevent globally using Native Event Listeners' })\n            .click()\n\n          const messages = await waitForMessages(page, 3)\n          await expect(messages[0]).toBe('onBefore')\n          await expect(messages[1]).toBe('Inertia.on(before)')\n          await expect(messages[2]).toBe('addEventListener(inertia:before)')\n        })\n      })\n    })\n\n    test.describe('cancelToken', () => {\n      test('fires when the request is starting', async ({ page }) => {\n        await page.getByRole('link', { exact: true, name: 'Cancel Token Event' }).click()\n\n        // Assert that it only gets fired locally.\n        const messages = await waitForMessages(page, 2)\n        await expect(messages[0]).toBe('onCancelToken')\n        assertCancelToken(messages[1])\n      })\n\n      test('fires when the request is starting (link)', async ({ page }) => {\n        await page.getByRole('button', { exact: true, name: 'Cancel Token Event Link' }).click()\n\n        // Assert that it only gets fired locally.\n        const messages = await waitForMessages(page, 2)\n        await expect(messages[0]).toBe('linkOnCancelToken')\n        assertCancelToken(messages[1])\n      })\n    })\n\n    test.describe('cancel', () => {\n      test('fires when the request was cancelled', async ({ page }) => {\n        await page.getByRole('link', { exact: true, name: 'Cancel Event' }).click()\n\n        const messages = await waitForMessages(page, 2)\n        await expect(messages[0]).toBe('onCancel')\n        await expect(messages[1]).toBeUndefined()\n      })\n\n      test('fires when the request was cancelled (link)', async ({ page }) => {\n        await page.getByRole('button', { exact: true, name: 'Cancel Event Link' }).click()\n\n        const messages = await waitForMessages(page, 2)\n        await expect(messages[0]).toBe('linkOnCancel')\n        await expect(messages[1]).toBeUndefined()\n      })\n    })\n\n    test.describe('start', () => {\n      test('fires when the request has started', async ({ page }) => {\n        await listenForGlobalMessages(page, 'inertia:start')\n\n        await page.getByRole('link', { exact: true, name: 'Start Event' }).click()\n\n        const messages = await waitForMessages(page, 6)\n        const globalMessages = await waitForGlobalMessages(page, 'inertia:start', 1)\n\n        await assertIsGlobalEvent(globalMessages[0], 'inertia:start', false)\n        await assertVisitObject(globalMessages[0].detail.visit)\n\n        // Global Inertia Event Listener\n        await expect(messages[0]).toBe('Inertia.on(start)')\n\n        // Global Native Event Listener\n        await expect(messages[2]).toBe('addEventListener(inertia:start)')\n\n        // Local Event Callback\n        await expect(messages[4]).toBe('onStart')\n        assertVisitObject(messages[5])\n      })\n\n      test('fires when the request has started (link)', async ({ page }) => {\n        await page.getByRole('button', { exact: true, name: 'Start Event Link' }).click()\n\n        // Local Event Callback\n        const messages = await waitForMessages(page, 2)\n        await expect(messages[0]).toBe('linkOnStart')\n        assertVisitObject(messages[1])\n      })\n    })\n\n    test.describe('progress', () => {\n      test('fires when the request has files and upload progression occurs', async ({ page }) => {\n        await listenForGlobalMessages(page, 'inertia:progress')\n        await clickAndWaitForResponse(page, 'Progress Event')\n\n        const messages = await waitForMessages(page, 6)\n        const globalMessages = await waitForGlobalMessages(page, 'inertia:progress', 1)\n\n        await assertIsGlobalEvent(globalMessages[0], 'inertia:progress', false)\n        await assertProgressObject(globalMessages[0].detail.progress)\n\n        // Global Inertia Event Listener\n        await expect(messages[0]).toBe('Inertia.on(progress)')\n\n        // Global Native Event Listener\n        await expect(messages[2]).toBe('addEventListener(inertia:progress)')\n\n        // Local Event Callback\n        await expect(messages[4]).toBe('onProgress')\n        await assertProgressObject(messages[5])\n      })\n\n      test('fires when the request has files and upload progression occurs (link)', async ({ page }) => {\n        await clickAndWaitForResponse(page, 'Progress Event Link', null, 'button')\n\n        const messages = await waitForMessages(page, 2)\n        await expect(messages[0]).toBe('linkOnProgress')\n        await assertProgressObject(messages[1])\n      })\n\n      test('does not fire when the request has no files', async ({ page }) => {\n        await page.getByRole('link', { exact: true, name: 'Missing Progress Event (no files)' }).click()\n        const messages = await waitForMessages(page, 1)\n        await expect(messages[0]).toBe('progressNoFilesOnBefore')\n      })\n\n      test('does not fire when the request has no files (link)', async ({ page }) => {\n        await page.getByRole('button', { exact: true, name: 'Progress Event Link (no files)' }).click()\n        const messages = await waitForMessages(page, 1)\n        await expect(messages[0]).toBe('linkProgressNoFilesOnBefore')\n      })\n    })\n\n    test.describe('error', () => {\n      test('fires when the request finishes with validation errors', async ({ page }) => {\n        await listenForGlobalMessages(page, 'inertia:error')\n        await clickAndWaitForResponse(page, 'Error Event', 'events/errors')\n\n        const messages = await waitForMessages(page, 6)\n        const globalMessages = await waitForGlobalMessages(page, 'inertia:error', 1)\n\n        await assertGlobalErrorEvent(globalMessages[0])\n\n        // Global Inertia Event Listener\n        await expect(messages[0]).toBe('Inertia.on(error)')\n\n        // Global Native Event Listener\n        await expect(messages[2]).toBe('addEventListener(inertia:error)')\n\n        // Local Event Callback\n        await expect(messages[4]).toBe('onError')\n        await assertErrorsObject(messages[5])\n      })\n\n      test('fires when the request finishes with validation errors (link)', async ({ page }) => {\n        await listenForGlobalMessages(page, 'inertia:error')\n        await clickAndWaitForResponse(page, 'Error Event Link', 'events/errors', 'button')\n\n        const messages = await waitForMessages(page, 2)\n        const globalMessages = await waitForGlobalMessages(page, 'inertia:error', 1)\n\n        // Global Inertia Event Listener\n        await expect(messages[0]).toBe('linkOnError')\n        await expect(messages[1]).toEqual({ foo: 'bar' })\n        await assertGlobalErrorEvent(globalMessages[0])\n      })\n    })\n\n    test.describe('Local Event Callbacks', () => {\n      test('can delay onFinish from firing by returning a promise', async ({ page }) => {\n        await clickAndWaitForResponse(page, 'Error Event (delaying onFinish w/ Promise)', 'events/errors')\n\n        const messages = await waitForMessages(page, 3)\n        await expect(messages[0]).toBe('onError')\n        await expect(messages[1]).toBe('onFinish should have been fired by now if Promise functionality did not work')\n        await expect(messages[2]).toBe('onFinish')\n      })\n\n      test('can delay onFinish from firing by returning a promise (link)', async ({ page }) => {\n        test.skip(process.env.PACKAGE === 'svelte', 'Feature not supported by the Svelte adapter')\n\n        await page.getByRole('button', { exact: true, name: 'Error Event Link (delaying onFinish w/ Promise)' }).click()\n\n        const messages = await waitForMessages(page, 3)\n        await expect(messages[0]).toBe('linkOnError')\n        await expect(messages[1]).toBe('onFinish should have been fired by now if Promise functionality did not work')\n        await expect(messages[2]).toBe('linkOnFinish')\n      })\n    })\n  })\n\n  test.describe('success', () => {\n    test('fires when the request finished without validation errors', async ({ page }) => {\n      await listenForGlobalMessages(page, 'inertia:success')\n\n      await clickAndWaitForResponse(page, 'Success Event')\n\n      const messages = await waitForMessages(page, 6)\n      const globalMessages = await waitForGlobalMessages(page, 'inertia:success', 1)\n\n      await assertGlobalSuccessEvent(globalMessages[0])\n\n      // Global Inertia Event Listener\n      await expect(messages[0]).toBe('Inertia.on(success)')\n\n      // Global Native Event Listener\n      await expect(messages[2]).toBe('addEventListener(inertia:success)')\n\n      // Local Event Callback\n      await expect(messages[4]).toBe('onSuccess')\n      await assertPageObject(messages[5])\n    })\n\n    test('fires when the request finished without validation errors (link)', async ({ page }) => {\n      await listenForGlobalMessages(page, 'inertia:success')\n      await clickAndWaitForResponse(page, 'Success Event Link', null, 'button')\n\n      const messages = await waitForMessages(page, 2)\n      const globalMessages = await waitForGlobalMessages(page, 'inertia:success', 1)\n\n      await assertGlobalSuccessEvent(globalMessages[0])\n\n      // Global Inertia Event Listener\n      await expect(messages[0]).toBe('linkOnSuccess')\n    })\n\n    test.describe('Local Event Callbacks', () => {\n      test('can delay onFinish from firing by returning a promise', async ({ page }) => {\n        await page.getByRole('link', { exact: true, name: 'Success Event (delaying onFinish w/ Promise)' }).click()\n\n        const messages = await waitForMessages(page, 3)\n        await expect(messages[0]).toBe('onSuccess')\n        await expect(messages[1]).toBe('onFinish should have been fired by now if Promise functionality did not work')\n        await expect(messages[2]).toBe('onFinish')\n      })\n\n      test('can delay onFinish from firing by returning a promise (link)', async ({ page }) => {\n        test.skip(process.env.PACKAGE === 'svelte', 'Feature not supported by the Svelte adapter')\n\n        await page\n          .getByRole('button', { exact: true, name: 'Success Event Link (delaying onFinish w/ Promise)' })\n          .click()\n\n        const messages = await waitForMessages(page, 3)\n        await expect(messages[0]).toBe('linkOnSuccess')\n        await expect(messages[1]).toBe('onFinish should have been fired by now if Promise functionality did not work')\n        await expect(messages[2]).toBe('linkOnFinish')\n      })\n    })\n  })\n\n  test.describe('invalid', () => {\n    test('gets fired when a non-Inertia response is received', async ({ page }) => {\n      await listenForGlobalMessages(page, 'inertia:invalid')\n      await clickAndWaitForResponse(page, 'Invalid Event', 'non-inertia')\n\n      const messages = await waitForMessages(page, 4)\n      const globalMessages = await waitForGlobalMessages(page, 'inertia:invalid', 1)\n\n      await assertIsGlobalEvent(globalMessages[0], 'inertia:invalid', true)\n      await assertResponseObject(globalMessages[0].detail.response)\n\n      // Global Inertia Event Listener\n      await expect(messages[0]).toBe('Inertia.on(invalid)')\n\n      // Global Native Event Listener\n      await expect(messages[2]).toBe('addEventListener(inertia:invalid)')\n    })\n  })\n\n  test.describe('exception', () => {\n    test('gets fired when an unexpected situation occurs (e.g. network disconnect)', async ({ page }) => {\n      await listenForGlobalMessages(page, 'inertia:exception', true)\n      await page.getByRole('link', { exact: true, name: 'Exception Event' }).click()\n\n      const messages = await waitForMessages(page, 4)\n      const globalMessages = await waitForGlobalMessages(page, 'inertia:exception', 1)\n\n      await assertIsGlobalEvent(globalMessages[0], 'inertia:exception', true)\n      await assertExceptionObject(JSON.parse(globalMessages[0].detail))\n\n      // Global Inertia Event Listener\n      await expect(messages[0]).toBe('Inertia.on(exception)')\n\n      // Global Native Event Listener\n      await expect(messages[2]).toBe('addEventListener(inertia:exception)')\n    })\n  })\n\n  test.describe('finish', () => {\n    test('fires when the request completes', async ({ page }) => {\n      await listenForGlobalMessages(page, 'inertia:finish')\n      await clickAndWaitForResponse(page, 'Finish Event')\n\n      const messages = await waitForMessages(page, 6)\n      const globalMessages = await waitForGlobalMessages(page, 'inertia:finish', 1)\n\n      await assertGlobalFinishEvent(globalMessages[0])\n\n      // Global Inertia Event Listener\n      await expect(messages[0]).toBe('Inertia.on(finish)')\n\n      // Global Native Event Listener\n      await expect(messages[2]).toBe('addEventListener(inertia:finish)')\n\n      // Local Event Callback\n      await expect(messages[4]).toBe('onFinish')\n      await assertVisitObject(messages[5])\n    })\n\n    test('fires when the request completes (link)', async ({ page }) => {\n      await listenForGlobalMessages(page, 'inertia:finish')\n      await clickAndWaitForResponse(page, 'Finish Event Link', null, 'button')\n\n      const messages = await waitForMessages(page, 2)\n      const globalMessages = await waitForGlobalMessages(page, 'inertia:finish', 1)\n\n      await assertGlobalFinishEvent(globalMessages[0])\n\n      await expect(messages[0]).toBe('linkOnFinish')\n    })\n  })\n\n  test.describe('navigate', () => {\n    test('fires when the page navigates away after a successful request', async ({ page }) => {\n      await listenForGlobalMessages(page, 'inertia:navigate')\n      await page.getByRole('link', { exact: true, name: 'Navigate Event' }).click()\n\n      const messages = await waitForMessages(page, 4)\n      const globalMessages = await waitForGlobalMessages(page, 'inertia:navigate', 1)\n\n      await assertIsGlobalEvent(globalMessages[0], 'inertia:navigate', false)\n      await assertPageObject(globalMessages[0].detail.page)\n\n      // Global Inertia Event Listener\n      await expect(messages[0]).toBe('Inertia.on(navigate)')\n\n      // Global Native Event Listener\n      await expect(messages[2]).toBe('addEventListener(inertia:navigate)')\n    })\n  })\n\n  test.describe('prefetching/prefetched', () => {\n    test('fires when using Link component event handlers', async ({ page }) => {\n      const prefetchResponse = page.waitForResponse('**/prefetch/2')\n\n      await page.getByRole('button', { name: 'Prefetch Event Link (Hover)' }).hover()\n      await prefetchResponse\n\n      const messages = await waitForMessages(page)\n\n      // Link Event Callbacks\n      const prefetchingIndex = messages.findIndex((msg) => msg === 'linkOnPrefetching')\n      const prefetchedIndex = messages.findIndex((msg) => msg === 'linkOnPrefetched')\n\n      await expect(prefetchingIndex).toBeGreaterThanOrEqual(0)\n      await expect(prefetchedIndex).toBeGreaterThanOrEqual(0)\n      await expect(prefetchingIndex).toBeLessThan(prefetchedIndex)\n\n      // Verify the visit and response objects were passed correctly\n      const visitObject = messages[prefetchingIndex + 1]\n      const responseObject = messages[prefetchedIndex + 1]\n\n      await assertVisitObject(visitObject)\n      await expect(visitObject.url.pathname).toBe('/prefetch/2')\n      await expect(responseObject.status).toBe(200)\n    })\n  })\n})\n\ntest.describe('Lifecycles', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/events')\n  })\n\n  test('fires all expected events in the correct order on a successful request', async ({ page }) => {\n    await page.getByRole('link', { exact: true, name: 'Lifecycle Success' }).click()\n\n    const messages = await waitForMessages(page, 16)\n\n    await expect(messages[0]).toBe('onBefore')\n    await expect(messages[1]).toBe('Inertia.on(before)')\n    await expect(messages[2]).toBe('addEventListener(inertia:before)')\n    await expect(messages[3]).toBe('onCancelToken')\n    await expect(messages[4]).toBe('Inertia.on(start)')\n    await expect(messages[5]).toBe('addEventListener(inertia:start)')\n    await expect(messages[6]).toBe('onStart')\n    await expect(messages[7]).toBe('Inertia.on(progress)')\n    await expect(messages[8]).toBe('addEventListener(inertia:progress)')\n    await expect(messages[9]).toBe('onProgress')\n    await expect(messages[10]).toBe('Inertia.on(success)')\n    await expect(messages[11]).toBe('addEventListener(inertia:success)')\n    await expect(messages[12]).toBe('onSuccess')\n    await expect(messages[13]).toBe('Inertia.on(finish)')\n    await expect(messages[14]).toBe('addEventListener(inertia:finish)')\n    await expect(messages[15]).toBe('onFinish')\n  })\n\n  test('fires all expected events in the correct order on an error request', async ({ page }) => {\n    await clickAndWaitForResponse(page, 'Lifecycle Error', 'events/errors')\n\n    const messages = await waitForMessages(page, 18)\n\n    await expect(messages[0]).toBe('onBefore')\n    await expect(messages[1]).toBe('Inertia.on(before)')\n    await expect(messages[2]).toBe('addEventListener(inertia:before)')\n    await expect(messages[3]).toBe('onCancelToken')\n    await expect(messages[4]).toBe('Inertia.on(start)')\n    await expect(messages[5]).toBe('addEventListener(inertia:start)')\n    await expect(messages[6]).toBe('onStart')\n    await expect(messages[7]).toBe('Inertia.on(progress)')\n    await expect(messages[8]).toBe('addEventListener(inertia:progress)')\n    await expect(messages[9]).toBe('onProgress')\n    await expect(messages[10]).toBe('Inertia.on(navigate)')\n    await expect(messages[11]).toBe('addEventListener(inertia:navigate)')\n    await expect(messages[12]).toBe('Inertia.on(error)')\n    await expect(messages[13]).toBe('addEventListener(inertia:error)')\n    await expect(messages[14]).toBe('onError')\n    await expect(messages[15]).toBe('Inertia.on(finish)')\n    await expect(messages[16]).toBe('addEventListener(inertia:finish)')\n    await expect(messages[17]).toBe('onFinish')\n  })\n\n  test.describe('Cancelling', () => {\n    test('cancels a visit before it completes', async ({ page }) => {\n      await page.getByRole('link', { exact: true, name: 'Lifecycle Cancel' }).click()\n\n      const messages = await waitForMessages(page, 15)\n\n      await expect(messages[0]).toBe('onBefore')\n      await expect(messages[1]).toBe('Inertia.on(before)')\n      await expect(messages[2]).toBe('addEventListener(inertia:before)')\n      await expect(messages[3]).toBe('onCancelToken')\n      await expect(messages[4]).toBe('Inertia.on(start)')\n      await expect(messages[5]).toBe('addEventListener(inertia:start)')\n      await expect(messages[6]).toBe('onStart')\n      await expect(messages[7]).toBe('Inertia.on(progress)')\n      await expect(messages[8]).toBe('addEventListener(inertia:progress)')\n      await expect(messages[9]).toBe('onProgress')\n      await expect(messages[10]).toBe('CANCELLING!')\n      await expect(messages[11]).toBe('onCancel')\n      await expect(messages[12]).toBe('Inertia.on(finish)')\n      await expect(messages[13]).toBe('addEventListener(inertia:finish)')\n      await expect(messages[14]).toBe('onFinish')\n    })\n\n    test('prevents onCancel from firing when the request is already finished', async ({ page }) => {\n      await page.getByRole('link', { exact: true, name: 'Lifecycle Cancel - After Finish' }).click()\n\n      const messages = await waitForMessages(page, 17)\n\n      await expect(messages[0]).toBe('onBefore')\n      await expect(messages[1]).toBe('Inertia.on(before)')\n      await expect(messages[2]).toBe('addEventListener(inertia:before)')\n      await expect(messages[3]).toBe('onCancelToken')\n      await expect(messages[4]).toBe('Inertia.on(start)')\n      await expect(messages[5]).toBe('addEventListener(inertia:start)')\n      await expect(messages[6]).toBe('onStart')\n      await expect(messages[7]).toBe('Inertia.on(progress)')\n      await expect(messages[8]).toBe('addEventListener(inertia:progress)')\n      await expect(messages[9]).toBe('onProgress')\n      await expect(messages[10]).toBe('Inertia.on(success)')\n      await expect(messages[11]).toBe('addEventListener(inertia:success)')\n      await expect(messages[12]).toBe('onSuccess')\n      await expect(messages[13]).toBe('Inertia.on(finish)')\n      await expect(messages[14]).toBe('addEventListener(inertia:finish)')\n      await expect(messages[15]).toBe('onFinish')\n      await expect(messages[16]).toBe('CANCELLING!')\n    })\n  })\n})\n"
  },
  {
    "path": "tests/flash.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport { gotoPageAndWaitForContent, requests } from './support'\n\nconst waitForMessages = async (page, count?: number): Promise<any[]> => {\n  if (typeof count === 'number') {\n    await page.waitForFunction((count) => (window as any).messages.length === count, count)\n  }\n\n  return await page.evaluate(() => (window as any).messages)\n}\n\ntest.describe('Flash Data', () => {\n  test('displays flash data from initial page load', async ({ page }) => {\n    await page.goto('/flash/initial')\n    await expect(page.locator('#flash')).toContainText('Hello from server')\n  })\n\n  test('fires flash event on initial page load for global listeners', async ({ page }) => {\n    await page.goto('/flash/initial')\n    await expect(page.locator('#flash-events')).toContainText('Hello from server')\n  })\n\n  test('preserves flash data after deferred props load and does not fire event again', async ({ page }) => {\n    // Set up response listener before navigating to catch the deferred request\n    const deferredResponse = page.waitForResponse((res) => res.url().includes('/flash/with-deferred'))\n\n    await gotoPageAndWaitForContent(page, '/flash/with-deferred')\n\n    await expect(page.locator('#flash')).toContainText('Flash with deferred')\n    await expect(page.locator('#flash-event-count')).toHaveText('1')\n\n    // Wait for deferred data to load (may already be loaded in fast CI environments)\n    await deferredResponse\n\n    await expect(page.locator('#loading')).not.toBeVisible()\n    await expect(page.locator('#data')).toContainText('Deferred data loaded')\n    await expect(page.locator('#flash')).toContainText('Flash with deferred')\n    await expect(page.locator('#flash-event-count')).toHaveText('1')\n  })\n\n  test('preserves flash data and fires event when page has InfiniteScroll', async ({ page }) => {\n    await page.goto('/')\n\n    await page.evaluate(() => window.testing.Inertia.visit('/flash/with-infinite-scroll'))\n    await page.waitForURL('**/flash/with-infinite-scroll')\n\n    await expect(page.locator('#flash')).toContainText('Flash with infinite scroll')\n    await expect(page.locator('#flash-event-count')).toHaveText('1')\n  })\n\n  test('fires flash event on partial request even when flash is unchanged', async ({ page }) => {\n    await page.goto('/flash/partial')\n\n    await expect(page.locator('#flash')).toContainText('Initial flash')\n    await expect(page.locator('#flash-event-count')).toHaveText('1')\n\n    const initialCount = await page.locator('#count').textContent()\n    const responsePromise = page.waitForResponse((res) => res.url().includes('/flash/partial'))\n    await page.getByRole('button', { name: 'Reload with same flash' }).click()\n    await responsePromise\n\n    await expect(page.locator('#count')).not.toHaveText(initialCount!)\n    await expect(page.locator('#flash')).toContainText('Initial flash')\n    await expect(page.locator('#flash-event-count')).toHaveText('2')\n  })\n\n  test('fires flash event on partial request when flash changes', async ({ page }) => {\n    await page.goto('/flash/partial')\n\n    await expect(page.locator('#flash')).toContainText('Initial flash')\n    await expect(page.locator('#flash-event-count')).toHaveText('1')\n\n    const responsePromise = page.waitForResponse((res) => res.url().includes('/flash/partial'))\n    await page.getByRole('button', { name: 'Reload with different flash' }).click()\n    await responsePromise\n\n    await expect(page.locator('#flash')).toContainText('Updated flash')\n    await expect(page.locator('#flash-event-count')).toHaveText('2')\n  })\n\n  test.describe('Requests', () => {\n    test.beforeEach(async ({ page }) => {\n      await page.goto('/flash/events')\n    })\n\n    test('receives flash data and fires event callbacks', async ({ page }) => {\n      await page.getByRole('link', { name: 'Visit with flash' }).click()\n\n      const messages = await waitForMessages(page, 8)\n\n      expect(messages).toEqual([\n        'Inertia.on(flash)',\n        { foo: 'bar' },\n        'addEventListener(inertia:flash)',\n        { foo: 'bar' },\n        'onFlash',\n        { foo: 'bar' },\n        'onSuccess',\n        { foo: 'bar' },\n      ])\n    })\n\n    test('flash data is not persisted in browser history', async ({ page }) => {\n      await page.getByRole('link', { name: 'Visit with flash' }).click()\n      await waitForMessages(page, 8)\n\n      const flashBefore = await page.locator('#flash').textContent()\n      expect(flashBefore).toContain('foo')\n\n      await page.getByRole('link', { name: 'Navigate away' }).click()\n      await page.waitForURL('/')\n\n      await page.goBack()\n      expect(page.url()).toContain('/flash/events')\n\n      const flashAfter = await page.locator('#flash').textContent()\n      expect(flashAfter).toBe('{}')\n    })\n\n    test('does not fire flash event when no flash data is present', async ({ page }) => {\n      await page.getByRole('link', { name: 'Visit without flash' }).click()\n\n      const messages = await waitForMessages(page, 1)\n\n      expect(messages).toEqual(['onSuccess'])\n    })\n  })\n\n  test.describe('Client-side visits', () => {\n    test.beforeEach(async ({ page }) => {\n      await page.goto('/flash/client-side-visits')\n    })\n\n    test('sets flash data and fires onFlash callback', async ({ page }) => {\n      requests.listen(page)\n\n      await expect(page.locator('#flash')).toHaveText('{}')\n\n      await page.getByRole('button', { name: 'With flash object' }).click()\n\n      await expect(page.locator('#flash')).toContainText('foo')\n      expect(await page.evaluate(() => window.flashCount)).toBe(1)\n      expect(requests.requests.length).toBe(0)\n    })\n\n    test('merges flash data using function', async ({ page }) => {\n      requests.listen(page)\n\n      await page.getByRole('button', { name: 'With flash object' }).click()\n      await expect(page.locator('#flash')).toContainText('foo')\n\n      await page.getByRole('button', { name: 'With flash function' }).click()\n\n      const flashText = await page.locator('#flash').textContent()\n      expect(flashText).toContain('foo')\n      expect(flashText).toContain('bar')\n      expect(flashText).toContain('baz')\n      expect(await page.evaluate(() => window.flashCount)).toBe(2)\n      expect(requests.requests.length).toBe(0)\n    })\n\n    test('flash data does not carry over to next client-side visit', async ({ page }) => {\n      requests.listen(page)\n\n      await page.getByRole('button', { name: 'With flash object' }).click()\n      await expect(page.locator('#flash')).toContainText('foo')\n\n      await page.getByRole('button', { name: 'Without flash' }).click()\n\n      await expect(page.locator('#flash')).toHaveText('{}')\n      expect(await page.evaluate(() => window.flashCount)).toBe(1)\n      expect(requests.requests.length).toBe(0)\n    })\n  })\n\n  test.describe('router.flash()', () => {\n    test.beforeEach(async ({ page }) => {\n      await page.goto('/flash/router-flash')\n    })\n\n    test('sets flash data with object', async ({ page }) => {\n      requests.listen(page)\n\n      await expect(page.locator('#flash')).toHaveText('{}')\n\n      await page.getByRole('button', { name: 'Set flash', exact: true }).click()\n\n      await expect(page.locator('#flash')).toContainText('foo')\n      expect(requests.requests.length).toBe(0)\n    })\n\n    test('sets flash data with key-value pair', async ({ page }) => {\n      requests.listen(page)\n\n      await expect(page.locator('#flash')).toHaveText('{}')\n\n      await page.getByRole('button', { name: 'Set flash key-value' }).click()\n\n      await expect(page.locator('#flash')).toContainText('foo')\n      await expect(page.locator('#flash')).toContainText('bar')\n      expect(requests.requests.length).toBe(0)\n    })\n\n    test('merges flash data using function', async ({ page }) => {\n      requests.listen(page)\n\n      await page.getByRole('button', { name: 'Set flash', exact: true }).click()\n      await expect(page.locator('#flash')).toContainText('foo')\n\n      await page.getByRole('button', { name: 'Merge flash' }).click()\n\n      const flashText = await page.locator('#flash').textContent()\n      expect(flashText).toContain('foo')\n      expect(flashText).toContain('bar')\n      expect(flashText).toContain('baz')\n      expect(requests.requests.length).toBe(0)\n    })\n\n    test('clears flash data using function', async ({ page }) => {\n      requests.listen(page)\n\n      await page.getByRole('button', { name: 'Set flash', exact: true }).click()\n      await expect(page.locator('#flash')).toContainText('foo')\n\n      await page.getByRole('button', { name: 'Clear flash' }).click()\n\n      await expect(page.locator('#flash')).toHaveText('{}')\n      expect(requests.requests.length).toBe(0)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/form-component-context.spec.ts",
    "content": "import test, { expect } from '@playwright/test'\nimport { pageLoads } from './support'\n\ntest.describe('Form Component Context', () => {\n  test.describe('Basic Context', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/form-component/context/default')\n    })\n\n    test('it provides context to child and deeply nested components', async ({ page }) => {\n      await expect(page.getByText('Child: Form is clean')).toBeVisible()\n      await expect(page.getByText('Deeply Nested: Form is clean')).toBeVisible()\n    })\n\n    test('it returns undefined outside Form component', async ({ page }) => {\n      await expect(page.getByText('Correctly returns undefined when used outside a Form component')).toBeVisible()\n    })\n\n    test('it syncs state between parent and child', async ({ page }) => {\n      await expect(page.getByText('Parent: Form is clean')).toBeVisible()\n      await expect(page.getByText('Child: Form is clean')).toBeVisible()\n\n      await page.locator('input[name=\"name\"]').fill('Jane Doe')\n      await expect(page.getByText('Parent: Form is dirty')).toBeVisible()\n      await expect(page.getByText('Child: Form is dirty')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Set Error' }).click()\n      await expect(page.getByText('Error set from child component')).toHaveCount(2)\n      await expect(page.getByText('Parent: Form has errors')).toBeVisible()\n      await expect(page.getByText('Child: Form has errors')).toBeVisible()\n    })\n\n    test('it can call form methods from child component', async ({ page }) => {\n      await page.locator('input[name=\"name\"]').fill('Changed Name')\n      await expect(page.getByText('Child: Form is dirty')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Reset from Child' }).click()\n      await expect(page.locator('input[name=\"name\"]')).toHaveValue('John Doe')\n      await expect(page.getByText('Child: Form is clean')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Set Error' }).click()\n      await expect(page.getByText('Error set from child component').first()).toBeVisible()\n\n      await page.getByRole('button', { name: 'Clear Error' }).click()\n      await expect(page.getByText('Error set from child component')).not.toBeVisible()\n\n      await page.locator('input[name=\"name\"]').fill('New Default')\n      await page.getByRole('button', { name: 'Set Defaults' }).click()\n      await expect(page.getByText('Child: Form is clean')).toBeVisible()\n\n      await page.locator('input[name=\"name\"]').fill('Something else')\n      await page.getByRole('button', { name: 'Reset from Child' }).click()\n      await expect(page.locator('input[name=\"name\"]')).toHaveValue('New Default')\n\n      await page.getByRole('button', { name: 'Submit from Child' }).click()\n      await page.waitForURL('/dump/post')\n    })\n  })\n\n  test.describe('Context Methods', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/form-component/context/methods')\n    })\n\n    test('it can reset fields from child', async ({ page }) => {\n      await page.locator('input[name=\"name\"]').fill('Changed')\n      await page.locator('input[name=\"email\"]').fill('changed@example.com')\n      await page.locator('textarea[name=\"bio\"]').fill('Changed bio')\n\n      await page.getByRole('button', { name: 'reset()', exact: true }).click()\n      await expect(page.locator('input[name=\"name\"]')).toHaveValue('Initial Name')\n      await expect(page.locator('input[name=\"email\"]')).toHaveValue('initial@example.com')\n      await expect(page.locator('textarea[name=\"bio\"]')).toHaveValue('Initial bio')\n\n      await page.locator('input[name=\"name\"]').fill('Changed')\n      await page.locator('input[name=\"email\"]').fill('changed@example.com')\n      await page.getByRole('button', { name: \"reset('name')\", exact: true }).click()\n      await expect(page.locator('input[name=\"name\"]')).toHaveValue('Initial Name')\n      await expect(page.locator('input[name=\"email\"]')).toHaveValue('changed@example.com')\n\n      await page.locator('input[name=\"name\"]').fill('Changed')\n      await page.locator('textarea[name=\"bio\"]').fill('Changed bio')\n      await page.getByRole('button', { name: \"reset('name', 'email')\" }).click()\n      await expect(page.locator('input[name=\"name\"]')).toHaveValue('Initial Name')\n      await expect(page.locator('input[name=\"email\"]')).toHaveValue('initial@example.com')\n      await expect(page.locator('textarea[name=\"bio\"]')).toHaveValue('Changed bio')\n    })\n\n    test('it can manage errors from child', async ({ page }) => {\n      await page.getByRole('button', { name: \"setError('name')\" }).click()\n      await expect(page.getByText('Name is invalid').first()).toBeVisible()\n\n      await page.getByRole('button', { name: \"clearErrors('name')\", exact: true }).click()\n      await expect(page.getByText('Name is invalid')).not.toBeVisible()\n\n      await page.getByRole('button', { name: 'setError({...})' }).click()\n      await expect(page.getByText('Name error from child').first()).toBeVisible()\n      await expect(page.getByText('Email error from child').first()).toBeVisible()\n      await expect(page.getByText('Bio error from child').first()).toBeVisible()\n\n      await page.getByRole('button', { name: 'clearErrors()', exact: true }).click()\n      await expect(page.getByText('Name error from child')).not.toBeVisible()\n      await expect(page.getByText('Email error from child')).not.toBeVisible()\n    })\n\n    test('it can reset and clear errors together from child', async ({ page }) => {\n      await page.locator('input[name=\"name\"]').fill('Changed')\n      await page.locator('input[name=\"email\"]').fill('changed@example.com')\n      await page.getByRole('button', { name: 'setError({...})' }).click()\n\n      await page.getByRole('button', { name: \"resetAndClearErrors('name')\" }).click()\n      await expect(page.locator('input[name=\"name\"]')).toHaveValue('Initial Name')\n      await expect(page.getByText('Name error from child')).not.toBeVisible()\n      await expect(page.locator('input[name=\"email\"]')).toHaveValue('changed@example.com')\n      await expect(page.getByText('Email error from child').first()).toBeVisible()\n\n      await page.getByRole('button', { name: 'resetAndClearErrors()', exact: true }).click()\n      await expect(page.locator('input[name=\"email\"]')).toHaveValue('initial@example.com')\n      await expect(page.getByText('Email error from child')).not.toBeVisible()\n    })\n\n    test('it can access data methods from child', async ({ page }) => {\n      await page.locator('input[name=\"name\"]').fill('Test Name')\n      await page.locator('input[name=\"email\"]').fill('test@example.com')\n\n      await page.getByRole('button', { name: 'getData()' }).click()\n      await expect(page.locator('#get-data-result')).toContainText('Test Name')\n      await expect(page.locator('#get-data-result')).toContainText('test@example.com')\n\n      await page.getByRole('button', { name: 'getFormData()' }).click()\n      await expect(page.locator('#get-form-data-result')).toContainText('Test Name')\n    })\n\n    test('it exposes success states through context', async ({ page }) => {\n      await expect(page.getByText('Child: was successful')).not.toBeVisible()\n      await expect(page.getByText('Child: recently successful')).not.toBeVisible()\n\n      await page.getByRole('button', { name: 'submit()' }).click()\n\n      await expect(page.getByText('Child: was successful')).toBeVisible()\n      await expect(page.getByText('Child: recently successful')).toBeVisible()\n\n      await page.waitForTimeout(2100)\n      await expect(page.getByText('Child: was successful')).toBeVisible()\n      await expect(page.getByText('Child: recently successful')).not.toBeVisible()\n    })\n  })\n\n  test.describe('Multiple Forms', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/form-component/context/multiple')\n    })\n\n    test('it provides isolated context to each form', async ({ page }) => {\n      await expect(page.getByText('Child: Form is clean').first()).toBeVisible()\n      await expect(page.getByText('Child: Form is clean').nth(1)).toBeVisible()\n\n      await page.locator('input[name=\"name\"]').first().fill('Changed')\n      await expect(page.getByText('Form 1 Parent: dirty')).toBeVisible()\n      await expect(page.getByText('Form 2 Parent: clean')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Set Error' }).first().click()\n      await expect(page.getByText('Error: Error from child')).toHaveCount(2)\n\n      await page.getByRole('button', { name: 'Set Error' }).nth(1).click()\n      await expect(page.getByText('Error: Error from child')).toHaveCount(4)\n\n      await page.getByRole('button', { name: 'Clear Error' }).first().click()\n      await expect(page.getByText('Error: Error from child')).toHaveCount(2)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/form-component.spec.ts",
    "content": "import test, { expect, Page } from '@playwright/test'\nimport { consoleMessages, pageLoads, requests, scrollElementTo, shouldBeDumpPage } from './support'\n\ntest.describe('Form Component', () => {\n  test.describe('Elements', () => {\n    test.beforeEach(async ({ page }) => {\n      await page.goto('/form-component/elements')\n    })\n\n    test('can submit the form with the default values', async ({ page }) => {\n      await page.getByRole('button', { name: 'Submit' }).click()\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      await expect(dump.method).toEqual('post')\n      await expect(dump.files).toEqual({})\n      await expect(dump.query).toEqual({})\n      await expect(dump.form).toEqual({\n        name: '',\n        country: 'uk',\n        bio: '',\n        token: 'abc123',\n        age: '',\n        user: { address: { street: '' } },\n        items: [{ name: 'Item A' }, { name: 'Item B' }],\n      })\n    })\n\n    const queryStringArrayFormats = ['brackets', 'indices', 'force-brackets']\n\n    queryStringArrayFormats.forEach((format) => {\n      test('can submit the form with filled values using ' + format + ' format', async ({ page }) => {\n        test.setTimeout(10_000)\n\n        await page.goto('/form-component/elements?queryStringArrayFormat=' + format)\n        await expect(page.locator('#name')).toBeVisible()\n\n        await page.fill('#name', 'Joe')\n        await page.selectOption('#country', 'us')\n        await page.selectOption('#role', 'User')\n        await page.check('input[name=\"plan\"][value=\"pro\"]')\n        await page.check('#subscribe')\n        await page.check('input[name=\"interests[]\"][value=\"sports\"]')\n        await page.check('input[name=\"interests[]\"][value=\"music\"]')\n        await page.selectOption('#skills', ['vue', 'react'])\n        await page.setInputFiles('#avatar', {\n          name: 'avatar.jpg',\n          mimeType: 'image/jpeg',\n          buffer: Buffer.from('fake image data'),\n        })\n        await page.setInputFiles('#documents', [\n          { name: 'doc1.pdf', mimeType: 'application/pdf', buffer: Buffer.from('fake pdf data 1') },\n          { name: 'doc2.pdf', mimeType: 'application/pdf', buffer: Buffer.from('fake pdf data 2') },\n        ])\n        await page.fill('#bio', 'This is a bio.')\n        await page.fill('#age', '30')\n        await page.fill('#nested_street', '123 Main St')\n        await page.fill('#item_a', 'Item 1')\n        await page.fill('#item_b', 'Item 2')\n\n        await page.getByRole('button', { name: 'Submit' }).click()\n        const dump = await shouldBeDumpPage(page, 'post')\n\n        await expect(dump.method).toEqual('post')\n        await expect(dump.query).toEqual({})\n        await expect(dump.files).toEqual([\n          {\n            fieldname: 'avatar',\n            originalname: 'avatar.jpg',\n            mimetype: 'image/jpeg',\n            buffer: { type: 'Buffer', data: expect.any(Array) },\n            encoding: '7bit',\n            size: 15,\n          },\n          {\n            fieldname: format === 'force-brackets' ? 'documents[]' : 'documents[0]',\n            originalname: 'doc1.pdf',\n            mimetype: 'application/pdf',\n            buffer: { type: 'Buffer', data: expect.any(Array) },\n            encoding: '7bit',\n            size: 15,\n          },\n          {\n            fieldname: format === 'force-brackets' ? 'documents[]' : 'documents[1]',\n            originalname: 'doc2.pdf',\n            mimetype: 'application/pdf',\n            buffer: { type: 'Buffer', data: expect.any(Array) },\n            encoding: '7bit',\n            size: 15,\n          },\n        ])\n\n        await expect(dump.form).toEqual({\n          name: 'Joe',\n          country: 'us',\n          role: 'User',\n          plan: 'pro',\n          subscribe: 'yes',\n          interests: ['sports', 'music'],\n          skills: ['vue', 'react'],\n          bio: 'This is a bio.',\n          token: 'abc123',\n          age: '30',\n          user: { address: { street: '123 Main St' } },\n          ...(format === 'force-brackets'\n            ? { 'items[][name]': ['Item 1', 'Item 2'] }\n            : { items: [{ name: 'Item 1' }, { name: 'Item 2' }] }),\n        })\n      })\n    })\n\n    test('can check if the form is dirty', async ({ page }) => {\n      await expect(page.getByText('Form is clean')).toBeVisible()\n      await page.fill('#name', 'Joe')\n      await expect(page.locator('#name')).toHaveValue('Joe')\n      await expect(page.getByText('Form is dirty')).toBeVisible()\n      await page.getByRole('button', { name: 'Reset' }).click()\n      await expect(page.getByText('Form is clean')).toBeVisible()\n      await expect(page.locator('#name')).toHaveValue('')\n    })\n  })\n\n  test.describe('Headers', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/form-component/headers')\n    })\n\n    test('can submit the form and send default headers', async ({ page }) => {\n      await page.getByRole('button', { name: 'Submit' }).click()\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      await expect(dump.method).toEqual('post')\n      await expect(dump.headers).toMatchObject({\n        'x-foo': 'Bar',\n      })\n    })\n\n    test('can submit the form and override headers via props', async ({ page }) => {\n      await page.getByRole('button', { name: 'Add Custom Header' }).click()\n      await page.getByRole('button', { name: 'Submit' }).click()\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      await expect(dump.method).toEqual('post')\n      await expect(dump.headers).toMatchObject({\n        'x-foo': 'Bar',\n        'x-custom': 'MyCustomValue',\n      })\n    })\n  })\n\n  test.describe('Errors', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/form-component/errors')\n    })\n\n    test('shows no errors by default', async ({ page }) => {\n      await expect(page.getByText('Form has errors')).not.toBeVisible()\n      await expect(page.locator('#error_name')).toHaveText('')\n      await expect(page.locator('#error_handle')).toHaveText('')\n    })\n\n    test('can set errors manually', async ({ page }) => {\n      await page.getByRole('button', { name: 'Set Errors' }).click()\n\n      await expect(page.getByText('Form has errors')).toBeVisible()\n      await expect(page.locator('#error_name')).toHaveText('The name field is required.')\n      await expect(page.locator('#error_handle')).toHaveText('The handle field is invalid.')\n    })\n\n    test('can clear all errors', async ({ page }) => {\n      await page.getByRole('button', { name: 'Set Errors' }).click()\n      await expect(page.getByText('Form has errors')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Clear Errors' }).click()\n\n      await expect(page.getByText('Form has errors')).not.toBeVisible()\n      await expect(page.locator('#error_name')).toHaveText('')\n      await expect(page.locator('#error_handle')).toHaveText('')\n    })\n\n    test('can clear a specific error', async ({ page }) => {\n      await page.getByRole('button', { name: 'Set Errors' }).click()\n      await expect(page.getByText('Form has errors')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Clear Name Error' }).click()\n\n      await expect(page.locator('#error_name')).toHaveText('')\n      await expect(page.locator('#error_handle')).toHaveText('The handle field is invalid.')\n      await expect(page.getByText('Form has errors')).toBeVisible()\n    })\n\n    test('shows server-side errors when submitting the form', async ({ page }) => {\n      await page.fill('#name', 'Some Name')\n      await page.fill('#handle', 'Invalid Handle')\n\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await expect(page.getByText('Form has errors')).toBeVisible()\n      await expect(page.locator('#error_name')).toHaveText('Some name error')\n      await expect(page.locator('#error_handle')).toHaveText('The Handle was invalid')\n    })\n\n    test('shows server-side errors when submitting the form with an error bag', async ({ page }) => {\n      await page.fill('#name', 'Some Name')\n      await page.fill('#handle', 'Invalid Handle')\n\n      await page.getByRole('button', { name: 'Use Error Bag' }).click()\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await expect(page.getByText('Form has errors')).toBeVisible()\n      await expect(page.locator('#error_name')).toHaveText('Some name error')\n      await expect(page.locator('#error_handle')).toHaveText('The Handle was invalid')\n    })\n\n    test('keep the initial value on errors', async ({ page }) => {\n      pageLoads.watch(page, 2)\n\n      await page.goto('/form-component/default-value')\n\n      await expect(page.locator('#name')).toHaveValue('John Doe')\n      await page.fill('#name', 'Jane Doe')\n\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await expect(page.locator('#error_name')).toHaveText('The name must be at least 10 characters.')\n      await expect(page.locator('#name')).toHaveValue('Jane Doe')\n\n      await page.fill('#name', 'Jonathan Doe')\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await page.waitForURL('/')\n    })\n  })\n\n  test.describe('Reset Attributes', () => {\n    test('resetOnError resets fields after error', async ({ page }) => {\n      await page.goto('/form-component/reset-on-error')\n\n      await page.fill('#name', 'Changed Name')\n      await page.fill('#email', 'changed@email.com')\n\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await expect(page.locator('#error_name')).toHaveText('Some name error')\n\n      await expect(page.locator('#name')).toHaveValue('John Doe')\n      await expect(page.locator('#email')).toHaveValue('john@doe.biz')\n    })\n\n    test('resetOnError with specific fields only resets those fields', async ({ page }) => {\n      await page.goto('/form-component/reset-on-error-fields')\n\n      await page.fill('#name', 'Changed Name')\n      await page.fill('#email', 'changed@email.com')\n\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await expect(page.locator('#error_name')).toHaveText('Some name error')\n\n      await expect(page.locator('#name')).toHaveValue('John Doe')\n      await expect(page.locator('#email')).toHaveValue('changed@email.com')\n    })\n\n    test('resetOnSuccess resets fields after success', async ({ page }) => {\n      await page.goto('/form-component/reset-on-success')\n\n      await page.fill('#name', 'Changed Name')\n      await page.fill('#email', 'changed@email.com')\n\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await expect(page.locator('#name')).toHaveValue('John Doe')\n      await expect(page.locator('#email')).toHaveValue('john@doe.biz')\n    })\n\n    test('resetOnSuccess with specific fields only resets those fields', async ({ page }) => {\n      await page.goto('/form-component/reset-on-success-fields')\n\n      await page.fill('#name', 'Changed Name')\n      await page.fill('#email', 'changed@email.com')\n\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await expect(page.locator('#name')).toHaveValue('John Doe')\n      await expect(page.locator('#email')).toHaveValue('changed@email.com')\n    })\n  })\n\n  test.describe('Set Defaults Attributes', () => {\n    test('setDefaultsOnSuccess updates defaults and clears dirty state', async ({ page }) => {\n      await page.goto('/form-component/set-defaults-on-success')\n\n      await expect(page.locator('#dirty-status')).toHaveText('Form is clean')\n      await page.fill('#name', 'Jane Smith')\n      await page.fill('#email', 'jane@smith.com')\n      await expect(page.locator('#dirty-status')).toHaveText('Form is dirty')\n\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await expect(page.locator('#name')).toHaveValue('Jane Smith')\n      await expect(page.locator('#email')).toHaveValue('jane@smith.com')\n      await expect(page.locator('#dirty-status')).toHaveText('Form is clean')\n    })\n  })\n\n  test.describe('Events and State', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/form-component/events')\n    })\n\n    const waitForEvents = async (page: Page, events: string[]) => {\n      await page.waitForFunction(async (expected) => {\n        return document.querySelector('#events')?.innerText === expected\n      }, events.join(','))\n    }\n\n    test('fires events in order on success', async ({ page }) => {\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await waitForEvents(page, ['onBefore', 'onCancelToken', 'onStart', 'onSuccess', 'onFinish'])\n    })\n\n    test('fires events in order on error', async ({ page }) => {\n      await page.getByRole('button', { name: 'Fail Request' }).click()\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await waitForEvents(page, ['onBefore', 'onCancelToken', 'onStart', 'onError', 'onFinish'])\n    })\n\n    test('fires only onBefore and onCancel when canceled via event cancellation', async ({ page }) => {\n      await page.getByRole('button', { name: 'Cancel in onBefore' }).click()\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await waitForEvents(page, ['onBefore', 'onCancel'])\n    })\n\n    test('fires onCancelToken and cancels the request via the token', async ({ page }) => {\n      await page.getByRole('button', { name: 'Should Delay' }).click()\n      await page.getByRole('button', { name: 'Submit' }).click()\n      await page.getByRole('button', { name: 'Cancel Visit' }).click()\n\n      await waitForEvents(page, ['onBefore', 'onCancelToken', 'onStart', 'onCancel', 'onFinish'])\n    })\n\n    test('fires onProgress during file upload', async ({ page }) => {\n      const file = {\n        name: 'test.jpg',\n        mimeType: 'image/jpeg',\n        buffer: Buffer.from('fake image data'),\n      }\n\n      await page.setInputFiles('#avatar', file)\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await waitForEvents(page, ['onBefore', 'onCancelToken', 'onStart', 'onProgress'])\n    })\n\n    test('updates processing during request', async ({ page }) => {\n      await page.getByRole('button', { name: 'Should Delay' }).click()\n      await expect(page.locator('#processing')).toHaveText('false')\n      await page.getByRole('button', { name: 'Submit' }).click()\n      await expect(page.locator('#processing')).toHaveText('true')\n      await page.waitForSelector('#processing:has-text(\"false\")')\n    })\n\n    test('shows progress during file upload', async ({ page }) => {\n      const file = {\n        name: 'test.jpg',\n        mimeType: 'image/jpeg',\n        buffer: Buffer.from('fake image data'),\n      }\n\n      await page.getByRole('button', { name: 'Should Delay' }).click()\n      await page.setInputFiles('#avatar', file)\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      // Wait for #progress not being 0\n      await page.waitForSelector('#progress.uploading')\n\n      const percentage = parseInt(await page.locator('#progress').innerText())\n      expect(percentage).toBeLessThanOrEqual(100)\n    })\n\n    test('updates wasSuccessful and recentlySuccessful after success', async ({ page }) => {\n      test.setTimeout(7_500)\n\n      await expect(page.locator('#was-successful')).toHaveText('false')\n      await expect(page.locator('#recently-successful')).toHaveText('false')\n\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await expect(page.locator('#was-successful')).toHaveText('true')\n      await expect(page.locator('#recently-successful')).toHaveText('true')\n      await expect(page.locator('#recently-successful')).toHaveText('false')\n    })\n  })\n\n  test.describe('Form Options', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/form-component/options')\n    })\n\n    test('submits the form and requests only the users prop', async ({ page }) => {\n      await page.getByRole('button', { name: 'Set Only (users)' }).click()\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      expect(dump.headers).toMatchObject({\n        'x-inertia-partial-data': 'users',\n        'x-inertia-partial-component': 'FormComponent/Options',\n      })\n    })\n\n    test('submits the form and excludes the stats prop from the response', async ({ page }) => {\n      await page.getByRole('button', { name: 'Set Except (stats)' }).click()\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      expect(dump.headers).toMatchObject({\n        'x-inertia-partial-except': 'stats',\n        'x-inertia-partial-component': 'FormComponent/Options',\n      })\n    })\n\n    test('submits the form and resets the orders prop from the response', async ({ page }) => {\n      await page.getByRole('button', { name: 'Set Reset (orders)' }).click()\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      expect(dump.headers).toMatchObject({\n        'x-inertia-partial-data': 'orders',\n        'x-inertia-partial-component': 'FormComponent/Options',\n        'x-inertia-reset': 'orders',\n      })\n    })\n\n    test('submits the form and encodes arrays using brackets format', async ({ page }) => {\n      await page.getByRole('button', { name: 'Use Brackets Format' }).click()\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'get')\n\n      expect(dump.url).toEqual(expect.stringContaining('/dump/get?tags[]=alpha&tags[]=beta'))\n    })\n\n    test('submits the form and encodes arrays using indices format', async ({ page }) => {\n      await page.getByRole('button', { name: 'Use Indices Format' }).click()\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'get')\n\n      expect(dump.url).toEqual(expect.stringContaining('/dump/get?tags[0]=alpha&tags[1]=beta'))\n    })\n\n    test('preserves the scroll position when preserveScroll is enabled', async ({ page }) => {\n      await page.getByRole('button', { name: 'Enable Preserve Scroll' }).click()\n      await scrollElementTo(\n        page,\n        page.evaluate(() => window.scrollTo(0, 100)),\n      )\n\n      const scrollBefore = await page.evaluate(() => window.scrollY)\n      expect(scrollBefore).toBeGreaterThan(0)\n\n      await page.getByRole('button', { name: 'Submit' }).click()\n      await page.waitForURL('/article?tags[]=alpha&tags[]=beta')\n\n      const scrollAfter = await page.evaluate(() => window.scrollY)\n      // TODO: why is this not exactly 100?\n      expect(scrollAfter).toBeGreaterThan(90)\n    })\n\n    test('preserves the form state when preserveState is enabled', async ({ page }) => {\n      requests.listen(page)\n\n      await expect(requests.requests).toHaveLength(0)\n\n      expect(await page.locator('#state').innerText()).toEqual('Default State')\n      await page.getByRole('button', { name: 'Enable Preserve State' }).click()\n      expect(await page.locator('#state').innerText()).toEqual('Replaced State')\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await expect(requests.requests).toHaveLength(1)\n      expect(await page.locator('#state').innerText()).toEqual('Replaced State')\n    })\n\n    test('preserves the URL when preserveUrl is enabled', async ({ page }) => {\n      requests.listen(page)\n\n      await expect(requests.requests).toHaveLength(0)\n\n      await page.getByRole('button', { name: 'Enable Preserve Url' }).click()\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await expect(requests.requests).toHaveLength(1)\n      await expect(page).toHaveURL('form-component/options')\n    })\n\n    test('submits the form with view transitions enabled', async ({ page, browserName }) => {\n      test.skip(browserName === 'firefox', 'Firefox does not support View Transitions API in CI')\n\n      consoleMessages.listen(page)\n      pageLoads.watch(page, 2)\n\n      await page.goto('/form-component/view-transition')\n\n      await page.getByRole('button', { name: 'Submit with View Transition' }).click()\n\n      await expect(page).toHaveURL('/form-component/view-transition')\n      await expect(page.getByText('Page B - View Transition Test')).toBeVisible()\n\n      await expect.poll(() => consoleMessages.messages).toEqual(['updateCallbackDone', 'ready', 'finished'])\n    })\n  })\n\n  test.describe('Progress', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/form-component/progress')\n      requests.listen(page)\n      requests.listenForFinished(page)\n      await expect(requests.requests).toHaveLength(0)\n      await expect(page.locator('#nprogress-appearances')).toHaveText('0')\n    })\n\n    test('shows progress during a normal request', async ({ page }) => {\n      await page.getByRole('button', { name: 'Submit' }).click()\n      await expect(requests.requests).toHaveLength(1)\n      await expect(page.locator('#nprogress-appearances')).toHaveText('1')\n    })\n\n    test('does not show progress when showProgress is false', async ({ page }) => {\n      await page.getByRole('button', { name: 'Disable Progress' }).click()\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await expect.poll(() => requests.finished.length).toBe(1)\n\n      await expect(page.locator('#nprogress-appearances')).toHaveText('0')\n    })\n  })\n\n  test('replaces the browser history when replace is enabled', async ({ page }) => {\n    await page.goto('/article')\n    await page.goto('/form-component/options')\n\n    await page.getByRole('button', { name: 'Enable Replace' }).click()\n    await page.getByRole('button', { name: 'Submit' }).click()\n\n    await shouldBeDumpPage(page, 'post')\n\n    await page.goBack()\n    await expect(page).toHaveURL('/article')\n  })\n\n  test('can disable the form while processing', async ({ page }) => {\n    await page.goto('/form-component/disable-while-processing/yes')\n    await page.getByRole('button', { name: 'Submit' }).click()\n    await expect(page.locator('form[inert]')).toBeVisible()\n    await expect(page.locator('form[inert]')).not.toBeVisible()\n  })\n\n  test('will not disable the form while processing by default', async ({ page }) => {\n    await page.goto('/form-component/disable-while-processing/no')\n    await page.getByRole('button', { name: 'Submit' }).click()\n    await page.waitForTimeout(250)\n    await expect(page.locator('form[inert]')).not.toBeVisible()\n  })\n\n  test('submit without an action attribute uses the current URL', async ({ page }) => {\n    await page.goto('/form-component/url/with/segements')\n    await expect(page.locator('#error_name')).not.toBeVisible()\n\n    requests.listen(page)\n\n    await page.getByRole('button', { name: 'Submit' }).click()\n    await expect(page.locator('#error_name')).toHaveText('Something went wrong')\n\n    await expect(requests.requests).toHaveLength(1)\n    const request = requests.requests[0]\n\n    expect(request.method()).toBe('POST')\n    expect(request.url().includes('/form-component/url/with/segements')).toBe(true)\n\n    await expect(page).toHaveURL('/form-component/url/with/segements')\n  })\n\n  test.describe('OnSubmitComplete callbacks', () => {\n    test('reset', async ({ page }) => {\n      await page.goto('/form-component/submit-complete/reset')\n\n      await expect(page.locator('#name')).toHaveValue('John Doe')\n      await expect(page.locator('#email')).toHaveValue('john@doe.biz')\n\n      await page.fill('#name', 'John Who')\n      await page.fill('#email', 'john@who.biz')\n\n      requests.listen(page)\n\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await expect(requests.requests).toHaveLength(1)\n\n      await expect(page.locator('#name')).toHaveValue('John Doe')\n      await expect(page.locator('#email')).toHaveValue('john@who.biz')\n    })\n\n    test('defaults', async ({ page }) => {\n      await page.goto('/form-component/submit-complete/defaults')\n\n      await expect(page.locator('#name')).toHaveValue('John Doe')\n      await expect(page.locator('#email')).toHaveValue('john@doe.biz')\n\n      await expect(page.locator('#dirty-status')).toHaveText('Form is clean')\n\n      await page.fill('#name', 'Jane Smith')\n      await page.fill('#email', 'jane@smith.com')\n\n      await expect(page.locator('#dirty-status')).toHaveText('Form is dirty')\n\n      requests.listen(page)\n\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await expect(requests.requests).toHaveLength(1)\n\n      // After submit with defaults(), the current values should become the new defaults\n      // Values should remain changed (not reset)\n      await expect(page.locator('#name')).toHaveValue('Jane Smith')\n      await expect(page.locator('#email')).toHaveValue('jane@smith.com')\n\n      // Most importantly: form should no longer be dirty after calling defaults()\n      await expect(page.locator('#dirty-status')).toHaveText('Form is clean')\n    })\n\n    test('redirect and reset', async ({ page }) => {\n      page.on('pageerror', (msg) => {\n        throw new Error(msg.message)\n      })\n\n      await page.goto('/form-component/submit-complete/redirect')\n\n      await expect(page.locator('#name')).toHaveValue('John Doe')\n      await page.fill('#name', 'John Who')\n\n      await page.getByRole('button', { name: 'Submit' }).click()\n\n      await expect(page.locator('#name')).not.toBeVisible()\n    })\n  })\n\n  test.describe('Methods', () => {\n    test.beforeEach(async ({ page }) => {\n      await page.goto('/form-component/methods')\n    })\n\n    test('submits GET request with query parameters', async ({ page }) => {\n      await page.getByRole('button', { name: 'GET', exact: true }).click()\n      await page.getByRole('button', { name: 'Submit GET' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'get')\n\n      await expect(dump.method).toEqual('get')\n      await expect(dump.query).toEqual({\n        name: 'John Doe',\n        active: 'true',\n      })\n    })\n\n    test('submits POST request with form data', async ({ page }) => {\n      await page.getByRole('button', { name: 'POST' }).click()\n      await page.getByRole('button', { name: 'Submit POST' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      await expect(dump.method).toEqual('post')\n      await expect(dump.form).toEqual({\n        name: 'John Doe',\n        active: 'true',\n      })\n    })\n\n    test('submits PUT request with form data', async ({ page }) => {\n      await page.getByRole('button', { name: 'PUT' }).click()\n      await page.getByRole('button', { name: 'Submit PUT' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'put')\n\n      await expect(dump.method).toEqual('put')\n      await expect(dump.form).toEqual({\n        name: 'John Doe',\n        active: 'true',\n      })\n    })\n\n    test('submits PATCH request with form data', async ({ page }) => {\n      await page.getByRole('button', { name: 'PATCH' }).click()\n      await page.getByRole('button', { name: 'Submit PATCH' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'patch')\n\n      await expect(dump.method).toEqual('patch')\n      await expect(dump.form).toEqual({\n        name: 'John Doe',\n        active: 'true',\n      })\n    })\n\n    test('submits DELETE request with form data', async ({ page }) => {\n      await page.getByRole('button', { name: 'DELETE' }).click()\n      await page.getByRole('button', { name: 'Submit DELETE' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'delete')\n\n      await expect(dump.method).toEqual('delete')\n      await expect(dump.form).toEqual({\n        name: 'John Doe',\n        active: 'true',\n      })\n    })\n  })\n\n  test.describe('Transform', () => {\n    test.beforeEach(async ({ page }) => {\n      await page.goto('/form-component/transform')\n    })\n\n    test('submits data without transformation when transform is none', async ({ page }) => {\n      await page.getByRole('button', { name: 'None' }).click()\n      await page.getByRole('button', { name: 'Submit with Transform' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      await expect(dump.form).toEqual({\n        name: 'John Doe',\n        firstName: 'John',\n        lastName: 'Doe',\n      })\n    })\n\n    test('transforms data to uppercase when uppercase transform is selected', async ({ page }) => {\n      await page.getByRole('button', { name: 'Uppercase' }).click()\n      await page.getByRole('button', { name: 'Submit with Transform' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      await expect(dump.form).toEqual({\n        name: 'JOHN DOE',\n        firstName: 'John',\n        lastName: 'Doe',\n      })\n    })\n\n    test('formats data when format transform is selected', async ({ page }) => {\n      await page.getByRole('button', { name: 'Format' }).click()\n      await page.getByRole('button', { name: 'Submit with Transform' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      await expect(dump.form).toEqual({\n        name: 'John Doe',\n        firstName: 'John',\n        lastName: 'Doe',\n        fullName: 'John Doe',\n      })\n    })\n\n    test('transforms update input data correctly', async ({ page }) => {\n      await page.fill('input[name=\"name\"]', 'jane smith')\n      await page.fill('input[name=\"firstName\"]', 'jane')\n      await page.fill('input[name=\"lastName\"]', 'smith')\n      await page.getByRole('button', { name: 'Uppercase' }).click()\n      await page.getByRole('button', { name: 'Submit with Transform' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      await expect(dump.form).toEqual({\n        name: 'JANE SMITH',\n        firstName: 'jane',\n        lastName: 'smith',\n      })\n    })\n\n    test('format transform adds fullName from updated firstName and lastName', async ({ page }) => {\n      await page.fill('input[name=\"firstName\"]', 'Jane')\n      await page.fill('input[name=\"lastName\"]', 'Smith')\n      await page.getByRole('button', { name: 'Format' }).click()\n      await page.getByRole('button', { name: 'Submit with Transform' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      await expect(dump.form.fullName).toEqual('Jane Smith')\n    })\n  })\n\n  test.describe('Dotted Keys', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/form-component/dotted-keys')\n    })\n\n    test('transforms basic and nested dotted keys into nested objects', async ({ page }) => {\n      await page.fill('input[name=\"user.name\"]', 'John Doe')\n      await page.fill('input[name=\"user.profile.city\"]', 'Paris')\n      await page.locator('input[name=\"user.skills[]\"]').nth(0).fill('JavaScript')\n      await page.locator('input[name=\"user.skills[]\"]').nth(1).fill('Python')\n      await page.fill('input[name=\"company.address.street\"]', '123 Tech Ave')\n      await page.getByRole('button', { name: 'Submit Basic' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      expect(dump.method).toEqual('post')\n      expect(dump.form).toEqual({\n        user: {\n          name: 'John Doe',\n          profile: {\n            city: 'Paris',\n          },\n          skills: ['JavaScript', 'Python'],\n        },\n        company: {\n          address: {\n            street: '123 Tech Ave',\n          },\n        },\n      })\n    })\n\n    test('handles escaped dots as literal keys', async ({ page }) => {\n      await page.fill('input[name=\"config\\\\\\\\.app\\\\\\\\.name\"]', 'My App')\n      await page.fill('input[name=\"settings.theme\\\\\\\\.mode\"]', 'dark')\n      await page.getByRole('button', { name: 'Submit Escaped' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      expect(dump.method).toEqual('post')\n      expect(dump.form).toEqual({\n        'config.app.name': 'My App',\n        settings: {\n          'theme.mode': 'dark',\n        },\n      })\n    })\n\n    test('handles mixed bracket and dotted notation correctly', async ({ page }) => {\n      await page.fill('input[name=\"settings.ui.theme\"]', 'light')\n      await page.getByRole('button', { name: 'Submit Mixed' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      expect(dump.method).toEqual('post')\n      expect(dump.form).toEqual({\n        user: {\n          roles: ['admin', 'editor'],\n        },\n        settings: {\n          ui: {\n            theme: 'light',\n          },\n        },\n      })\n    })\n  })\n\n  test.describe('Ref', () => {\n    test('can submit form programmatically using ref', async ({ page }) => {\n      await page.goto('/form-component/ref')\n\n      await page.getByRole('button', { name: 'Submit Programmatically' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      expect(dump.method).toEqual('post')\n      expect(dump.form).toEqual({\n        name: 'John Doe',\n        email: 'john@example.com',\n      })\n    })\n\n    test('can access errors and hasErrors via ref', async ({ page }) => {\n      await page.goto('/form-component/ref')\n\n      await expect(page.getByText('Form has errors')).not.toBeVisible()\n      await expect(page.locator('#error_name')).not.toBeVisible()\n\n      await page.getByRole('button', { name: 'Set Test Error' }).click()\n\n      await expect(page.getByText('Form has errors')).toBeVisible()\n      await expect(page.locator('#error_name')).toHaveText('This is a test error')\n    })\n\n    test('can check isDirty state via ref', async ({ page }) => {\n      await page.goto('/form-component/ref')\n\n      await expect(page.getByText('Form is clean')).toBeVisible()\n\n      await page.fill('input[name=\"name\"]', 'Modified Name')\n\n      await expect(page.getByText('Form is dirty')).toBeVisible()\n    })\n\n    test('can reset form via ref', async ({ page }) => {\n      await page.goto('/form-component/ref')\n\n      await page.fill('input[name=\"name\"]', 'Modified Name')\n      await page.fill('input[name=\"email\"]', 'modified@example.com')\n\n      expect(await page.inputValue('input[name=\"name\"]')).toBe('Modified Name')\n      expect(await page.inputValue('input[name=\"email\"]')).toBe('modified@example.com')\n\n      await page.click('button:has-text(\"Reset Form\")')\n\n      expect(await page.inputValue('input[name=\"name\"]')).toBe('John Doe')\n      expect(await page.inputValue('input[name=\"email\"]')).toBe('john@example.com')\n    })\n\n    test('can reset particular form fields via ref', async ({ page }) => {\n      await page.goto('/form-component/ref')\n\n      await page.fill('input[name=\"name\"]', 'Modified Name')\n      await page.fill('input[name=\"email\"]', 'modified@example.com')\n\n      expect(await page.inputValue('input[name=\"name\"]')).toBe('Modified Name')\n      expect(await page.inputValue('input[name=\"email\"]')).toBe('modified@example.com')\n\n      await page.click('button:has-text(\"Reset Name Field\")')\n\n      expect(await page.inputValue('input[name=\"name\"]')).toBe('John Doe')\n      expect(await page.inputValue('input[name=\"email\"]')).toBe('modified@example.com')\n    })\n\n    test('can set current form data as defaults via ref', async ({ page, browserName }) => {\n      await page.goto('/form-component/ref')\n\n      // Modify form fields\n      await page.fill('input[name=\"name\"]', 'New Name')\n      await page.fill('input[name=\"email\"]', 'new@example.com')\n\n      // Form should be dirty\n      await expect(page.getByText('Form is dirty')).toBeVisible()\n\n      // Set current values as defaults\n      await page.click('button:has-text(\"Set Current as Defaults\")')\n\n      // Form should no longer be dirty\n      await expect(page.getByText('Form is clean')).toBeVisible()\n\n      // Reset form should now use the new defaults\n      await page.fill('input[name=\"name\"]', 'Modified Again')\n      await page.click('button:has-text(\"Reset Form\")')\n\n      expect(await page.inputValue('input[name=\"name\"]')).toBe('New Name')\n      expect(await page.inputValue('input[name=\"email\"]')).toBe('new@example.com')\n    })\n\n    test('the precognition methods are available via ref', async ({ page }) => {\n      await page.goto('/form-component/ref')\n      requests.listen(page)\n\n      await page.click('button:has-text(\"Call Precognition Methods\")')\n\n      await page.waitForTimeout(500) // Wait for request to be made\n\n      await expect(requests.requests).toHaveLength(1)\n\n      const request = requests.requests[0]\n\n      expect(request.method()).toBe('POST')\n      expect(request.headers()['precognition']).toBe('true')\n    })\n  })\n\n  test.describe('Uppercase Methods', () => {\n    test.beforeEach(async ({ page }) => {\n      await page.goto('/form-component/uppercase-method')\n    })\n\n    test('accepts uppercase POST method', async ({ page }) => {\n      await page.getByRole('button', { name: 'Submit POST' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      await expect(dump.method).toEqual('post')\n      await expect(dump.form).toEqual({\n        name: 'Test POST',\n      })\n    })\n\n    test('accepts uppercase GET method', async ({ page }) => {\n      await page.getByRole('button', { name: 'Submit GET' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'get')\n\n      await expect(dump.method).toEqual('get')\n      await expect(dump.query).toEqual({\n        query: 'Test GET',\n      })\n    })\n\n    test('accepts uppercase PUT method', async ({ page }) => {\n      await page.getByRole('button', { name: 'Submit PUT' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'put')\n\n      await expect(dump.method).toEqual('put')\n      await expect(dump.form).toEqual({\n        data: 'Test PUT',\n      })\n    })\n  })\n\n  test.describe('Reset', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/form-component/reset')\n    })\n\n    const countFiles = async (page, selector: string) => {\n      return await page.evaluate((sel) => {\n        const input = document.querySelector(sel) as HTMLInputElement\n        return input.files?.length || 0\n      }, selector)\n    }\n\n    const getSelectedOptions = async (page, selector: string) => {\n      return await page.evaluate((sel) => {\n        const select = document.querySelector(sel) as HTMLSelectElement\n        return Array.from(select.selectedOptions).map((opt) => opt.value)\n      }, selector)\n    }\n\n    const resetForm = async (page, fields?: string[]) => {\n      // @ts-ignore\n      return await page.evaluate((fields) => (fields ? window.resetForm(...fields) : window.resetForm()), fields)\n    }\n\n    test('resets all fields to their default values', async ({ page }) => {\n      // Change all field values\n      await page.fill('#name', 'Jane Smith')\n      await page.fill('#email', 'jane@test.com')\n      await page.selectOption('#country', 'us')\n      await page.selectOption('#role', 'admin')\n      await page.check('#plan_free')\n      await page.check('#payment_card')\n      await page.uncheck('#subscribe')\n      await page.check('#terms')\n      await page.uncheck('#interests_sports')\n      await page.check('#interests_music')\n      await page.uncheck('#interests_tech')\n      await page.check('#interests_art')\n      await page.selectOption('#skills', ['react', 'svelte'])\n      await page.fill('#bio', 'New bio text')\n      await page.fill('#notes', 'Some notes')\n      await page.fill('#age', '30')\n      await page.fill('#quantity', '15')\n      await page.fill('#volume', '75')\n      await page.fill('#birthdate', '2000-12-31')\n      await page.fill('#appointment', '09:00')\n      await page.fill('#favorite_color', '#00ff00')\n      await page.fill('#website', 'https://newsite.com')\n      await page.fill('#phone', '+9876543210')\n      await page.fill('#password', 'newpass456')\n      await page.fill('#nested_street', '456 Oak Ave')\n      await page.fill('#nested_city', 'Los Angeles')\n      await page.fill('#item_0_name', 'Item C')\n      await page.fill('#item_0_quantity', '20')\n      await page.fill('#item_1_name', 'Item D')\n      await page.fill('#item_1_quantity', '30')\n\n      await resetForm(page)\n\n      // Verify all fields are reset to defaults\n      await expect(page.locator('#name')).toHaveValue('John Doe')\n      await expect(page.locator('#email')).toHaveValue('john@example.com')\n      await expect(page.locator('#country')).toHaveValue('uk')\n      await expect(page.locator('#role')).toHaveValue('')\n      await expect(page.locator('#plan_pro')).toBeChecked()\n      await expect(page.locator('#plan_free')).not.toBeChecked()\n      await expect(page.locator('#payment_card')).not.toBeChecked()\n      await expect(page.locator('#payment_bank')).not.toBeChecked()\n      await expect(page.locator('#payment_paypal')).not.toBeChecked()\n      await expect(page.locator('#subscribe')).toBeChecked()\n      await expect(page.locator('#terms')).not.toBeChecked()\n      await expect(page.locator('#interests_sports')).toBeChecked()\n      await expect(page.locator('#interests_music')).not.toBeChecked()\n      await expect(page.locator('#interests_tech')).toBeChecked()\n      await expect(page.locator('#interests_art')).not.toBeChecked()\n\n      // Check multi-select (need to get selected options)\n      const selectedSkills = await getSelectedOptions(page, '#skills')\n      expect(selectedSkills).toEqual(['vue', 'angular'])\n\n      await expect(page.locator('#bio')).toHaveValue('Default bio text here.')\n      await expect(page.locator('#notes')).toHaveValue('')\n      await expect(page.locator('#age')).toHaveValue('25')\n      await expect(page.locator('#quantity')).toHaveValue('')\n      await expect(page.locator('#volume')).toHaveValue('50')\n      await expect(page.locator('#birthdate')).toHaveValue('1990-01-01')\n      await expect(page.locator('#appointment')).toHaveValue('14:30')\n      await expect(page.locator('#favorite_color')).toHaveValue('#ff0000')\n      await expect(page.locator('#website')).toHaveValue('https://example.com')\n      await expect(page.locator('#phone')).toHaveValue('+1234567890')\n      await expect(page.locator('#password')).toHaveValue('secret123')\n      await expect(page.locator('#nested_street')).toHaveValue('123 Main St')\n      await expect(page.locator('#nested_city')).toHaveValue('New York')\n      await expect(page.locator('#item_0_name')).toHaveValue('Item A')\n      await expect(page.locator('#item_0_quantity')).toHaveValue('5')\n      await expect(page.locator('#item_1_name')).toHaveValue('Item B')\n      await expect(page.locator('#item_1_quantity')).toHaveValue('10')\n      await expect(page.locator('#token')).toHaveValue('abc123')\n\n      // Verify disabled field is not affected\n      await expect(page.locator('#disabled_field')).toHaveValue('Ignore me')\n    })\n\n    test('resets specific fields only', async ({ page }) => {\n      // Change multiple field values\n      await page.fill('#name', 'Jane Smith')\n      await page.fill('#email', 'jane@test.com')\n      await page.selectOption('#country', 'us')\n      await page.fill('#bio', 'New bio')\n      await page.fill('#age', '30')\n\n      // Reset only name and bio\n      await resetForm(page, ['name', 'bio'])\n\n      // Verify only specified fields are reset\n      await expect(page.locator('#name')).toHaveValue('John Doe')\n      await expect(page.locator('#bio')).toHaveValue('Default bio text here.')\n\n      // Verify other fields are not reset\n      await expect(page.locator('#email')).toHaveValue('jane@test.com')\n      await expect(page.locator('#country')).toHaveValue('us')\n      await expect(page.locator('#age')).toHaveValue('30')\n    })\n\n    test('resets file inputs to empty', async ({ page }) => {\n      // Add files to file inputs\n      await page.setInputFiles('#avatar', {\n        name: 'avatar.jpg',\n        mimeType: 'image/jpeg',\n        buffer: Buffer.from('fake image data'),\n      })\n\n      await page.setInputFiles('#documents', [\n        { name: 'doc1.pdf', mimeType: 'application/pdf', buffer: Buffer.from('fake pdf data 1') },\n        { name: 'doc2.pdf', mimeType: 'application/pdf', buffer: Buffer.from('fake pdf data 2') },\n      ])\n\n      // Verify files are set\n      expect(await countFiles(page, '#avatar')).toBe(1)\n      expect(await countFiles(page, '#documents')).toBe(2)\n\n      await resetForm(page)\n\n      // Verify file inputs are cleared\n      expect(await countFiles(page, '#avatar')).toBe(0)\n      expect(await countFiles(page, '#documents')).toBe(0)\n    })\n\n    test('does not affect button inputs', async ({ page }) => {\n      // Get initial button values\n      const buttonValue = await page.locator('input[name=\"button_input\"]').inputValue()\n      const submitValue = await page.locator('input[name=\"submit_input\"]').inputValue()\n      const resetValue = await page.locator('input[name=\"reset_input\"]').inputValue()\n\n      await resetForm(page)\n\n      // Verify button values are unchanged\n      await expect(page.locator('input[name=\"button_input\"]')).toHaveValue(buttonValue)\n      await expect(page.locator('input[name=\"submit_input\"]')).toHaveValue(submitValue)\n      await expect(page.locator('input[name=\"reset_input\"]')).toHaveValue(resetValue)\n    })\n\n    test('disabled fields reset behavior', async ({ page }) => {\n      // Get initial value of the disabled field\n      const initialValue = await page.locator('#disabled_field').inputValue()\n      expect(initialValue).toBe('Ignore me')\n\n      // Change the disabled field value using JavaScript\n      await page.evaluate(() => {\n        const input = document.querySelector('#disabled_field') as HTMLInputElement\n        input.value = 'Changed Value'\n      })\n\n      // Verify the disabled field value is changed\n      await expect(page.locator('#disabled_field')).toHaveValue('Changed Value')\n\n      await page.fill('#name', 'Test Name')\n      await page.fill('#email', 'test@test.com')\n\n      // Partial reset - disabled fields use their DOM defaultValue\n      await resetForm(page, ['disabled_field', 'name', 'email'])\n\n      // Disabled field is reset using its defaultValue\n      await expect(page.locator('#disabled_field')).toHaveValue('Ignore me')\n      await expect(page.locator('#name')).toHaveValue('John Doe')\n      await expect(page.locator('#email')).toHaveValue('john@example.com')\n\n      await page.fill('#name', 'Test Name Again')\n\n      // Change disabled field again to test full reset\n      await page.evaluate(() => {\n        const input = document.querySelector('#disabled_field') as HTMLInputElement\n        input.value = 'Changed Again'\n      })\n\n      // Full reset - uses browser's native reset() which resets all fields including disabled\n      await resetForm(page)\n\n      // Both partial and full reset now work consistently for disabled fields\n      await expect(page.locator('#disabled_field')).toHaveValue('Ignore me')\n      await expect(page.locator('#name')).toHaveValue('John Doe')\n    })\n\n    test('resets fields with dotted notation names', async ({ page }) => {\n      await page.fill('#user_name', 'Changed User')\n      await page.fill('#user_email', 'changed@user.com')\n      await page.fill('#company_name', 'Changed Corp')\n\n      await resetForm(page)\n\n      await expect(page.locator('#user_name')).toHaveValue('Default User')\n      await expect(page.locator('#user_email')).toHaveValue('user@default.com')\n      await expect(page.locator('#company_name')).toHaveValue('Default Corp')\n    })\n\n    test('resets array fields with same name', async ({ page }) => {\n      await page.fill('#tag_0', 'php')\n      await page.fill('#tag_1', 'laravel')\n      await page.fill('#tag_2', 'symfony')\n\n      await resetForm(page)\n\n      await expect(page.locator('#tag_0')).toHaveValue('javascript')\n      await expect(page.locator('#tag_1')).toHaveValue('vue')\n      await expect(page.locator('#tag_2')).toHaveValue('inertia')\n    })\n\n    test('edge cases - non-existent fields and dynamic fields', async ({ page }) => {\n      // Scenario 1: Handles non-existent field names gracefully\n      await page.fill('#name', 'Changed Name')\n      await page.fill('#email', 'changed@email.com')\n\n      // Reset with non-existent field names mixed with real ones\n      await resetForm(page, ['nonExistentField', 'name', 'anotherFakeField'])\n\n      // Verify real field was reset, others unchanged\n      await expect(page.locator('#name')).toHaveValue('John Doe')\n      await expect(page.locator('#email')).toHaveValue('changed@email.com')\n\n      // Scenario 2: Reset works with dynamically added fields\n      await page.evaluate(() => {\n        const form = document.querySelector('form')\n        const newInput = document.createElement('input')\n        newInput.type = 'text'\n        newInput.name = 'dynamic_field'\n        newInput.id = 'dynamic_field'\n        newInput.value = 'initial value'\n        form?.appendChild(newInput)\n      })\n\n      // Change the dynamic field\n      await page.fill('#dynamic_field', 'changed value')\n\n      // Reset should handle it (though it won't have a default in FormData)\n      await resetForm(page)\n\n      // Dynamic field should be empty (no default was captured)\n      await expect(page.locator('#dynamic_field')).toHaveValue('')\n\n      // Other fields should reset normally\n      await expect(page.locator('#name')).toHaveValue('John Doe')\n    })\n\n    test('can reset form using reset-type input element', async ({ page }) => {\n      await page.fill('#name', 'Changed Name')\n      await page.fill('#email', 'changed@example.com')\n\n      await expect(page.locator('#name')).toHaveValue('Changed Name')\n      await expect(page.locator('#email')).toHaveValue('changed@example.com')\n\n      await page.click('input[name=\"reset_input\"]')\n\n      await expect(page.locator('#name')).toHaveValue('John Doe')\n      await expect(page.locator('#email')).toHaveValue('john@example.com')\n    })\n\n    test('can reset form using reset-type button element', async ({ page }) => {\n      await page.fill('#name', 'Changed Name')\n      await page.fill('#email', 'changed@example.com')\n\n      await expect(page.locator('#name')).toHaveValue('Changed Name')\n      await expect(page.locator('#email')).toHaveValue('changed@example.com')\n\n      await page.click('button[name=\"reset_button\"]')\n\n      await expect(page.locator('#name')).toHaveValue('John Doe')\n      await expect(page.locator('#email')).toHaveValue('john@example.com')\n    })\n\n    test('multi-select reset behavior comprehensive test', async ({ page }) => {\n      // Multi-select with no defaults resets to empty\n      await page.selectOption('#languages', ['javascript', 'python'])\n      const beforeLanguageReset = await getSelectedOptions(page, '#languages')\n      expect(beforeLanguageReset).toEqual(['javascript', 'python'])\n\n      await resetForm(page, ['languages[]'])\n      const afterLanguageReset = await getSelectedOptions(page, '#languages')\n      expect(afterLanguageReset).toEqual([])\n\n      // Multi-select with all options selected resets correctly\n      await page.selectOption('#tools', ['vscode']) // Select only one\n      const beforeToolsReset = await getSelectedOptions(page, '#tools')\n      expect(beforeToolsReset).toEqual(['vscode'])\n\n      await resetForm(page, ['tools[]'])\n      const afterToolsReset = await getSelectedOptions(page, '#tools')\n      expect(afterToolsReset.sort()).toEqual(['sublime', 'vscode', 'webstorm'])\n\n      // Single select vs multi-select behavior differs correctly\n      await page.selectOption('#editor', 'emacs')\n      await page.selectOption('#skills', ['react'])\n\n      await resetForm(page, ['editor', 'skills[]'])\n\n      await expect(page.locator('#editor')).toHaveValue('vim')\n      const skillsSelected = await getSelectedOptions(page, '#skills')\n      expect(skillsSelected.sort()).toEqual(['angular', 'vue'])\n\n      // Partial reset preserves other multi-selects\n      await page.selectOption('#skills', ['react', 'svelte'])\n      await page.selectOption('#languages', ['javascript', 'typescript'])\n      await page.selectOption('#tools', ['vscode'])\n\n      await resetForm(page, ['skills[]'])\n\n      const skillsAfterPartialReset = await getSelectedOptions(page, '#skills')\n      expect(skillsAfterPartialReset.sort()).toEqual(['angular', 'vue'])\n\n      const languagesAfterPartialReset = await getSelectedOptions(page, '#languages')\n      expect(languagesAfterPartialReset).toEqual(['javascript', 'typescript'])\n\n      const toolsAfterPartialReset = await getSelectedOptions(page, '#tools')\n      expect(toolsAfterPartialReset).toEqual(['vscode'])\n\n      // Edge cases with invalid selections\n      await page.evaluate(() => {\n        const select = document.querySelector('#skills') as HTMLSelectElement\n        Array.from(select.options).forEach((opt) => (opt.selected = false))\n        select.value = 'nonexistent'\n      })\n\n      await resetForm(page, ['skills[]'])\n      const skillsAfterEdgeCase = await getSelectedOptions(page, '#skills')\n      expect(skillsAfterEdgeCase.sort()).toEqual(['angular', 'vue'])\n\n      // Verify detailed option states (bug fix verification)\n      await page.selectOption('#skills', ['react', 'svelte'])\n      await resetForm(page, ['skills[]'])\n\n      const detailedOptions = await page.evaluate(() => {\n        const select = document.querySelector('#skills') as HTMLSelectElement\n        return {\n          selectedValues: Array.from(select.selectedOptions)\n            .map((opt) => opt.value)\n            .sort(),\n          allValues: Array.from(select.options).map((opt) => ({ value: opt.value, selected: opt.selected })),\n        }\n      })\n\n      expect(detailedOptions.selectedValues).toEqual(['angular', 'vue'])\n      expect(detailedOptions.allValues).toEqual([\n        { value: 'vue', selected: true },\n        { value: 'react', selected: false },\n        { value: 'angular', selected: true },\n        { value: 'svelte', selected: false },\n      ])\n    })\n\n    test('numeric field reset behavior - full and selective', async ({ page }) => {\n      // Scenario 1: Full reset of numeric fields\n      await page.check('#rating_3')\n      await page.uncheck('#years_2020')\n      await page.uncheck('#years_2022')\n      await page.check('#years_2021')\n      await page.selectOption('#version', '2')\n      await page.selectOption('#ports', ['8080'])\n\n      // Verify fields were changed\n      await expect(page.locator('#rating_3')).toBeChecked()\n      await expect(page.locator('#years_2021')).toBeChecked()\n      await expect(page.locator('#years_2020')).not.toBeChecked()\n      await expect(page.locator('#years_2022')).not.toBeChecked()\n      await expect(page.locator('#version')).toHaveValue('2')\n      const selectedPorts = await getSelectedOptions(page, '#ports')\n      expect(selectedPorts).toEqual(['8080'])\n\n      await resetForm(page)\n\n      // Verify numeric fields are reset to defaults\n      await expect(page.locator('#rating_1')).toBeChecked()\n      await expect(page.locator('#rating_2')).not.toBeChecked()\n      await expect(page.locator('#rating_3')).not.toBeChecked()\n      await expect(page.locator('#years_2020')).toBeChecked()\n      await expect(page.locator('#years_2021')).not.toBeChecked()\n      await expect(page.locator('#years_2022')).toBeChecked()\n      await expect(page.locator('#version')).toHaveValue('1')\n      const resetPorts = await getSelectedOptions(page, '#ports')\n      expect(resetPorts.sort()).toEqual(['443', '80'])\n\n      // Scenario 2: Selective reset of numeric fields\n      await page.check('#rating_2')\n      await page.uncheck('#years_2020')\n      await page.check('#years_2021')\n      await page.selectOption('#version', '3')\n      await page.selectOption('#ports', ['8080'])\n\n      // Reset only rating and version fields\n      await resetForm(page, ['rating', 'version'])\n\n      // Verify only specified numeric fields are reset\n      await expect(page.locator('#rating_1')).toBeChecked()\n      await expect(page.locator('#rating_2')).not.toBeChecked()\n      await expect(page.locator('#version')).toHaveValue('1')\n\n      // Other fields should maintain changed values\n      await expect(page.locator('#years_2020')).not.toBeChecked()\n      await expect(page.locator('#years_2021')).toBeChecked()\n      await expect(page.locator('#years_2022')).toBeChecked() // This stays as original default\n      const unchangedPorts = await getSelectedOptions(page, '#ports')\n      expect(unchangedPorts).toEqual(['8080'])\n    })\n  })\n\n  test('it accepts wayfinder shaped objects as action', async ({ page }) => {\n    await page.goto('/form-component/wayfinder')\n\n    const form = page.locator('form')\n    await expect(form).toHaveAttribute('action', '/dump/post')\n    await expect(form).toHaveAttribute('method', 'post')\n\n    await page.getByRole('button', { name: 'Submit' }).click()\n\n    const dump = await shouldBeDumpPage(page, 'post')\n    expect(dump.method).toEqual('post')\n    expect(dump.form).toEqual({\n      name: 'John Doe',\n      active: 'true',\n    })\n  })\n\n  const cacheTagsPropTypes = ['string', 'array']\n\n  cacheTagsPropTypes.forEach((propType) => {\n    test(`invalidate prefetch cache using tags (using ${propType})`, async ({ page }) => {\n      await page.goto('/form-component/invalidate-tags/' + propType)\n\n      // Prefetch both pages\n      const prefetchUser = page.waitForResponse('/prefetch/tags/1')\n      await page.getByRole('link', { name: 'User Tagged Page' }).hover()\n      await prefetchUser\n\n      const prefetchProduct = page.waitForResponse('/prefetch/tags/2')\n      await page.getByRole('link', { name: 'Product Tagged Page' }).hover()\n      await prefetchProduct\n\n      // Submit form that invalidates 'user' tag\n      await page.fill('#form-name', 'Test User')\n      await page.click('#submit-invalidate-user')\n      await shouldBeDumpPage(page, 'post')\n\n      await page.goBack()\n\n      // User-tagged page should be invalidated and refetched\n      requests.listen(page)\n      await page.getByRole('link', { name: 'User Tagged Page' }).click()\n      await expect(page).toHaveURL('/prefetch/tags/1')\n      await expect.poll(() => requests.requests.length).toBeGreaterThanOrEqual(1)\n\n      // Go back and check product page is still cached\n      await page.goBack()\n      requests.listen(page)\n      await page.getByRole('link', { name: 'Product Tagged Page' }).click()\n      await expect(page).toHaveURL('/prefetch/tags/2')\n      expect(requests.requests.length).toBe(0)\n    })\n  })\n\n  test.describe('React', () => {\n    test.skip(process.env.PACKAGE !== 'react', 'Skipping React-specific tests')\n\n    test('it preserves the internal state of child components', async ({ page }) => {\n      await page.goto('/form-component/child-component')\n\n      await expect(page.getByText('Form is clean')).toBeVisible()\n\n      await page.fill('#child', 'a')\n      await expect(page.locator('#child')).toHaveValue('A')\n      await expect(page.getByText('Form is dirty')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Submit' }).click()\n      const dump = await shouldBeDumpPage(page, 'post')\n      expect(dump.form).toEqual({ child: 'A' })\n    })\n  })\n\n  test.describe('getData and getFormData methods', () => {\n    test.beforeEach(async ({ page }) => {\n      consoleMessages.listen(page)\n      await page.goto('/form-component/data-methods')\n    })\n\n    test('getData returns form data as object', async ({ page }) => {\n      await page.fill('#name', 'John Doe')\n      await page.getByRole('button', { name: 'Test getData()' }).click()\n\n      const result = consoleMessages.messages.find((msg) => msg.includes('getData result:'))\n      expect(result).toBe('getData result: {\"name\":\"John Doe\"}')\n    })\n\n    test('getFormData returns FormData instance', async ({ page }) => {\n      await page.fill('#name', 'Jane Doe')\n      await page.getByRole('button', { name: 'Test getFormData()' }).click()\n\n      const formDataMessage = consoleMessages.messages.find((msg) => msg.includes('getFormData entries:'))\n      expect(formDataMessage).toBe('getFormData entries: {\"name\":\"Jane Doe\"}')\n    })\n  })\n\n  test.describe('Mixed Key Serialization', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/form-component/mixed-key-serialization')\n    })\n\n    test('submits form with mixed numeric and string keys as objects', async ({ page }) => {\n      await page.getByRole('button', { name: 'Submit' }).first().click()\n\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      expect(Array.isArray(dump.form.fields?.entries)).toBe(false)\n      expect(typeof dump.form.fields?.entries).toBe('object')\n\n      const entryKeys = Object.keys(dump.form.fields.entries)\n      expect(entryKeys).toEqual(['100', 'new:1'])\n\n      expect(dump.form.fields.entries['100']).toEqual({\n        name: 'John Doe',\n        email: 'john@example.com',\n      })\n\n      expect(dump.form.fields.entries['new:1']).toEqual({\n        name: 'Jane Smith',\n        email: 'jane@example.com',\n      })\n    })\n  })\n\n  test.describe('Submit Button', () => {\n    test.beforeEach(async ({ page }) => {\n      await page.goto('/form-component/submit-button')\n    })\n\n    test('includes submit button name and value in form data', async ({ page }) => {\n      await page.click('#save-button')\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      expect(dump.form).toEqual({\n        name: 'John Doe',\n        action: 'save',\n      })\n    })\n\n    test('includes different button value when clicking different submit button', async ({ page }) => {\n      await page.click('#draft-button')\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      expect(dump.form).toEqual({\n        name: 'John Doe',\n        action: 'draft',\n      })\n    })\n\n    test('does not include action when button has no name', async ({ page }) => {\n      await page.click('#no-name-button')\n      const dump = await shouldBeDumpPage(page, 'post')\n\n      expect(dump.form).toEqual({\n        name: 'John Doe',\n      })\n    })\n  })\n\n  test.describe('Form Target', () => {\n    test('it opens a new tab when button has formTarget=\"_blank\" on GET forms', async ({ page, context }) => {\n      await page.goto('/form-component/form-target')\n\n      const newPagePromise = context.waitForEvent('page')\n      await page.click('#button-blank')\n      const newPage = await newPagePromise\n\n      await newPage.waitForLoadState()\n      const text = await newPage.locator('body').innerText()\n\n      expect(text).toContain('query:search=test-query&format=csv')\n      await newPage.close()\n    })\n\n    test('it opens a new tab when input has formTarget=\"_blank\" on GET forms', async ({ page, context }) => {\n      await page.goto('/form-component/form-target')\n\n      const newPagePromise = context.waitForEvent('page')\n      await page.click('#input-blank')\n      const newPage = await newPagePromise\n\n      await newPage.waitForLoadState()\n      const text = await newPage.locator('body').innerText()\n\n      expect(text).toContain('query:search=test-query&type=export')\n      await newPage.close()\n    })\n  })\n})\n"
  },
  {
    "path": "tests/form-helper.spec.ts",
    "content": "import test, { expect, Page } from '@playwright/test'\nimport { clickAndWaitForResponse, consoleMessages, pageLoads, shouldBeDumpPage } from './support'\n\ntest.describe('Form Helper', () => {\n  test.describe('Methods', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/form-helper/methods')\n      await page.check('#remember')\n    })\n\n    const data = [\n      { method: 'post', label: 'POST' },\n      { method: 'put', label: 'PUT' },\n      { method: 'patch', label: 'PATCH' },\n      { method: 'delete', label: 'DELETE' },\n      { method: 'post', label: 'SUBMIT' },\n      { method: 'post', label: 'SUBMIT OBJECT' },\n    ] as const\n\n    data.forEach(({ method, label }) => {\n      test(`can submit the form using the ${label} method`, async ({ page }) => {\n        await page.getByRole('button', { name: `${label} form` }).click()\n\n        const dump = await shouldBeDumpPage(page, method)\n\n        await expect(dump.method).toEqual(method)\n        await expect(dump.query).toEqual({})\n        await expect(dump.form.name).toEqual('foo')\n        await expect(dump.form.remember).toEqual(true)\n      })\n    })\n  })\n\n  test.describe('Transform', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/form-helper/transform')\n      await page.check('#remember')\n    })\n\n    const data = [\n      { method: 'post', label: 'POST', fooValue: 'bar' },\n      { method: 'put', label: 'PUT', fooValue: 'baz' },\n      { method: 'patch', label: 'PATCH', fooValue: 'foo' },\n      { method: 'delete', label: 'DELETE', fooValue: 'bar' },\n    ] as const\n\n    data.forEach(({ method, label, fooValue }) => {\n      test(`can transform the form prior to submission using the ${label} method`, async ({ page }) => {\n        await page.getByRole('button', { name: `${label} form` }).click()\n\n        const dump = await shouldBeDumpPage(page, method)\n\n        await expect(dump.method).toEqual(method)\n        await expect(dump.query).toEqual({})\n        await expect(dump.form.name).toEqual(fooValue)\n        await expect(dump.form.remember).toEqual(true)\n      })\n    })\n  })\n\n  test.describe('Errors', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n\n      await page.goto('/form-helper/errors')\n      const errorsStatus = await page.locator('.errors-status')\n      await expect(await errorsStatus.textContent()).toEqual('Form has no errors')\n\n      await page.fill('#name', 'A')\n      await page.fill('#handle', 'B')\n      await page.check('#remember')\n    })\n\n    const waitForErrors = async (page: Page) => {\n      await page.waitForFunction(() => {\n        return document.querySelector('.errors-status')?.textContent === 'Form has errors'\n      })\n    }\n\n    const waitForNoErrors = async (page: Page) => {\n      await page.waitForFunction(() => {\n        return document.querySelector('.errors-status')?.textContent === 'Form has no errors'\n      })\n    }\n\n    test('can display form errors', async ({ page }) => {\n      await page.waitForSelector('.name_error', { state: 'detached' })\n      await page.waitForSelector('.handle_error', { state: 'detached' })\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n\n      await page.getByRole('button', { name: 'Submit form' }).click()\n\n      await expect(page).toHaveURL('form-helper/errors')\n\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n      await waitForErrors(page)\n\n      const nameError = await page.locator('.name_error')\n      const handleError = await page.locator('.handle_error')\n\n      await expect(await nameError.textContent()).toEqual('Some name error')\n      await expect(await handleError.textContent()).toEqual('The Handle was invalid')\n    })\n\n    test('can clear all form errors', async ({ page }) => {\n      await page.getByRole('button', { name: 'Submit form' }).click()\n\n      await expect(page).toHaveURL('form-helper/errors')\n\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n\n      await waitForErrors(page)\n\n      const nameError = await page.locator('.name_error')\n      const handleError = await page.locator('.handle_error')\n\n      await expect(await nameError.textContent()).toEqual('Some name error')\n      await expect(await handleError.textContent()).toEqual('The Handle was invalid')\n\n      await page.getByRole('button', { name: 'Clear all errors' }).click()\n\n      await page.waitForSelector('.name_error', { state: 'detached' })\n      await page.waitForSelector('.handle_error', { state: 'detached' })\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n\n      await waitForNoErrors(page)\n    })\n\n    test('does not reset fields back to their initial values when it clears all form errors', async ({ page }) => {\n      await page.getByRole('button', { name: 'Submit form' }).click()\n\n      await expect(page).toHaveURL('form-helper/errors')\n\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n\n      await waitForErrors(page)\n\n      const nameError = await page.locator('.name_error')\n      const handleError = await page.locator('.handle_error')\n\n      await expect(await nameError.textContent()).toEqual('Some name error')\n      await expect(await handleError.textContent()).toEqual('The Handle was invalid')\n\n      await expect(await page.locator('#name').inputValue()).toEqual('A')\n      await expect(await page.locator('#handle').inputValue()).toEqual('B')\n      await expect(await page.locator('#remember').isChecked()).toEqual(true)\n\n      await page.getByRole('button', { name: 'Clear all errors' }).click()\n\n      await page.waitForSelector('.name_error', { state: 'detached' })\n      await page.waitForSelector('.handle_error', { state: 'detached' })\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n\n      await waitForNoErrors(page)\n\n      await expect(await page.locator('#name').inputValue()).toEqual('A')\n      await expect(await page.locator('#handle').inputValue()).toEqual('B')\n      await expect(await page.locator('#remember').isChecked()).toEqual(true)\n    })\n\n    test('can clear a subset of form errors', async ({ page }) => {\n      await page.getByRole('button', { name: 'Submit form' }).click()\n\n      await expect(page).toHaveURL('form-helper/errors')\n\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n\n      await waitForErrors(page)\n\n      const nameError = await page.locator('.name_error')\n      const handleError = await page.locator('.handle_error')\n\n      await expect(await nameError.textContent()).toEqual('Some name error')\n      await expect(await handleError.textContent()).toEqual('The Handle was invalid')\n\n      await page.getByRole('button', { name: 'Clear one error' }).click()\n\n      await waitForErrors(page)\n\n      await expect(await nameError.textContent()).toEqual('Some name error')\n      await page.waitForSelector('.handle_error', { state: 'detached' })\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n    })\n\n    test('does not reset fields back to their initial values when it clears a subset of form errors', async ({\n      page,\n    }) => {\n      await page.getByRole('button', { name: 'Submit form' }).click()\n\n      await expect(page).toHaveURL('form-helper/errors')\n\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n\n      await waitForErrors(page)\n\n      const nameError = await page.locator('.name_error')\n      const handleError = await page.locator('.handle_error')\n\n      await expect(await nameError.textContent()).toEqual('Some name error')\n      await expect(await handleError.textContent()).toEqual('The Handle was invalid')\n\n      await expect(await page.locator('#name').inputValue()).toEqual('A')\n      await expect(await page.locator('#handle').inputValue()).toEqual('B')\n      await expect(await page.locator('#remember').isChecked()).toEqual(true)\n\n      await page.getByRole('button', { name: 'Clear one error' }).click()\n\n      await waitForErrors(page)\n\n      await expect(await nameError.textContent()).toEqual('Some name error')\n      await page.waitForSelector('.handle_error', { state: 'detached' })\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n\n      await expect(await page.locator('#name').inputValue()).toEqual('A')\n      await expect(await page.locator('#handle').inputValue()).toEqual('B')\n      await expect(await page.locator('#remember').isChecked()).toEqual(true)\n    })\n\n    test('can set a single error', async ({ page }) => {\n      await page.getByRole('button', { name: 'Set one error' }).click()\n\n      await expect(page).toHaveURL('form-helper/errors')\n\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n      await page.waitForSelector('.name_error', { state: 'detached' })\n\n      await waitForErrors(page)\n\n      const handleError = await page.locator('.handle_error')\n      await expect(await handleError.textContent()).toEqual('Manually set Handle error')\n    })\n\n    test('can set multiple errors', async ({ page }) => {\n      await page.getByRole('button', { name: 'Set errors' }).click()\n\n      await expect(page).toHaveURL('form-helper/errors')\n\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n\n      await waitForErrors(page)\n\n      const handleError = await page.locator('.handle_error')\n      const nameError = await page.locator('.name_error')\n\n      await expect(await handleError.textContent()).toEqual('Manually set Handle error')\n      await expect(await nameError.textContent()).toEqual('Manually set Name error')\n    })\n\n    test('can reset all errors and reset all fields to their initial values', async ({ page }) => {\n      await page.getByRole('button', { name: 'Submit form' }).click()\n\n      await expect(page).toHaveURL('form-helper/errors')\n\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n\n      await waitForErrors(page)\n\n      const nameError = await page.locator('.name_error')\n      const handleError = await page.locator('.handle_error')\n\n      await expect(await nameError.textContent()).toEqual('Some name error')\n      await expect(await handleError.textContent()).toEqual('The Handle was invalid')\n\n      await page.getByRole('button', { name: 'Reset all' }).click()\n\n      await expect(page.locator('#name')).toHaveValue('foo')\n      await expect(page.locator('#handle')).toHaveValue('example')\n      await expect(page.locator('#remember')).not.toBeChecked()\n\n      await page.waitForSelector('.name_error', { state: 'detached' })\n      await page.waitForSelector('.handle_error', { state: 'detached' })\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n\n      await waitForNoErrors(page)\n    })\n\n    test('can reset a single error and reset a single field to its initial value', async ({ page }) => {\n      await page.getByRole('button', { name: 'Submit form' }).click()\n\n      await expect(page).toHaveURL('form-helper/errors')\n\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n\n      await waitForErrors(page)\n\n      const nameError = await page.locator('.name_error')\n      const handleError = await page.locator('.handle_error')\n\n      await expect(await nameError.textContent()).toEqual('Some name error')\n      await expect(await handleError.textContent()).toEqual('The Handle was invalid')\n\n      await page.getByRole('button', { name: 'Reset handle' }).click()\n\n      await expect(page.locator('#name')).toHaveValue('A')\n      await expect(page.locator('#handle')).toHaveValue('example')\n      await expect(page.locator('#remember')).toBeChecked()\n\n      await expect(await nameError.textContent()).toEqual('Some name error')\n      await page.waitForSelector('.handle_error', { state: 'detached' })\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n\n      await waitForErrors(page)\n    })\n  })\n\n  test('it clears errors for fields that are no longer invalid on resubmit', async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/form-helper/errors/clear-on-resubmit')\n\n    // Submit with both fields empty\n    await clickAndWaitForResponse(page, 'Submit', undefined, 'button')\n    await expect(page.locator('#name-error')).toHaveText('The name must be at least 3 characters.')\n    await expect(page.locator('#handle-error')).toHaveText('The handle must be at least 3 characters.')\n\n    // Fill name with valid value and resubmit\n    await page.fill('#name', 'John')\n    await clickAndWaitForResponse(page, 'Submit', undefined, 'button')\n\n    // Name error should be cleared, handle error should remain\n    await expect(page.locator('#name-error')).not.toBeVisible()\n    await expect(page.locator('#handle-error')).toHaveText('The handle must be at least 3 characters.')\n  })\n\n  test.describe('Dirty', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/form-helper/dirty')\n    })\n\n    test('can check if the form is dirty', async ({ page }) => {\n      await expect(page.getByText('Form is clean')).toBeVisible()\n      await page.fill('#name', 'Joe')\n      await expect(page.locator('#name')).toHaveValue('Joe')\n      await expect(page.getByText('Form is dirty')).toBeVisible()\n      await page.getByRole('button', { name: 'Submit form' }).click()\n      await expect(page.getByText('Form is clean')).toBeVisible()\n    })\n\n    test('form should be dirty after setting the defaults', async ({ page }) => {\n      test.skip(process.env.PACKAGE === 'svelte', 'Skipping Svelte for now')\n\n      await expect(page.getByText('Form is clean')).toBeVisible()\n      await page.getByRole('button', { name: 'Defaults', exact: true }).click()\n      await expect(page.getByText('Form is clean')).toBeVisible()\n      await page.getByRole('button', { name: 'Push value' }).click()\n      await expect(page.getByText('Form is dirty')).toBeVisible()\n    })\n\n    test('form should be clean after setting data and then setting the defaults', async ({ page }) => {\n      test.skip(process.env.PACKAGE === 'svelte', 'Skipping Svelte for now')\n\n      await expect(page.getByText('Form is clean')).toBeVisible()\n      await page.getByRole('button', { name: 'Data and Defaults' }).click()\n      await expect(page.getByText('Form is clean')).toBeVisible()\n      await page.getByRole('button', { name: 'Push value' }).click()\n      await expect(page.getByText('Form is dirty')).toBeVisible()\n    })\n\n    test('does not override manual setDefaults() calls in onSuccess', async ({ page }) => {\n      await expect(page.getByText('Form is clean')).toBeVisible()\n      await page.fill('#name', 'changed')\n      await expect(page.getByText('Form is dirty')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Submit and setDefaults', exact: true }).click()\n      await expect(page.getByText('Form is clean')).toBeVisible()\n      await expect(page.locator('#name')).toHaveValue('changed')\n    })\n\n    test('respects custom defaults set in onSuccess callback', async ({ page }) => {\n      await expect(page.getByText('Form is clean')).toBeVisible()\n      await page.fill('#name', 'changed')\n      await expect(page.getByText('Form is dirty')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Submit and setDefaults custom' }).click()\n      await expect(page.getByText('Form is dirty')).toBeVisible()\n      await expect(page.locator('#name')).toHaveValue('changed')\n\n      await page.fill('#name', 'Custom Default')\n      await expect(page.getByText('Form is clean')).toBeVisible()\n    })\n  })\n\n  test.describe('Data', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/form-helper/data')\n    })\n\n    test('can reset all fields to their initial values', async ({ page }) => {\n      await page.fill('#name', 'A')\n      await page.check('#remember')\n\n      await expect(page.locator('#name')).toHaveValue('A')\n      await expect(page.locator('#handle')).toHaveValue('example')\n      await expect(page.locator('#remember')).toBeChecked()\n\n      await page.getByRole('button', { name: 'Submit form', exact: true }).click()\n\n      await expect(page).toHaveURL('form-helper/data')\n\n      await page.getByRole('button', { name: 'Reset all data' }).click()\n\n      await expect(page.locator('#name')).toHaveValue('foo')\n      await expect(page.locator('#handle')).toHaveValue('example')\n      await expect(page.locator('#remember')).not.toBeChecked()\n    })\n\n    test('can reset a single field to its initial value', async ({ page }) => {\n      await page.fill('#name', 'A')\n      await page.fill('#handle', 'B')\n      await page.check('#remember')\n\n      await expect(page.locator('#name')).toHaveValue('A')\n      await expect(page.locator('#handle')).toHaveValue('B')\n      await expect(page.locator('#remember')).toBeChecked()\n\n      await page.getByRole('button', { name: 'Submit form', exact: true }).click()\n\n      await expect(page).toHaveURL('form-helper/data')\n\n      await page.getByRole('button', { name: 'Reset one field' }).click()\n\n      await expect(page.locator('#name')).toHaveValue('A')\n      await expect(page.locator('#handle')).toHaveValue('example')\n      await expect(page.locator('#remember')).toBeChecked()\n    })\n\n    test('does not reset errors when it resets one field to its initial value', async ({ page }) => {\n      await page.fill('#name', 'A')\n      await page.fill('#handle', 'B')\n      await page.check('#remember')\n\n      await page.getByRole('button', { name: 'Submit form', exact: true }).click()\n\n      await expect(page).toHaveURL('form-helper/data')\n\n      await expect(page.locator('#name')).toHaveValue('A')\n      await expect(page.locator('#handle')).toHaveValue('B')\n      await expect(page.locator('#remember')).toBeChecked()\n\n      await expect(page.locator('.errors-status')).toHaveText('Form has errors')\n      await expect(page.locator('.name_error')).toHaveText('Some name error')\n      await expect(page.locator('.handle_error')).toHaveText('The Handle was invalid')\n\n      await page.getByRole('button', { name: 'Reset one field' }).click()\n\n      await expect(page.locator('#name')).toHaveValue('A')\n      await expect(page.locator('#handle')).toHaveValue('example')\n      await expect(page.locator('#remember')).toBeChecked()\n\n      await expect(page.locator('.errors-status')).toHaveText('Form has errors')\n      await expect(page.locator('.name_error')).toHaveText('Some name error')\n      await expect(page.locator('.handle_error')).toHaveText('The Handle was invalid')\n      await expect(page.locator('.remember_error')).not.toBeVisible()\n    })\n\n    test('does not reset errors when it resets all fields to their initial values', async ({ page }) => {\n      await page.fill('#name', 'A')\n      await page.fill('#handle', 'B')\n      await page.check('#remember')\n\n      await page.getByRole('button', { name: 'Submit form', exact: true }).click()\n\n      await expect(page).toHaveURL('form-helper/data')\n\n      await expect(page.locator('#name')).toHaveValue('A')\n      await expect(page.locator('#handle')).toHaveValue('B')\n      await expect(page.locator('#remember')).toBeChecked()\n\n      await expect(page.locator('.errors-status')).toHaveText('Form has errors')\n      await expect(page.locator('.name_error')).toHaveText('Some name error')\n      await expect(page.locator('.handle_error')).toHaveText('The Handle was invalid')\n\n      await page.getByRole('button', { name: 'Reset all data' }).click()\n\n      await expect(page.locator('#name')).toHaveValue('foo')\n      await expect(page.locator('#handle')).toHaveValue('example')\n      await expect(page.locator('#remember')).not.toBeChecked()\n\n      await expect(page.locator('.errors-status')).toHaveText('Form has errors')\n      await expect(page.locator('.name_error')).toHaveText('Some name error')\n      await expect(page.locator('.handle_error')).toHaveText('The Handle was invalid')\n      await expect(page.locator('.remember_error')).not.toBeVisible()\n    })\n\n    test('preserves original defaults after reset in onSuccess callback', async ({ page }) => {\n      await page.fill('#name', 'A')\n      await page.getByRole('button', { name: 'Submit form and reset' }).click()\n      await expect(page.locator('#name')).toHaveValue('foo')\n\n      await page.fill('#name', 'B')\n      await page.getByRole('button', { name: 'Submit form and reset' }).click()\n      await expect(page.locator('#name')).toHaveValue('foo')\n    })\n\n    test.describe('Update \"reset\" defaults', () => {\n      test.beforeEach(async ({ page }) => {\n        await expect(page.locator('#name')).toHaveValue('foo')\n        await expect(page.locator('#handle')).toHaveValue('example')\n        await expect(page.locator('#remember')).not.toBeChecked()\n      })\n\n      test('can assign the current values as the new defaults', async ({ page }) => {\n        await page.fill('#name', 'A')\n        await page.fill('#handle', 'B')\n        await page.check('#remember')\n\n        await page.getByRole('button', { name: 'Reassign current as defaults' }).click()\n\n        await page.fill('#name', 'foo')\n        await page.fill('#handle', 'example')\n        await page.uncheck('#remember')\n\n        await expect(page.locator('#name')).toHaveValue('foo')\n        await expect(page.locator('#handle')).toHaveValue('example')\n        await expect(page.locator('#remember')).not.toBeChecked()\n\n        await page.getByRole('button', { name: 'Reset all data' }).click()\n\n        await expect(page.locator('#name')).toHaveValue('A')\n        await expect(page.locator('#handle')).toHaveValue('B')\n        await expect(page.locator('#remember')).toBeChecked()\n      })\n\n      test('can assign new defaults for multiple fields', async ({ page }) => {\n        await page.getByRole('button', { name: 'Reassign default values' }).click()\n\n        await expect(page.locator('#name')).toHaveValue('foo')\n        await expect(page.locator('#handle')).toHaveValue('example')\n        await expect(page.locator('#remember')).not.toBeChecked()\n\n        await page.getByRole('button', { name: 'Reset one field' }).click()\n\n        await expect(page.locator('#name')).toHaveValue('foo')\n        await expect(page.locator('#handle')).toHaveValue('updated handle')\n        await expect(page.locator('#remember')).not.toBeChecked()\n\n        await page.getByRole('button', { name: 'Reset all data' }).click()\n\n        await expect(page.locator('#name')).toHaveValue('foo')\n        await expect(page.locator('#handle')).toHaveValue('updated handle')\n        await expect(page.locator('#remember')).toBeChecked()\n      })\n\n      test('can assign new default for a single field', async ({ page }) => {\n        await page.getByRole('button', { name: 'Reassign single default' }).click()\n\n        await expect(page.locator('#name')).toHaveValue('foo')\n        await expect(page.locator('#handle')).toHaveValue('example')\n        await expect(page.locator('#remember')).not.toBeChecked()\n\n        await page.getByRole('button', { name: 'Reset all data' }).click()\n\n        await expect(page.locator('#name')).toHaveValue('single value')\n        await expect(page.locator('#handle')).toHaveValue('example')\n        await expect(page.locator('#remember')).not.toBeChecked()\n      })\n    })\n  })\n\n  test.describe('Remember', () => {\n    test('navigates correctly with remember key', async ({ page }) => {\n      // Start on users index\n      await page.goto('/remember/users')\n      await expect(page.getByRole('heading', { name: 'Users Index' })).toBeVisible()\n\n      // Navigate to user 1 edit\n      await page.getByRole('link', { name: 'Edit User One' }).click()\n      await expect(page).toHaveURL(/\\/remember\\/users\\/1\\/edit/)\n      await expect(page.getByRole('heading', { name: 'Edit User 1' })).toBeVisible()\n\n      // Navigate back to users index\n      await page.waitForTimeout(100)\n      await page.goBack()\n      await page.waitForTimeout(100)\n      await expect(page).toHaveURL('/remember/users')\n      await expect(page.getByRole('heading', { name: 'Users Index' })).toBeVisible()\n\n      // Navigate to user 2 edit\n      await page.getByRole('link', { name: 'Edit User Two' }).click()\n      await expect(page).toHaveURL(/\\/remember\\/users\\/2\\/edit/)\n      await expect(page.getByRole('heading', { name: 'Edit User 2' })).toBeVisible()\n\n      // Navigate back - should go to users index\n      await page.waitForTimeout(100)\n      await page.goBack()\n      await page.waitForTimeout(100)\n      await expect(page).toHaveURL('/remember/users')\n      await expect(page.getByRole('heading', { name: 'Users Index' })).toBeVisible()\n    })\n  })\n\n  const waitForEventMessages = async (page: Page, minCount?: number): Promise<any[string]> => {\n    if (typeof minCount === 'number') {\n      await page.waitForFunction((minCount) => (window as any).events.length >= minCount, minCount)\n    }\n\n    return await page.evaluate(() => (window as any).events)\n  }\n\n  const waitForDataMessages = async (page: Page, minCount?: number): Promise<any[string]> => {\n    if (typeof minCount === 'number') {\n      await page.waitForFunction((minCount) => (window as any).data.length >= minCount, minCount)\n    }\n\n    return await page.evaluate(() => (window as any).data)\n  }\n\n  test.describe('Events', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/form-helper/events')\n    })\n\n    test.describe('onBefore', () => {\n      test('fires when a request is about to be made', async ({ page }) => {\n        await page.getByRole('button', { exact: true, name: 'onBefore' }).click()\n\n        const messages = await waitForEventMessages(page, 1)\n        const data = await waitForDataMessages(page, 1)\n\n        await expect(messages[0]).toBe('onBefore')\n\n        const visit = data.find((d) => d.event === 'onBefore' && d.type === 'visit').data\n\n        await expect(visit).toHaveProperty('url')\n        await expect(visit).toHaveProperty('method')\n        await expect(visit).toHaveProperty('data')\n        await expect(visit).toHaveProperty('headers')\n        await expect(visit).toHaveProperty('preserveState')\n      })\n\n      test('can prevent the visit from starting by returning false', async ({ page }) => {\n        await page.getByRole('button', { exact: true, name: 'onBefore cancellation' }).click()\n\n        const messages = await waitForEventMessages(page, 1)\n\n        await expect(messages).toHaveLength(1)\n        await expect(messages[0]).toBe('onBefore')\n      })\n\n      test('will reset the successful and recently successful statuses immediately when the form gets (re)submitted', async ({\n        page,\n      }) => {\n        await expect(page.locator('.success-status')).toHaveText('Form was not successful')\n        await expect(page.locator('.recently-status')).toHaveText('Form was not recently successful')\n\n        await page.getByRole('button', { exact: true, name: 'Submit form' }).click()\n\n        await expect(page.locator('.success-status')).toHaveText('Form was successful')\n        await expect(page.locator('.recently-status')).toHaveText('Form was recently successful')\n\n        await page.getByRole('button', { exact: true, name: 'onBefore cancellation' }).click()\n\n        await expect(page.locator('.success-status')).toHaveText('Form was not successful')\n        await expect(page.locator('.recently-status')).toHaveText('Form was not recently successful')\n      })\n    })\n\n    test.describe('onStart', () => {\n      test('fires when the request has started', async ({ page }) => {\n        await page.getByRole('button', { exact: true, name: 'onStart' }).click()\n\n        const messages = await waitForEventMessages(page, 3)\n        const data = await waitForDataMessages(page, 3)\n\n        await expect(messages[2]).toBe('onStart')\n\n        const visit = data.find((d) => d.event === 'onStart' && d.type === 'visit').data\n\n        await expect(visit).toHaveProperty('url')\n        await expect(visit).toHaveProperty('method')\n        await expect(visit).toHaveProperty('data')\n        await expect(visit).toHaveProperty('headers')\n        await expect(visit).toHaveProperty('preserveState')\n      })\n\n      test('marks the form as processing', async ({ page }) => {\n        await clickAndWaitForResponse(page, 'onSuccess resets processing', null, 'button')\n\n        const messages = await waitForEventMessages(page, 5)\n        const data = await waitForDataMessages(page, 5)\n\n        const processing = data.find((d) => d.event === 'onStart' && d.type === 'processing').data\n\n        await expect(processing).toBe(true)\n        await expect(messages).toEqual(['onBefore', 'onCancelToken', 'onStart', 'onSuccess', 'onFinish'])\n      })\n    })\n\n    test.describe('onProgress', () => {\n      test('fires when the form has files (and upload progression occurs)', async ({ page }) => {\n        await page.getByRole('button', { exact: true, name: 'onProgress' }).click()\n\n        await page.waitForTimeout(100)\n\n        const messages = await waitForEventMessages(page, 4)\n        const data = await waitForDataMessages(page, 4)\n\n        const event = data.find((d) => d.event === 'onProgress' && d.type === 'progressEvent').data\n\n        await expect(messages[3]).toBe('onProgress')\n\n        await expect(event).toHaveProperty('percentage')\n        await expect(event).toHaveProperty('total')\n        await expect(event).toHaveProperty('loaded')\n        await expect(event.percentage).toBeGreaterThanOrEqual(0)\n        await expect(event.percentage).toBeLessThanOrEqual(100)\n      })\n\n      test('does not fire when the form has no files', async ({ page }) => {\n        await clickAndWaitForResponse(page, 'progress no files', null, 'button')\n\n        const messages = await waitForEventMessages(page, 5)\n\n        await expect(messages).toEqual(['onBefore', 'onCancelToken', 'onStart', 'onSuccess', 'onFinish'])\n      })\n\n      test('updates the progress property of the form', async ({ page, context }) => {\n        await clickAndWaitForResponse(page, 'onSuccess progress property', 'sleep', 'button')\n\n        const messages = await waitForEventMessages(page, 4)\n        const data = await waitForDataMessages(page, 4)\n\n        await expect(messages[2]).toBe('onStart')\n        await expect(messages[3]).toBe('onProgress')\n\n        const event = data.find((d) => d.event === 'onProgress' && d.type === 'progress').data\n\n        await expect(event).toHaveProperty('percentage')\n        await expect(event).toHaveProperty('total')\n        await expect(event).toHaveProperty('loaded')\n        await expect(event.percentage).toBeGreaterThanOrEqual(0)\n        await expect(event.percentage).toBeLessThanOrEqual(100)\n      })\n    })\n\n    test.describe('onCancel', () => {\n      test('fires when the request was cancelled', async ({ page }) => {\n        await page.getByRole('button', { exact: true, name: 'Cancellable Visit' }).click()\n\n        await page.waitForTimeout(200)\n\n        const messages = await waitForEventMessages(page, 5)\n\n        await expect(messages[3]).toBe('CANCELLING!')\n        await expect(messages[4]).toBe('onCancel')\n      })\n    })\n\n    test.describe('onSuccess', () => {\n      test('fires the request succeeds without validation errors', async ({ page }) => {\n        await page.getByRole('button', { exact: true, name: 'onSuccess' }).click()\n\n        const messages = await waitForEventMessages(page, 4)\n        const data = await waitForDataMessages(page, 4)\n\n        await expect(messages[0]).toBe('onBefore')\n        await expect(messages[1]).toBe('onCancelToken')\n        await expect(messages[2]).toBe('onStart')\n        await expect(messages[3]).toBe('onSuccess')\n\n        const pageData = data.find((d) => d.event === 'onSuccess' && d.type === 'page').data\n\n        await expect(pageData).toHaveProperty('component')\n        await expect(pageData).toHaveProperty('props')\n        await expect(pageData).toHaveProperty('url')\n        await expect(pageData).toHaveProperty('version')\n      })\n\n      test('marks the form as no longer processing', async ({ page }) => {\n        await page.getByRole('button', { exact: true, name: 'onSuccess resets processing' }).click()\n\n        const data = await waitForDataMessages(page, 7)\n\n        const processing = data.find((d) => d.event === 'onStart' && d.type === 'processing').data\n        const notProcessing = data.find((d) => d.event === 'onFinish' && d.type === 'processing').data\n\n        await expect(processing).toBe(true)\n        await expect(notProcessing).toBe(false)\n      })\n\n      test('resets the progress property back to null', async ({ page }) => {\n        await clickAndWaitForResponse(page, 'onSuccess progress property', 'sleep', 'button')\n\n        const messages = await waitForEventMessages(page, 5)\n        const data = await waitForDataMessages(page, 5)\n        const event = data.find((d) => d.event === 'onProgress' && d.type === 'progress').data\n        const endEvent = data.find((d) => d.event === 'onFinish' && d.type === 'progress').data\n\n        await expect(event).toHaveProperty('percentage')\n        await expect(event).toHaveProperty('total')\n        await expect(event).toHaveProperty('loaded')\n        await expect(event.percentage).toBeGreaterThanOrEqual(0)\n        await expect(event.percentage).toBeLessThanOrEqual(100)\n\n        await expect(messages[4]).toBe('onFinish')\n        await expect(endEvent).toBeNull()\n      })\n\n      test('can delay onFinish from firing by returning a promise', async ({ page }) => {\n        await clickAndWaitForResponse(page, 'onSuccess promise', '/dump/post', 'button')\n\n        await page.waitForTimeout(50)\n\n        const messages = await waitForEventMessages(page, 6)\n\n        await expect(messages).toEqual([\n          'onBefore',\n          'onCancelToken',\n          'onStart',\n          'onSuccess',\n          'onFinish should have been fired by now if Promise functionality did not work',\n          'onFinish',\n        ])\n      })\n\n      test('clears all existing errors and resets the hasErrors prop', async ({ page }) => {\n        await clickAndWaitForResponse(page, 'onSuccess resets errors', null, 'button')\n\n        const messages = await waitForEventMessages(page, 6)\n        const data = await waitForDataMessages(page, 6)\n\n        await expect(messages).toEqual(['onError', 'onBefore', 'onCancelToken', 'onStart', 'onSuccess', 'onFinish'])\n\n        const errors = data.find((d) => d.event === 'onStart' && d.type === 'errors').data\n        const endingErrors = data.find((d) => d.event === 'onFinish' && d.type === 'errors').data\n\n        await expect(errors).toHaveProperty('name')\n        await expect(errors.name).toBe('Some name error')\n\n        await expect(endingErrors).toEqual({})\n      })\n\n      test('will mark the form as being submitted successfully', async ({ page }) => {\n        await expect(page.locator('.success-status')).toHaveText('Form was not successful')\n        await clickAndWaitForResponse(page, 'Submit form', null, 'button')\n        await expect(page.locator('.success-status')).toHaveText('Form was successful')\n      })\n\n      test('will only mark the form as \"recently successful\" for two seconds', async ({ page }) => {\n        await expect(page.locator('.success-status')).toHaveText('Form was not successful')\n        await expect(page.locator('.recently-status')).toHaveText('Form was not recently successful')\n\n        await clickAndWaitForResponse(page, 'Submit form', null, 'button')\n\n        await expect(page.locator('.success-status')).toHaveText('Form was successful')\n        await expect(page.locator('.recently-status')).toHaveText('Form was recently successful')\n\n        await page.waitForTimeout(2020)\n\n        await expect(page.locator('.success-status')).toHaveText('Form was successful')\n        await expect(page.locator('.recently-status')).toHaveText('Form was not recently successful')\n      })\n\n      test('resets the input value to the default value', async ({ page }) => {\n        await expect(page.locator('.name-input')).toHaveValue('foo')\n        await expect(page.locator('.remember-input')).not.toBeChecked()\n\n        await page.fill('.name-input', 'bar')\n        await page.check('.remember-input')\n\n        await expect(page.locator('.name-input')).toHaveValue('bar')\n        await expect(page.locator('.remember-input')).toBeChecked()\n\n        await clickAndWaitForResponse(page, 'onSuccess resets value', null, 'button')\n\n        await expect(page.locator('.name-input')).toHaveValue('foo')\n        await expect(page.locator('.remember-input')).not.toBeChecked()\n      })\n    })\n\n    test.describe('onError', () => {\n      test('fires when the request finishes with validation errors', async ({ page }) => {\n        await clickAndWaitForResponse(page, 'onError', 'form-helper/events/errors', 'button')\n\n        const messages = await waitForEventMessages(page, 5)\n        const data = await waitForDataMessages(page, 4)\n\n        await expect(messages).toEqual(['onBefore', 'onCancelToken', 'onStart', 'onError', 'onFinish'])\n\n        const errors = data.find((d) => d.event === 'onError' && d.type === 'errors').data\n\n        await expect(errors).toHaveProperty('name')\n        await expect(errors.name).toBe('Some name error')\n      })\n\n      test('marks the form as no longer processing', async ({ page }) => {\n        await clickAndWaitForResponse(page, 'onError resets processing', 'form-helper/events/errors', 'button')\n\n        const messages = await waitForEventMessages(page, 5)\n        const data = await waitForDataMessages(page, 5)\n\n        await expect(messages).toEqual(['onBefore', 'onCancelToken', 'onStart', 'onError', 'onFinish'])\n\n        const processing = data.find((d) => d.event === 'onStart' && d.type === 'processing').data\n        const notProcessing = data.find((d) => d.event === 'onFinish' && d.type === 'processing').data\n\n        await expect(processing).toBe(true)\n        await expect(notProcessing).toBe(false)\n      })\n\n      test('resets the progress property back to null', async ({ page }) => {\n        await clickAndWaitForResponse(page, 'onError progress property', 'form-helper/events/errors', 'button')\n\n        const messages = await waitForEventMessages(page, 4)\n        const data = await waitForDataMessages(page, 4)\n\n        await expect(messages[3]).toBe('onProgress')\n\n        const event = data.find((d) => d.event === 'onProgress' && d.type === 'progress').data\n        const finishEvent = data.find((d) => d.event === 'onFinish' && d.type === 'progress').data\n\n        await expect(event).toHaveProperty('percentage')\n        await expect(event).toHaveProperty('total')\n        await expect(event).toHaveProperty('loaded')\n        await expect(event.percentage).toBeGreaterThanOrEqual(0)\n        await expect(event.percentage).toBeLessThanOrEqual(100)\n\n        await expect(messages[4]).toBe('onError')\n        await expect(finishEvent).toBeNull()\n      })\n\n      test('sets form errors', async ({ page }) => {\n        await clickAndWaitForResponse(page, 'Errors set on error', 'form-helper/events/errors', 'button')\n\n        const messages = await waitForEventMessages(page, 5)\n        const data = await waitForDataMessages(page, 5)\n\n        await expect(messages).toEqual(['onBefore', 'onCancelToken', 'onStart', 'onError', 'onFinish'])\n\n        const startErrors = data.find((d) => d.event === null && d.type === 'errors').data\n        const errors = data.find((d) => d.event === 'onFinish' && d.type === 'errors').data\n\n        await expect(startErrors).toEqual({})\n\n        await expect(errors).toHaveProperty('name')\n        await expect(errors.name).toBe('Some name error')\n      })\n\n      test('can delay onFinish from firing by returning a promise', async ({ page }) => {\n        await clickAndWaitForResponse(page, 'onError promise', 'form-helper/events/errors', 'button')\n\n        await page.waitForTimeout(50)\n\n        const messages = await waitForEventMessages(page, 6)\n\n        await expect(messages).toEqual([\n          'onBefore',\n          'onCancelToken',\n          'onStart',\n          'onError',\n          'onFinish should have been fired by now if Promise functionality did not work',\n          'onFinish',\n        ])\n      })\n    })\n\n    test.describe('onFinish', () => {\n      test('fires when the request is completed', async ({ page }) => {\n        await page.getByRole('button', { exact: true, name: 'Successful request' }).click()\n\n        const messages = await waitForEventMessages(page, 5)\n\n        await expect(messages).toEqual(['onBefore', 'onCancelToken', 'onStart', 'onSuccess', 'onFinish'])\n      })\n    })\n  })\n})\n\ntest.describe('Nested', () => {\n  test.beforeEach(async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/form-helper/nested')\n  })\n\n  test('can handle nested data', async ({ page }) => {\n    await expect(await page.locator('#name').inputValue()).toEqual('foo')\n    await expect(await page.locator('#street').inputValue()).toEqual('123 Main St')\n    await expect(await page.locator('#city').inputValue()).toEqual('New York')\n    await expect(await page.locator('#foo').isChecked()).toEqual(true)\n    await expect(await page.locator('#bar').isChecked()).toEqual(true)\n    await expect(await page.locator('#baz').isChecked()).toEqual(false)\n    await expect(await page.locator('#repo-name').inputValue()).toEqual('inertiajs/inertia')\n    await expect(await page.locator('#organization-name').inputValue()).toEqual('Inertia')\n    await expect(await page.locator('#tag-0').isChecked()).toEqual(true)\n    await expect(await page.locator('#tag-1').isChecked()).toEqual(true)\n    await expect(await page.locator('#tag-2').isChecked()).toEqual(false)\n\n    await page.fill('#name', 'Joe')\n    await expect(page.locator('#name')).toHaveValue('Joe')\n\n    await page.fill('#street', '456 Elm St')\n    await expect(page.locator('#street')).toHaveValue('456 Elm St')\n\n    await page.check('#baz')\n    await expect(page.locator('#baz')).toBeChecked()\n\n    await page.uncheck('#bar')\n    await expect(page.locator('#bar')).not.toBeChecked()\n\n    await page.fill('#repo-name', 'inertiajs/inersha')\n    await expect(page.locator('#repo-name')).toHaveValue('inertiajs/inersha')\n\n    await page.check('#tag-2')\n    await expect(page.locator('#tag-2')).toBeChecked()\n\n    await page.uncheck('#tag-0')\n    await expect(page.locator('#tag-0')).not.toBeChecked()\n\n    await page.getByRole('button', { name: 'Submit form' }).click()\n    const dump = await shouldBeDumpPage(page, 'post')\n\n    await expect(dump.method).toEqual('post')\n    await expect(dump.query).toEqual({})\n    await expect(dump.form.name).toEqual('Joe')\n    await expect(dump.form.address.street).toEqual('456 Elm St')\n    await expect(dump.form.address.city).toEqual('New York')\n    await expect(dump.form.checked).toEqual(['foo', 'baz'])\n    await expect(dump.form.organization.repo.name).toEqual('inertiajs/inersha')\n    await expect(dump.form.organization.name).toEqual('Inertia')\n    await expect(dump.form.organization.repo.tags).toEqual(['v0.2', 'v0.3'])\n  })\n})\n\ntest.describe('React', () => {\n  test.skip(process.env.PACKAGE !== 'react', 'Only for React')\n\n  test('setDefaults callback in useEffect executes once per change', async ({ page }) => {\n    await page.goto('/form-helper/effect-count')\n\n    await expect(page.locator('#data-count')).toHaveText('Count: 0')\n    await expect(page.locator('#form-data')).toHaveText('Form data: {\"count\":0,\"foo\":\"bar\"}')\n    await expect(page.locator('#effect-count')).toHaveText('Effect count: 1')\n\n    await page.getByRole('button', { name: 'Increment' }).click()\n\n    await expect(page.locator('#data-count')).toHaveText('Count: 1')\n    await expect(page.locator('#form-data')).toHaveText('Form data: {\"count\":1,\"foo\":\"bar\"}')\n    await expect(page.locator('#effect-count')).toHaveText('Effect count: 2')\n  })\n})\n\ntest.describe('Vue Options API', () => {\n  test.skip(process.env.PACKAGE !== 'vue3', 'Only for Vue')\n\n  test.beforeEach(async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/form-helper/options-api')\n  })\n\n  test('can set default form values', async ({ page }) => {\n    await expect(page.locator('#email')).toHaveValue('test@test.com')\n    await expect(page.locator('#password')).toHaveValue('')\n    await expect(page.locator('#remember')).not.toBeChecked()\n    await expect(page.locator('.email-value')).toHaveText('test@test.com')\n  })\n\n  test('v-model two-way binding works', async ({ page }) => {\n    await expect(page.locator('#email')).toHaveValue('test@test.com')\n    await expect(page.locator('.email-value')).toHaveText('test@test.com')\n\n    await page.fill('#email', 'new@email.com')\n\n    await expect(page.locator('#email')).toHaveValue('new@email.com')\n    await expect(page.locator('.email-value')).toHaveText('new@email.com')\n    await expect(page.locator('.dirty-status')).toHaveText('Form is dirty')\n\n    await page.check('#remember')\n    await expect(page.locator('#remember')).toBeChecked()\n    await expect(page.locator('.remember-value')).toHaveText('true')\n  })\n\n  test('can programmatically update form fields', async ({ page }) => {\n    await expect(page.locator('#email')).toHaveValue('test@test.com')\n\n    await page.getByRole('button', { name: 'Set email programmatically' }).click()\n\n    await expect(page.locator('#email')).toHaveValue('changed@test.com')\n    await expect(page.locator('.email-value')).toHaveText('changed@test.com')\n    await expect(page.locator('.dirty-status')).toHaveText('Form is dirty')\n  })\n\n  test('can clear form fields', async ({ page }) => {\n    await expect(page.locator('#email')).toHaveValue('test@test.com')\n\n    await page.getByRole('button', { name: 'Clear email' }).click()\n\n    await expect(page.locator('#email')).toHaveValue('')\n    await expect(page.locator('.email-value')).toHaveText('')\n    await expect(page.locator('.dirty-status')).toHaveText('Form is dirty')\n  })\n\n  test('can reset form to initial values', async ({ page }) => {\n    await page.fill('#email', 'changed@test.com')\n    await expect(page.locator('.dirty-status')).toHaveText('Form is dirty')\n\n    await page.getByRole('button', { name: 'Reset all data' }).click()\n\n    await expect(page.locator('#email')).toHaveValue('test@test.com')\n    await expect(page.locator('.email-value')).toHaveText('test@test.com')\n    await expect(page.locator('.dirty-status')).toHaveText('Form is not dirty')\n  })\n\n  test('can submit form', async ({ page }) => {\n    await page.fill('#email', 'submitted@test.com')\n    await page.fill('#password', 'secret123')\n    await page.check('#remember')\n\n    await page.getByRole('button', { name: 'Submit form' }).click()\n\n    const dump = await shouldBeDumpPage(page, 'post')\n\n    await expect(dump.method).toEqual('post')\n    await expect(dump.form.email).toEqual('submitted@test.com')\n    await expect(dump.form.password).toEqual('secret123')\n    await expect(dump.form.remember).toEqual(true)\n  })\n})\n\ntest.describe('Reserved Keys', () => {\n  test.skip(process.env.PACKAGE === 'react', 'React uses separate data property, no conflicts possible')\n\n  test('it logs a console error when using reserved form keys', async ({ page }) => {\n    consoleMessages.listen(page)\n    await page.goto('/form-helper/reserved-keys')\n\n    // Form still works, but console.error was called\n    await expect(page.locator('#form-created')).toContainText('Form created')\n    expect(consoleMessages.messages.some((m) => m.includes('[Inertia] useForm()'))).toBe(true)\n    expect(consoleMessages.messages.some((m) => m.includes('\"progress\"'))).toBe(true)\n  })\n})\n\ntest('it can create a form without initial data and use transform', async ({ page }) => {\n  pageLoads.watch(page)\n  await page.goto('/form-helper/empty-form')\n\n  await page.getByRole('button', { name: 'Submit' }).click()\n\n  const dump = await shouldBeDumpPage(page, 'post')\n\n  await expect(dump.form.name).toEqual('John Doe')\n  await expect(dump.form.email).toEqual('john@example.com')\n})\n"
  },
  {
    "path": "tests/head.spec.ts",
    "content": "import { expect, Page, test } from '@playwright/test'\n\nasync function getInertiaHeadHTML(page: Page) {\n  return await page.evaluate(() => {\n    const inertiaElements = Array.from(document.querySelector('head').querySelectorAll('[inertia]'))\n\n    return inertiaElements.map((el) => el.outerHTML).join('')\n  })\n}\n\ntest.describe('Head component', () => {\n  test.beforeEach(async ({ page }) => {\n    test.skip(process.env.PACKAGE === 'svelte', 'Svelte adapter has no Head component')\n  })\n\n  test('replaces the original title element', async ({ page }) => {\n    await page.goto('/head')\n    await page.waitForSelector('title[inertia]', { state: 'attached' })\n\n    const titles = await page.evaluate(() => {\n      const allTitles = Array.from(document.querySelectorAll('title'))\n      return {\n        total: allTitles.length,\n        inertiaTitle: allTitles.find((t) => t.hasAttribute('inertia'))?.textContent,\n        allHaveInertiaAttribute: allTitles.every((t) => t.hasAttribute('inertia')),\n      }\n    })\n\n    expect(titles.total).toBe(1)\n    expect(titles.inertiaTitle).toBe('Test Head Component')\n    expect(titles.allHaveInertiaAttribute).toBe(true)\n  })\n\n  test('opt-in to using data-inertia instead of inertia attribute', async ({ page }) => {\n    await page.goto('/head/dataset')\n    await page.waitForSelector('title[data-inertia]', { state: 'attached' })\n\n    const titles = await page.evaluate(() => {\n      const allTitles = Array.from(document.querySelectorAll('title'))\n      return {\n        total: allTitles.length,\n        inertiaTitle: allTitles.find((t) => t.hasAttribute('data-inertia'))?.textContent,\n        allHaveInertiaAttribute: allTitles.every((t) => t.hasAttribute('data-inertia')),\n      }\n    })\n\n    expect(titles.total).toBe(1)\n    expect(titles.inertiaTitle).toBe('Test Head Component')\n    expect(titles.allHaveInertiaAttribute).toBe(true)\n  })\n\n  test('renders the title tag and children with proper escaping', async ({ page }) => {\n    await page.goto('/head')\n    await page.waitForSelector('title[inertia]', { state: 'attached' })\n\n    const headHTML = await getInertiaHeadHTML(page)\n    expect(headHTML).toBe(\n      '<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" inertia=\"\">' +\n        '<meta name=\"description\" content=\"This is an &quot;escape&quot; example\" inertia=\"\">' +\n        '<meta name=\"undefined\" content=\"undefined\" inertia=\"\">' +\n        '<meta name=\"number\" content=\"0\" inertia=\"\">' +\n        '<meta name=\"boolean\" content=\"true\" inertia=\"\">' +\n        '<meta name=\"false\" content=\"false\" inertia=\"\">' +\n        '<meta name=\"null\" content=\"null\" inertia=\"\">' +\n        '<meta name=\"float\" content=\"3.14\" inertia=\"\">' +\n        '<meta name=\"xss\" content=\"&lt;script&gt;alert(\\'xss\\')&lt;/script&gt;\" inertia=\"\">' +\n        '<meta name=\"ampersand\" content=\"Laravel &amp; Inertia\" inertia=\"\">' +\n        '<meta name=\"unicode\" content=\"Hélló! 🎉\" inertia=\"\">' +\n        '<title inertia=\"\">Test Head Component</title>',\n    )\n  })\n\n  test('dynamically updates head elements', async ({ page }) => {\n    await page.goto('/head/reactive')\n    await page.waitForSelector('title[inertia]', { state: 'attached' })\n\n    let headHTML = await getInertiaHeadHTML(page)\n    expect(headHTML).toBe(\n      '<meta name=\"author\" content=\"Test Author\" inertia=\"\">' +\n        '<meta name=\"description\" content=\"Initial description\" inertia=\"description\">' +\n        '<title inertia=\"\">Initial Title</title>',\n    )\n\n    await page.click('#update-meta')\n    await page.waitForTimeout(100)\n\n    headHTML = await getInertiaHeadHTML(page)\n    expect(headHTML).toBe(\n      '<meta name=\"author\" content=\"Test Author\" inertia=\"\">' +\n        '<meta name=\"description\" content=\"Updated description\" inertia=\"description\">' +\n        '<title inertia=\"\">Updated Title</title>',\n    )\n  })\n\n  test('renders multiple different head element tags', async ({ page }) => {\n    await page.goto('/head/mixed')\n    await page.waitForSelector('title[inertia]', { state: 'attached' })\n\n    const headHTML = await getInertiaHeadHTML(page)\n    expect(headHTML).toBe(\n      '<meta charset=\"utf-8\" inertia=\"\">' +\n        '<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" inertia=\"\">' +\n        '<meta name=\"description\" content=\"Testing multiple head elements\" inertia=\"\">' +\n        '<meta name=\"keywords\" content=\"test, vue, inertia\" inertia=\"\">' +\n        '<meta property=\"og:title\" content=\"Open Graph Title\" inertia=\"\">' +\n        '<meta property=\"og:description\" content=\"Open Graph Description\" inertia=\"\">' +\n        '<link rel=\"icon\" href=\"/favicon.ico\" inertia=\"\">' +\n        '<link rel=\"stylesheet\" href=\"/custom.css\" inertia=\"\">' +\n        '<link rel=\"canonical\" href=\"https://example.com/page\" inertia=\"\">' +\n        '<title inertia=\"\">Multiple Elements Test</title>',\n    )\n  })\n\n  test('handles conditional rendering', async ({ page }) => {\n    await page.goto('/head/conditional')\n    await page.waitForSelector('title[inertia]', { state: 'attached' })\n\n    let headHTML = await getInertiaHeadHTML(page)\n    expect(headHTML).toBe(\n      '<meta name=\"always-present\" content=\"This is always here\" inertia=\"\">' +\n        '<meta name=\"description\" content=\"This description is conditionally rendered\" inertia=\"description\">' +\n        '<title inertia=\"\">Conditional Rendering</title>',\n    )\n\n    await page.click('#toggle-description')\n    await page.waitForTimeout(100)\n    headHTML = await getInertiaHeadHTML(page)\n    expect(headHTML).toBe(\n      '<meta name=\"always-present\" content=\"This is always here\" inertia=\"\">' +\n        '<title inertia=\"\">Conditional Rendering</title>',\n    )\n\n    await page.click('#toggle-keywords')\n    await page.waitForTimeout(100)\n    headHTML = await getInertiaHeadHTML(page)\n    expect(headHTML).toBe(\n      '<meta name=\"always-present\" content=\"This is always here\" inertia=\"\">' +\n        '<title inertia=\"\">Conditional Rendering</title>' +\n        '<meta name=\"keywords\" content=\"vue, test, conditional\" inertia=\"keywords\">',\n    )\n\n    await page.click('#toggle-description')\n    await page.waitForTimeout(100)\n    headHTML = await getInertiaHeadHTML(page)\n    expect(headHTML).toBe(\n      '<meta name=\"always-present\" content=\"This is always here\" inertia=\"\">' +\n        '<title inertia=\"\">Conditional Rendering</title>' +\n        '<meta name=\"keywords\" content=\"vue, test, conditional\" inertia=\"keywords\">' +\n        '<meta name=\"description\" content=\"This description is conditionally rendered\" inertia=\"description\">',\n    )\n  })\n\n  test('handles head without title prop', async ({ page }) => {\n    await page.goto('/head/without-title')\n    await page.waitForTimeout(100)\n\n    const headHTML = await getInertiaHeadHTML(page)\n    expect(headHTML).toBe('<meta name=\"test\" content=\"no title provided\" inertia=\"\">')\n  })\n\n  test('handles head with title prop', async ({ page }) => {\n    await page.goto('/head/with-title')\n    await page.waitForSelector('title[inertia]', { state: 'attached' })\n\n    const headHTML = await getInertiaHeadHTML(page)\n    expect(headHTML).toBe(\n      '<meta name=\"description\" content=\"Title set via children, not prop\" inertia=\"\">' +\n        '<title inertia=\"\">Title from Children</title>',\n    )\n  })\n\n  test('preserves head-key for proper updates', async ({ page }) => {\n    await page.goto('/head/reactive')\n    await page.waitForSelector('title[inertia]', { state: 'attached' })\n\n    const descriptionInertiaAttr = await page.locator('meta[name=\"description\"]').getAttribute('inertia')\n    await expect(descriptionInertiaAttr).toBe('description')\n\n    await page.click('#update-meta')\n    await page.waitForTimeout(100)\n\n    const descriptionCount = await page.locator('meta[name=\"description\"]').count()\n    await expect(descriptionCount).toBe(1)\n    await expect(page.locator('meta[name=\"description\"]')).toHaveAttribute('content', 'Updated description')\n  })\n\n  test('does not duplicate meta tags on navigation', async ({ page }) => {\n    await page.goto('/head/mixed')\n    await page.waitForSelector('title[inertia]', { state: 'attached' })\n\n    await page.click('#navigate-away')\n    await page.waitForFunction(() => document.querySelector('title[inertia]')?.textContent === 'Home')\n\n    await page.click('#navigate-back')\n    await page.waitForFunction(() => document.querySelector('title[inertia]')?.textContent === 'Multiple Elements Test')\n\n    const expectedMixedContent =\n      '<meta charset=\"utf-8\" inertia=\"\">' +\n      '<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" inertia=\"\">' +\n      '<meta name=\"description\" content=\"Testing multiple head elements\" inertia=\"\">' +\n      '<meta name=\"keywords\" content=\"test, vue, inertia\" inertia=\"\">' +\n      '<meta property=\"og:title\" content=\"Open Graph Title\" inertia=\"\">' +\n      '<meta property=\"og:description\" content=\"Open Graph Description\" inertia=\"\">' +\n      '<link rel=\"icon\" href=\"/favicon.ico\" inertia=\"\">' +\n      '<link rel=\"stylesheet\" href=\"/custom.css\" inertia=\"\">' +\n      '<link rel=\"canonical\" href=\"https://example.com/page\" inertia=\"\">' +\n      '<title inertia=\"\">Multiple Elements Test</title>'\n\n    const headHTML = await getInertiaHeadHTML(page)\n    expect(headHTML).toBe(expectedMixedContent)\n\n    await page.goBack()\n    await page.waitForSelector('title[inertia]', { state: 'attached' })\n    const homeTitle = await page.evaluate(() => document.querySelector('title[inertia]')?.textContent)\n    expect(homeTitle).toBe('Home')\n\n    await page.goBack()\n    await page.waitForSelector('title[inertia]', { state: 'attached' })\n    const backToMixedHTML = await getInertiaHeadHTML(page)\n    expect(backToMixedHTML).toBe(expectedMixedContent)\n  })\n})\n"
  },
  {
    "path": "tests/history-quota.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport { clickAndWaitForResponse } from './support'\n\n// WebKit has a ~64MB limit on history.state storage.\n// Chromium and Firefox have virtually unlimited storage.\ntest.describe('history quota exceeded', () => {\n  test.setTimeout(10_000)\n\n  test.beforeEach(async ({ page, browserName }) => {\n    test.skip(browserName !== 'webkit', 'WebKit-specific quota limit')\n\n    await page.goto('/history-quota/1')\n  })\n\n  test('it performs a full page reload when quota is exceeded', async ({ page }) => {\n    let fullReloadAtPage = 0\n    let loadCount = 0\n\n    page.on('load', () => {\n      loadCount++\n    })\n\n    for (let i = 2; i <= 20; i++) {\n      const loadsBefore = loadCount\n\n      await clickAndWaitForResponse(page, `Page ${i}`, `/history-quota/${i}`)\n      await expect(page.getByText(`History Quota Test - Page ${i}`)).toBeVisible()\n\n      if (loadCount > loadsBefore) {\n        fullReloadAtPage = i\n        break\n      }\n    }\n\n    expect(fullReloadAtPage).toBeGreaterThan(0)\n    await expect(page.getByText(`History Quota Test - Page ${fullReloadAtPage}`)).toBeVisible()\n  })\n\n  test('navigation continues to work after quota-triggered reload', async ({ page }) => {\n    let reloadHappened = false\n\n    page.on('load', () => {\n      reloadHappened = true\n    })\n\n    for (let i = 2; i <= 20; i++) {\n      reloadHappened = false\n\n      await clickAndWaitForResponse(page, `Page ${i}`, `/history-quota/${i}`)\n      await expect(page.getByText(`History Quota Test - Page ${i}`)).toBeVisible()\n\n      if (reloadHappened) {\n        const nextPage = i + 1\n        await clickAndWaitForResponse(page, `Page ${nextPage}`, `/history-quota/${nextPage}`)\n        await expect(page.getByText(`History Quota Test - Page ${nextPage}`)).toBeVisible()\n        return\n      }\n    }\n\n    throw new Error('Expected a full page reload to occur')\n  })\n\n  test('back and forward navigation works after quota is exceeded', async ({ page }) => {\n    let reloadHappened = false\n    let reloadAtPage = 0\n\n    page.on('load', () => {\n      reloadHappened = true\n    })\n\n    for (let i = 2; i <= 20; i++) {\n      reloadHappened = false\n\n      await clickAndWaitForResponse(page, `Page ${i}`, `/history-quota/${i}`)\n      await expect(page.getByText(`History Quota Test - Page ${i}`)).toBeVisible()\n\n      if (reloadHappened) {\n        reloadAtPage = i\n        break\n      }\n    }\n\n    expect(reloadAtPage).toBeGreaterThan(0)\n\n    const pageAfterReload = reloadAtPage + 1\n    await clickAndWaitForResponse(page, `Page ${pageAfterReload}`, `/history-quota/${pageAfterReload}`)\n    await expect(page.getByText(`History Quota Test - Page ${pageAfterReload}`)).toBeVisible()\n\n    await page.goBack()\n    await page.waitForURL(`/history-quota/${reloadAtPage}`)\n    await expect(page.getByText(`History Quota Test - Page ${reloadAtPage}`)).toBeVisible()\n\n    await page.goBack()\n    await page.waitForURL(`/history-quota/${reloadAtPage - 1}`)\n    await expect(page.getByText(`History Quota Test - Page ${reloadAtPage - 1}`)).toBeVisible()\n\n    await page.goForward()\n    await page.waitForURL(`/history-quota/${reloadAtPage}`)\n    await expect(page.getByText(`History Quota Test - Page ${reloadAtPage}`)).toBeVisible()\n\n    await page.goForward()\n    await page.waitForURL(`/history-quota/${pageAfterReload}`)\n    await expect(page.getByText(`History Quota Test - Page ${pageAfterReload}`)).toBeVisible()\n  })\n})\n"
  },
  {
    "path": "tests/history-throttle.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport { consoleMessages, pageLoads } from './support'\n\ntest.describe('History API throttle', () => {\n  test('should handle rapid replaceState calls without crashing and continue navigating', async ({\n    page,\n    browserName,\n  }) => {\n    consoleMessages.listen(page)\n    pageLoads.watch(page)\n\n    await page.goto('/history-throttle')\n    await page.click('#trigger')\n    await expect(page.locator('#call-count')).toContainText('State updates: 120')\n\n    // Check for Safari's throttle error\n    const throttleErrors = consoleMessages.errors.filter(\n      (msg) =>\n        msg.includes('history.replaceState') ||\n        msg.includes('history.pushState') ||\n        msg.includes('SecurityError') ||\n        msg.includes('100 times'),\n    )\n\n    expect(throttleErrors, 'History API throttle errors should not occur').toHaveLength(0)\n\n    const throttleLogs = consoleMessages.messages.filter(\n      (msg) =>\n        msg.includes('history.replaceState') ||\n        msg.includes('history.pushState') ||\n        msg.includes('SecurityError') ||\n        msg.includes('100 times'),\n    )\n\n    if (browserName === 'webkit') {\n      expect(throttleLogs[0]).toContain('100 times')\n    }\n\n    // Verify navigation still works after throttling\n    await page.click('#home-link')\n    await expect(page.locator('.text')).toContainText('This is the Test App Entrypoint page')\n  })\n})\n"
  },
  {
    "path": "tests/history.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport { clickAndWaitForResponse, requests } from './support'\n\ntest.beforeEach(async ({ page }) => {\n  await page.goto('/history/1')\n})\n\ntest('it will not encrypt history by default', async ({ page }) => {\n  const historyState1 = await page.evaluate(() => window.history.state)\n  await expect(historyState1.page.component).toBe('History/Page')\n  await expect(historyState1.page.props.pageNumber).toBe('1')\n  await expect(page.getByText('This is page 1')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Page 2', '/history/2')\n  const historyState2 = await page.evaluate(() => window.history.state)\n  await expect(historyState2.page.component).toBe('History/Page')\n  await expect(historyState2.page.props.pageNumber).toBe('2')\n  await expect(page.getByText('This is page 2')).toBeVisible()\n\n  requests.listen(page)\n\n  await page.goBack()\n  await page.waitForURL('/history/1')\n  await expect(page.getByText('This is page 1')).toBeVisible()\n  await expect(requests.requests).toHaveLength(0)\n\n  await page.goForward()\n  await page.waitForURL('/history/2')\n  await expect(page.getByText('This is page 2')).toBeVisible()\n  await expect(requests.requests).toHaveLength(0)\n})\n\ntest('it can encrypt history', async ({ page }) => {\n  await clickAndWaitForResponse(page, 'Page 3', '/history/3')\n  // When history is encrypted, the page is an ArrayBuffer,\n  // but Playwright doesn't transfer it as such over the wire (page.evaluate),\n  // so if the object is \"empty\" and the page check below works, it's working.\n  await expect\n    .poll(async () => {\n      const state = await page.evaluate(() => window.history.state)\n      return state.page\n    })\n    .toEqual({})\n\n  requests.listen(page)\n\n  await page.goBack()\n  await page.waitForURL('/history/1')\n  await expect(page.getByText('This is page 1')).toBeVisible()\n  await expect(requests.requests).toHaveLength(0)\n\n  // Double check that this history state did not get encrypted\n  const historyState1 = await page.evaluate(() => window.history.state)\n  await expect(historyState1.page.component).toBe('History/Page')\n  await expect(historyState1.page.props.pageNumber).toBe('1')\n\n  await page.goForward()\n  await page.waitForURL('/history/3')\n  await expect\n    .poll(async () => {\n      const state = await page.evaluate(() => window.history.state)\n      return state.page\n    })\n    .toEqual({})\n  await expect(page.getByText('This is page 3')).toBeVisible()\n  await expect(requests.requests).toHaveLength(0)\n})\n\ntest('history can be cleared via router', async ({ page }) => {\n  await clickAndWaitForResponse(page, 'Page 3', '/history/3')\n\n  await page.waitForTimeout(200)\n\n  await page.goBack()\n  await page.waitForURL('/history/1')\n\n  await page.getByRole('button', { name: 'Clear History' }).click()\n\n  requests.listen(page)\n\n  await page.goForward()\n  await page.waitForURL('/history/3')\n  await expect(page.getByText('This is page 3')).toBeVisible()\n  await expect(requests.requests).toHaveLength(1)\n\n  await page.goBack()\n  await page.waitForURL('/history/1')\n  // Should be the same, non-encrypted history state doesn't get cleared\n  await expect(requests.requests).toHaveLength(1)\n\n  await page.goForward()\n  await page.waitForURL('/history/3')\n  await expect(requests.requests).toHaveLength(1)\n})\n\ntest('history can be cleared via props', async ({ page }) => {\n  await clickAndWaitForResponse(page, 'Page 3', '/history/3')\n  await clickAndWaitForResponse(page, 'Page 4', '/history/4')\n\n  requests.listen(page)\n\n  await page.goBack()\n  await page.waitForURL('/history/3')\n  await expect(page.getByText('This is page 3')).toBeVisible()\n  await expect(requests.requests).toHaveLength(1)\n\n  await page.goBack()\n  await page.waitForURL('/history/1')\n  // Should be the same, non-encrypted history state doesn't get cleared\n  await expect(requests.requests).toHaveLength(1)\n\n  await page.goForward()\n  await page.waitForURL('/history/3')\n  await expect(requests.requests).toHaveLength(1)\n})\n\ntest('multi byte strings can be encrypted', async ({ page }) => {\n  await clickAndWaitForResponse(page, 'Page 5', '/history/5')\n\n  // Check that the history state has a 'page' key\n  const historyState5Keys = await page.evaluate(() => Object.keys(window.history.state))\n  await expect(historyState5Keys).toContain('page')\n\n  // When history is encrypted, the page is an ArrayBuffer,\n  // but Playwright doesn't transfer it as such over the wire (page.evaluate),\n  // so if the object is \"empty\" and the page check below works, it's working.\n  const historyState5Page = await page.evaluate(() => window.history.state.page)\n  await expect(historyState5Page).toEqual({})\n\n  await expect(page.getByText('Multi byte character: 😃')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Page 1', '/history/1')\n\n  await expect(page.getByText('Multi byte character: n/a')).toBeVisible()\n\n  requests.listen(page)\n\n  await page.goBack()\n  await page.waitForURL('/history/5')\n  await expect(page.getByText('This is page 5')).toBeVisible()\n  await expect(requests.requests).toHaveLength(0)\n  await expect(page.getByText('Multi byte character: 😃')).toBeVisible()\n})\n\ntest('url will update after scrolling and pressing back', async ({ page }) => {\n  // Weird bug that surfaced after setting scroll restoration to manual\n  await page.waitForURL('/history/1')\n  await clickAndWaitForResponse(page, 'Page 5', '/history/5')\n  await page.evaluate(() => (window as any).scrollTo(0, 1000))\n  await page.goBack()\n  await page.waitForURL('/history/1')\n  await page.waitForTimeout(200)\n  await page.waitForURL('/history/1')\n})\n\ntest('it handles bfcache restoration after history is cleared', async ({ page }) => {\n  await clickAndWaitForResponse(page, 'Page 3', '/history/3')\n  await expect(page.getByText('This is page 3')).toBeVisible()\n\n  // Simulate clearHistory removing the encryption keys\n  await page.evaluate(() => {\n    window.sessionStorage.removeItem('historyKey')\n    window.sessionStorage.removeItem('historyIv')\n  })\n\n  requests.listen(page)\n\n  // Simulate bfcache restoration\n  await page.evaluate(() => {\n    window.dispatchEvent(new PageTransitionEvent('pageshow', { persisted: true }))\n  })\n\n  await page.waitForTimeout(1000)\n  expect(requests.requests.length).toBeGreaterThan(0)\n})\n\ntest('will pull from server if history version is different than current version when pressing back', async ({\n  page,\n}) => {\n  await page.goto('/history/version/1')\n  await page.waitForURL('/history/version/1')\n  await clickAndWaitForResponse(page, 'Page 2', '/history/version/2')\n\n  requests.listen(page)\n\n  await page.goBack()\n  await page.waitForURL('/history/version/1')\n  await page.waitForTimeout(200)\n  await expect(requests.requests).toHaveLength(1)\n})\n"
  },
  {
    "path": "tests/inertia.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\n\ntest.beforeEach(async ({ page }) => {\n  await page.goto('/')\n})\n\ntest('mounts the initial page', async ({ page }) => {\n  await expect(page.locator('#app')).toContainText('This is the Test App Entrypoint page')\n})\n"
  },
  {
    "path": "tests/infinite-scroll.spec.ts",
    "content": "import { expect, Locator, Page, test } from '@playwright/test'\nimport { consoleMessages, gotoPageAndWaitForContent, requests } from './support'\n\nfunction infiniteScrollRequests() {\n  return requests.requests.filter((req) => {\n    return (\n      req.url().includes('/infinite-scroll/') &&\n      !!req.headers()['x-inertia'] &&\n      !!req.headers()['x-inertia-partial-data']\n    )\n  })\n}\n\nasync function scrollToTop(page: Page) {\n  await page.evaluate(() => window.scrollTo(0, 0))\n  await expect.poll(() => page.evaluate(() => window.scrollY === 0)).toBe(true)\n}\n\nasync function scrollToBottom(page: Page) {\n  const scrollTarget = await page.evaluate(() => {\n    const target = document.body.scrollHeight - window.innerHeight\n    window.scrollTo(0, document.body.scrollHeight)\n    return target\n  })\n  await page.waitForFunction((target: number) => window.scrollY >= target - 2, scrollTarget)\n}\n\nasync function smoothScrollTo(page: any, targetY: number) {\n  // The { behavior: 'smooth' } option has different implementation across browsers, so we do our\n  // own 'smooth' scroll by scrolling halfway first, then to the target after a short delay...\n  await page.evaluate((top: number) => {\n    const current = window.scrollY\n    window.scrollTo(0, current + (top - current) / 2)\n    setTimeout(() => window.scrollTo(0, top), 10)\n  }, targetY)\n\n  // Wait for the setTimeout to fire and scroll to settle\n  await page.waitForTimeout(100)\n}\n\nasync function scrollElementSmoothTo(element: Locator, targetY: number) {\n  // Same as smoothScrollTo but for a specific element\n  await element.evaluate((el, top) => {\n    const current = el.scrollTop\n    el.scrollTo(0, current + (top - current) / 2)\n    setTimeout(() => el.scrollTo(0, top), 10)\n  }, targetY)\n\n  // Wait for the setTimeout to fire and scroll to settle\n  await element.page().waitForTimeout(100)\n}\n\nasync function scrollElementToBottom(element: Locator) {\n  const height = await element.evaluate((el) => el.scrollHeight)\n\n  return scrollElementSmoothTo(element, height)\n}\n\nasync function getUserIdsFromDOM(page: Page) {\n  const userCards = await page.locator('[data-user-id]').all()\n  const userIds = []\n\n  for (const card of userCards) {\n    const userId = await card.getAttribute('data-user-id')\n    userIds.push(parseInt(userId || '0'))\n  }\n\n  return userIds\n}\n\n// Helper function to check URL updates\nasync function expectQueryString(page: Page, expectedPage: string) {\n  if (expectedPage === '1') {\n    // Page 1 removes the page param entirely\n    await page.waitForFunction(() => !window.location.search.includes('page='), {}, { timeout: 1000 })\n    const currentUrl = await page.url()\n    expect(currentUrl).not.toContain('page=')\n  } else {\n    // Other pages should have explicit page param\n    await page.waitForFunction((pageNum: string) => window.location.search.includes(`page=${pageNum}`), expectedPage, {\n      timeout: 1000,\n    })\n    const currentUrl = await page.url()\n    expect(currentUrl).toContain(`page=${expectedPage}`)\n  }\n}\n\nasync function getUserCardPosition(page: Page, id: string) {\n  const userCard = page.getByText(`User ${id}`)\n  await expect(userCard).toBeVisible()\n\n  const boundingBox = await userCard.boundingBox()\n\n  if (!boundingBox) {\n    throw new Error(`Could not find bounding box for User ${id}`)\n  }\n\n  const scrollY = await page.evaluate(() => window.scrollY)\n  const viewportHeight = await page.evaluate(() => window.innerHeight)\n\n  return {\n    top: boundingBox.y + scrollY,\n    bottom: boundingBox.y + boundingBox.height + scrollY,\n    viewportTop: boundingBox.y,\n    viewportBottom: boundingBox.y + boundingBox.height,\n    relativeToViewport: boundingBox.y / viewportHeight,\n  }\n}\n\nasync function getUserCardPositionInContainer(page: Page, container: Locator, id: string) {\n  const userCard = page.getByText(`User ${id}`)\n  await expect(userCard).toBeVisible()\n\n  const containerBox = await container.boundingBox()\n  const userBox = await userCard.boundingBox()\n\n  if (!containerBox || !userBox) {\n    throw new Error(`Could not find bounding box for container or User ${id}`)\n  }\n\n  const containerScrollTop = await container.evaluate((el) => el.scrollTop)\n  const containerHeight = await container.evaluate((el) => el.clientHeight)\n\n  const relativeTop = userBox.y - containerBox.y + containerScrollTop\n  const relativeBottom = relativeTop + userBox.height\n\n  return {\n    top: relativeTop,\n    bottom: relativeBottom,\n    viewportTop: userBox.y - containerBox.y,\n    viewportBottom: userBox.y + userBox.height - containerBox.y,\n    relativeToContainer: (userBox.y - containerBox.y) / containerHeight,\n  }\n}\n\ntest.describe('Automatic page loading', () => {\n  test('it loads the next page when scrolling to the bottom', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/trigger-both')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n\n    const pageHeight = await page.evaluate(() => document.body.scrollHeight)\n\n    // Scroll to middle of page to check we're not loading the next page yet\n    await page.evaluate((height) => window.scrollTo(0, height / 2), pageHeight)\n\n    await expect(infiniteScrollRequests().length).toBe(0)\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeHidden()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    // Scroll to the bottom of the page to trigger loading the next page\n    await scrollToBottom(page)\n\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(2)\n\n    // Scroll to the bottom of the page - should NOT trigger loading since User 40 is the last one\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeHidden()\n    await expect(infiniteScrollRequests().length).toBe(2) // Should still be 2, no additional request\n\n    // Check if the data-infinite-scroll attribute is set correctly\n    const user1 = await page.locator('[data-user-id=\"1\"]')\n    const user15 = await page.locator('[data-user-id=\"15\"]')\n    const user16 = await page.locator('[data-user-id=\"16\"]')\n    const user30 = await page.locator('[data-user-id=\"30\"]')\n    const user31 = await page.locator('[data-user-id=\"31\"]')\n    const user40 = await page.locator('[data-user-id=\"40\"]')\n\n    await expect(user1).toHaveAttribute('data-infinite-scroll-page', '1')\n    await expect(user15).toHaveAttribute('data-infinite-scroll-page', '1')\n    await expect(user16).toHaveAttribute('data-infinite-scroll-page', '2')\n    await expect(user30).toHaveAttribute('data-infinite-scroll-page', '2')\n    await expect(user31).toHaveAttribute('data-infinite-scroll-page', '3')\n    await expect(user40).toHaveAttribute('data-infinite-scroll-page', '3')\n  })\n\n  test('it loads the previous page when scrolling to the top', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/trigger-both?page=3')\n\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeHidden()\n\n    // It automatically loads page 2 because the start trigger is visible\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 15')).toBeHidden()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    // Scroll to the top - 500px to make sure we don't trigger the previous page yet\n    await page.evaluate(() => window.scrollTo(0, 500))\n\n    await expect(infiniteScrollRequests().length).toBe(1) // Should still be 1, no additional request\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    // Scroll to the top to trigger loading the first\n    await scrollToTop(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n  })\n\n  test('it loads pages in reverse order when reverse mode is enabled', async ({ page }) => {\n    test.setTimeout(10_000)\n    requests.listen(page)\n    await page.goto('/infinite-scroll/reverse')\n\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('User 26')).toBeVisible()\n    await expect(page.getByText('User 25')).toBeHidden()\n\n    // It automatically loads page 2 because the start trigger is visible\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await expect(page.getByText('User 25')).toBeVisible()\n    await expect(page.getByText('User 11')).toBeVisible()\n    await expect(page.getByText('User 10')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    // Scroll to the top to trigger loading the last page\n    await scrollToTop(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await expect(page.getByText('User 10')).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(2)\n\n    // Check if the data-infinite-scroll attribute is set correctly\n    const user1 = await page.locator('[data-user-id=\"1\"]')\n    const user10 = await page.locator('[data-user-id=\"10\"]')\n    const user11 = await page.locator('[data-user-id=\"11\"]')\n    const user25 = await page.locator('[data-user-id=\"25\"]')\n    const user26 = await page.locator('[data-user-id=\"26\"]')\n    const user40 = await page.locator('[data-user-id=\"40\"]')\n\n    await expect(user1).toHaveAttribute('data-infinite-scroll-page', '3')\n    await expect(user10).toHaveAttribute('data-infinite-scroll-page', '3')\n    await expect(user11).toHaveAttribute('data-infinite-scroll-page', '2')\n    await expect(user25).toHaveAttribute('data-infinite-scroll-page', '2')\n    await expect(user26).toHaveAttribute('data-infinite-scroll-page', '1')\n    await expect(user40).toHaveAttribute('data-infinite-scroll-page', '1')\n  })\n\n  test('it loads pages until viewport is filled when individual pages are short', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/short-content') // 5 items per page\n\n    // It loads enough pages to fill the viewport\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 5')).toBeVisible()\n    await expect(page.getByText('User 10')).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 20')).toBeVisible()\n\n    await page.waitForTimeout(500)\n    await expect(page.getByText('User 25')).not.toBeVisible()\n  })\n\n  test('it does not load all pages in reverse mode when content is shorter than the scroll container', async ({\n    page,\n  }) => {\n    await page.setViewportSize({ width: 1280, height: 720 })\n    requests.listen(page)\n    await page.goto('/infinite-scroll/reverse-short-content') // 40 users, 5 per page, DESC = 8 pages\n\n    const container = page.locator('[data-testid=\"scroll-container\"]')\n    await expect(container).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n\n    // Wait for enough pages to load to fill the scroll container\n    await expect.poll(() => container.evaluate((el) => el.scrollHeight > el.clientHeight)).toBe(true)\n\n    await page.waitForTimeout(500)\n\n    // There are 8 pages total (40 items, 5 per page). The component should load\n    // enough pages to fill the scroll container, but not all of them.\n    expect(infiniteScrollRequests().length).toBeLessThan(7)\n\n    // The oldest users (last page) should NOT have been loaded\n    await expect(page.getByText('User 1', { exact: true })).not.toBeVisible()\n    await expect(page.getByText('User 5', { exact: true })).not.toBeVisible()\n  })\n\n  test('it handles dual scroll containers with separate data props and page query parameters', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/dual-containers')\n\n    // Get both scroll containers\n    const container1 = page.locator('[data-testid=\"scroll-container-1\"]')\n    const container2 = page.locator('[data-testid=\"scroll-container-2\"]')\n\n    await expect(container1).toBeVisible()\n    await expect(container2).toBeVisible()\n\n    // Initially both containers should show their first pages\n    await expect(container1.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(container1.getByText('User 15')).toBeVisible()\n    await expect(container1.getByText('User 16')).toBeHidden()\n    await expect(container2.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(container2.getByText('User 15')).toBeVisible()\n    await expect(container2.getByText('User 16')).toBeHidden()\n\n    // No query parameters should be present initially\n    expect(page.url()).not.toContain('users1=')\n    expect(page.url()).not.toContain('users2=')\n\n    // Scroll first container to load page 2 of users1\n    await scrollElementSmoothTo(container1, 10000)\n\n    await expect(container1.getByText('User 16')).toBeVisible()\n    await expect(container1.getByText('User 30')).toBeVisible()\n    await expect(container1.getByText('User 31')).toBeHidden()\n    await expect(container2.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(container2.getByText('User 15')).toBeVisible()\n    await expect(container2.getByText('User 16')).toBeHidden()\n\n    // Scroll to bottom of first container to check URL synchronization\n    const currentHeightContainer1 = await container1.evaluate((container) => container.scrollHeight)\n    await scrollElementSmoothTo(container1, currentHeightContainer1 - 500)\n    await page.waitForFunction(\n      () => window.location.search.includes('users1=2'),\n      {},\n      {\n        timeout: 1000,\n      },\n    )\n\n    // expect ?users1=2 in URL, but not users2\n    expect(page.url()).toContain('users1=2')\n    expect(page.url()).not.toContain('users2=')\n\n    // Scroll second container to load page 2 of users2\n    await scrollElementToBottom(container2)\n\n    await expect(container1.getByText('User 16')).toBeVisible()\n    await expect(container1.getByText('User 30')).toBeVisible()\n    await expect(container1.getByText('User 31')).toBeHidden()\n    await expect(container2.getByText('User 16')).toBeVisible()\n    await expect(container2.getByText('User 30')).toBeVisible()\n    await expect(container2.getByText('User 31')).toBeHidden()\n\n    // Scroll to bottom of second container to check URL synchronization\n    const currentHeightContainer2 = await container2.evaluate((container) => container.scrollHeight)\n    await scrollElementSmoothTo(container2, currentHeightContainer2 - 500)\n    await page.waitForFunction(\n      () => window.location.search.includes('users2=2'),\n      {},\n      {\n        timeout: 1000,\n      },\n    )\n\n    // expect both ?users1=2 and users2=2 in URL\n    expect(page.url()).toContain('users1=2')\n    expect(page.url()).toContain('users2=2')\n  })\n\n  test('it handles dual sibling InfiniteScroll with manual mode and query string updates', async ({ page }) => {\n    test.setTimeout(10_000)\n    requests.listen(page)\n    await page.goto('/infinite-scroll/dual-sibling')\n\n    await expect(page.getByText('User 1', { exact: true }).first()).toBeVisible()\n    await expect(page.getByText('User 15').first()).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true }).last()).toBeVisible()\n    await expect(page.getByText('User 15').last()).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n\n    await page.getByRole('button', { name: 'Load More Users 1' }).click()\n    await expect(page.getByText('User 16').first()).toBeVisible()\n    await expect(page.getByText('User 30').first()).toBeVisible()\n\n    await page.getByRole('button', { name: 'Load More Users 2' }).click()\n    await expect(page.getByText('User 16').last()).toBeVisible()\n    await expect(page.getByText('User 30').last()).toBeVisible()\n\n    await expect(page.getByText('User 31')).toBeHidden()\n\n    await scrollToBottom(page)\n    await page.waitForFunction(\n      () => window.location.search.includes('users1=2') && window.location.search.includes('users2=2'),\n      {},\n      { timeout: 1000 },\n    )\n    expect(page.url()).toContain('users1=2')\n    expect(page.url()).toContain('users2=2')\n\n    await scrollToTop(page)\n    await page.waitForFunction(\n      () => !window.location.search.includes('users1=') && !window.location.search.includes('users2='),\n      {},\n      { timeout: 1000 },\n    )\n    expect(page.url()).not.toContain('users1=')\n    expect(page.url()).not.toContain('users2=')\n  })\n})\n\ntest.describe('Manual page loading', () => {\n  test('it allows manual loading of next and previous pages when manual mode is enabled', async ({ page }) => {\n    test.setTimeout(10_000)\n    await page.goto('/infinite-scroll/manual?page=2')\n\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 15')).toBeHidden()\n    await expect(page.getByText('User 31')).toBeHidden()\n    await expect(page.getByText('Has more previous items: true')).toBeVisible()\n    await expect(page.getByText('Has more next items: true')).toBeVisible()\n\n    requests.listen(page)\n    await page.getByRole('button', { name: 'Load previous items' }).click()\n    await expect(page.getByText('Loading previous items...')).toBeVisible()\n    await expect(page.getByText('Loading next items...')).toBeHidden()\n\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('Loading previous items...')).toBeHidden()\n    await expect(page.getByText('Has more previous items: false')).toBeVisible()\n    await expect(page.getByText('Has more next items: true')).toBeVisible()\n\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    await page.getByRole('button', { name: 'Load next items' }).click()\n    await expect(page.getByText('Loading next items...')).toBeVisible()\n    await expect(page.getByText('Loading previous items...')).toBeHidden()\n\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('Loading next items...')).toBeHidden()\n    await expect(page.getByText('Has more previous items: false')).toBeVisible()\n    await expect(page.getByText('Has more next items: false')).toBeVisible()\n\n    await expect(infiniteScrollRequests().length).toBe(2)\n  })\n\n  test('it switches to manual mode after reaching the manualAfter threshold', async ({ page }) => {\n    await page.goto('/infinite-scroll/manual-after')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n    await expect(page.getByText('Manual mode: false')).toBeVisible()\n\n    requests.listen(page)\n\n    // Scroll to the bottom of the page to trigger loading the next page\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeHidden()\n    await expect(page.getByText('Loading...')).toBeHidden()\n    await expect(page.getByText('Manual mode: false')).toBeVisible()\n\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    // Scroll to the bottom of the page to trigger loading the next page\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 45')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n    await expect(page.getByText('Manual mode: true')).toBeVisible()\n\n    await expect(infiniteScrollRequests().length).toBe(2)\n\n    // Scroll to the bottom of the page - should NOT trigger loading since we're in manual mode now\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(2) // Should still be 2, no additional request\n\n    // Load next items manually\n    await page.getByRole('button', { name: 'Load next items' }).click()\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await expect(page.getByText('User 46')).toBeVisible()\n    await expect(page.getByText('User 60')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n    await expect(page.getByText('Manual mode: true')).toBeVisible()\n\n    await expect(infiniteScrollRequests().length).toBe(3)\n  })\n\n  test('it resets pagination state after direct URL navigation', async ({ page }) => {\n    await page.goto('/infinite-scroll/manual')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n    await expect(page.getByText('Has more next items: true')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Load next items' }).click()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Load next items' }).click()\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('Has more next items: false')).toBeVisible()\n\n    await page.goto('/infinite-scroll/manual')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n    await expect(page.getByText('User 31')).toBeHidden()\n    await expect(page.getByText('Has more next items: true')).toBeVisible()\n  })\n\n  test('it does not skip pages after direct URL navigation', async ({ page }) => {\n    await page.goto('/infinite-scroll/manual')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('Has more next items: true')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Load next items' }).click()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n\n    await page.goto('/infinite-scroll/manual')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n    await expect(page.getByText('Has more next items: true')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Load next items' }).click()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeHidden()\n  })\n\n  test('it resets pagination state when navigating to a different page number', async ({ page }) => {\n    await page.goto('/infinite-scroll/manual')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('Has more previous items: false')).toBeVisible()\n    await expect(page.getByText('Has more next items: true')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Load next items' }).click()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Load next items' }).click()\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('Has more previous items: false')).toBeVisible()\n    await expect(page.getByText('Has more next items: false')).toBeVisible()\n\n    await page.goto('/infinite-scroll/manual?page=2')\n\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true })).toBeHidden()\n    await expect(page.getByText('User 15')).toBeHidden()\n    await expect(page.getByText('User 31')).toBeHidden()\n    await expect(page.getByText('Has more previous items: true')).toBeVisible()\n    await expect(page.getByText('Has more next items: true')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Load previous items' }).click()\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('Has more previous items: false')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Load next items' }).click()\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('Has more next items: false')).toBeVisible()\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 20')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n  })\n\n  test('it resets hasMore state when filtering to fewer results in manual mode', async ({ page }) => {\n    test.setTimeout(10_000)\n    requests.listen(page)\n    await page.goto('/infinite-scroll/filtering-manual')\n\n    await expect(page.getByText('Adelle Crona DVM')).toBeVisible()\n    await expect(page.getByText('Breana Herzog')).toBeVisible()\n    await expect(page.getByText('Has more next items: true')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Load next items' }).click()\n    await expect(page.getByText('Camylle Metz Sr.')).toBeVisible()\n    await expect.poll(() => infiniteScrollRequests().length).toBe(1)\n\n    await page.getByRole('button', { name: 'Load next items' }).click()\n    await expect(page.getByText('Diamond Gibson PhD')).toBeVisible()\n    await expect.poll(() => infiniteScrollRequests().length).toBe(2)\n\n    await page.locator('input[placeholder=\"Search...\"]').fill('adelle')\n    await expect(page.getByText('Adelle Crona DVM')).toBeVisible()\n    await expect(page.getByText('Current search: adelle')).toBeVisible()\n    await expect(page.getByText('Breana Herzog')).toBeHidden()\n    await expect(page.getByText('Has more next items: false')).toBeVisible()\n  })\n\n  test('it resets hasMore state when clearing search filter in manual mode', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/filtering-manual?search=adelle')\n\n    await expect(page.getByText('Adelle Crona DVM')).toBeVisible()\n    await expect(page.getByText('Current search: adelle')).toBeVisible()\n    await expect(page.getByText('Has more next items: false')).toBeVisible()\n\n    await page.locator('input[placeholder=\"Search...\"]').clear()\n    await expect(page.getByText('Current search: none')).toBeVisible()\n    await expect(page.getByText('Adelle Crona DVM')).toBeVisible()\n    await expect(page.getByText('Breana Herzog')).toBeVisible()\n    await expect(page.getByText('Has more next items: true')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Load next items' }).click()\n    await expect(page.getByText('Camylle Metz Sr.')).toBeVisible()\n    await expect(infiniteScrollRequests().length).toBeGreaterThanOrEqual(1)\n  })\n})\n\ntest.describe('Remember state', () => {\n  test('it preserves state and element tags when navigating away and back', async ({ page }) => {\n    await page.goto('/infinite-scroll/remember-state')\n\n    // Verify initial state\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n    await expect(page.getByText('Manual mode: false')).toBeVisible()\n\n    requests.listen(page)\n\n    // Load page 2\n    const page2Response = page.waitForResponse((res) => res.url().includes('/infinite-scroll/remember-state?page=2'))\n    await scrollToBottom(page)\n    await page2Response\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeHidden()\n    await expect(page.getByText('Manual mode: false')).toBeVisible()\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    // Load page 3\n    const page3Response = page.waitForResponse((res) => res.url().includes('/infinite-scroll/remember-state?page=3'))\n    await scrollToBottom(page)\n    await page3Response\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 45')).toBeVisible()\n    await expect(page.getByText('User 46')).toBeHidden()\n    await expect(page.getByText('Manual mode: true')).toBeVisible()\n    await expect(infiniteScrollRequests().length).toBe(2)\n\n    // Wait for scroll to settle after content load\n    await expect.poll(() => page.evaluate(() => window.scrollY > 0)).toBe(true)\n\n    // Navigate to home page\n    await page.getByRole('link', { name: 'Go to Home' }).click()\n    await expect(page.getByText('This is the Test App Entrypoint page')).toBeVisible()\n\n    await page.goBack()\n    await page.waitForURL(/\\/infinite-scroll\\/remember-state/)\n\n    // Verify state is restored - should show all 3 pages of content\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 45')).toBeVisible()\n    await expect(page.getByText('User 46')).toBeHidden()\n    await expect(page.getByText('Manual mode: true')).toBeVisible()\n\n    // Assert the data-infinite-scroll-page attributes are still correct\n    const user1 = page.locator('[data-user-id=\"1\"]')\n    const user15 = page.locator('[data-user-id=\"15\"]')\n    const user16 = page.locator('[data-user-id=\"16\"]')\n    const user30 = page.locator('[data-user-id=\"30\"]')\n    const user31 = page.locator('[data-user-id=\"31\"]')\n    const user45 = page.locator('[data-user-id=\"45\"]')\n\n    // Wait for InfiniteScroll to fully initialize with page attributes\n    await expect(user1).toHaveAttribute('data-infinite-scroll-page', '1')\n    await expect(user15).toHaveAttribute('data-infinite-scroll-page', '1')\n    await expect(user16).toHaveAttribute('data-infinite-scroll-page', '2')\n    await expect(user30).toHaveAttribute('data-infinite-scroll-page', '2')\n    await expect(user31).toHaveAttribute('data-infinite-scroll-page', '3')\n    await expect(user45).toHaveAttribute('data-infinite-scroll-page', '3')\n\n    // Verify URL synchronization works after restoration\n    await scrollToTop(page)\n    await expectQueryString(page, '1')\n\n    const pageHeight = await page.evaluate(() => document.body.scrollHeight)\n    await smoothScrollTo(page, pageHeight * 0.9)\n    await expectQueryString(page, '3')\n\n    // Test that load more button works for page 4\n    requests.requests = [] // Reset request tracking\n    await scrollToBottom(page)\n    await page.getByRole('button', { name: 'Load next items' }).click()\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 46')).toBeVisible()\n    await expect(page.getByText('User 60')).toBeVisible()\n    await expect(page.getByText('Manual mode: true')).toBeVisible()\n    await expect(infiniteScrollRequests().length).toBe(1)\n  })\n\n  test('it resets to page 1 after browser refresh', async ({ page }) => {\n    await page.goto('/infinite-scroll/remember-state')\n\n    // Verify initial state\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n    await expect(page.getByText('Manual mode: false')).toBeVisible()\n\n    requests.listen(page)\n\n    // Load page 2 (auto mode)\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeHidden()\n    await expect(page.getByText('Manual mode: false')).toBeVisible()\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    // Load page 3 (this is the 2nd request, which triggers manual mode)\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 45')).toBeVisible()\n    await expect(page.getByText('User 46')).toBeHidden()\n    await expect(page.getByText('Manual mode: true')).toBeVisible()\n    await expect(infiniteScrollRequests().length).toBe(2)\n\n    // Verify we can see all content (pages 1-3)\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 45')).toBeVisible()\n\n    // Scroll to top to make page 1 visible and clear the page parameter\n    await scrollToTop(page)\n    await expectQueryString(page, '1') // This waits for the URL to clear\n\n    // Refresh the browser\n    await page.reload()\n\n    // Verify we're back to page 1 with only initial 15 items\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n    await expect(page.getByText('User 30')).toBeHidden()\n    await expect(page.getByText('User 31')).toBeHidden()\n    await expect(page.getByText('User 45')).toBeHidden()\n\n    // Verify we're back to initial state (not manual mode)\n    await expect(page.getByText('Manual mode: false')).toBeVisible()\n\n    // Verify no page param in URL\n    expect(page.url()).not.toContain('page=')\n  })\n\n  test('it preserves prepended items when navigating away and back', async ({ page }) => {\n    await page.goto('/infinite-scroll/remember-state')\n\n    // Page 1 should be loaded\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n    await expect(page.getByText('Manual mode: false')).toBeVisible()\n\n    requests.listen(page)\n\n    // Scroll to bottom to load page 2\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeHidden()\n    await expect(page.getByText('Loading...')).toBeHidden()\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    scrollToTop(page)\n\n    // Prepend two users: User 0 and User -1\n    await page.getByRole('button', { name: \"Prepend User '0'\" }).click()\n    await page.getByRole('button', { name: \"Prepend User '-1'\" }).click()\n\n    // Verify prepended users are visible\n    await expect(page.getByText('User 0')).toBeVisible()\n    await expect(page.getByText('User -1')).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n\n    await page.waitForTimeout(250)\n\n    // Navigate to home page\n    await page.getByRole('link', { name: 'Go Home' }).click()\n    await expect(page.getByText('This is the Test App Entrypoint page')).toBeVisible()\n\n    // Navigate back\n    await page.goBack()\n\n    // Verify the users we prepended are still there along with pages 1 and 2 content\n    await expect(page.getByText('User -1')).toBeVisible()\n    await expect(page.getByText('User 0')).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeHidden()\n\n    // Verify the dataset attributes are correctly assigned\n    // Users -1 and 0 should be part of page 1\n    const userMinus1 = await page.locator('[data-user-id=\"-1\"]')\n    const user0 = await page.locator('[data-user-id=\"0\"]')\n    const user1 = await page.locator('[data-user-id=\"1\"]')\n    const user15 = await page.locator('[data-user-id=\"15\"]')\n    const user16 = await page.locator('[data-user-id=\"16\"]')\n    const user30 = await page.locator('[data-user-id=\"30\"]')\n\n    await expect(userMinus1).toHaveAttribute('data-infinite-scroll-ignore', 'true')\n    await expect(userMinus1).not.toHaveAttribute('data-infinite-scroll-page')\n    await expect(user0).toHaveAttribute('data-infinite-scroll-ignore', 'true')\n    await expect(user0).not.toHaveAttribute('data-infinite-scroll-page')\n\n    await expect(user1).toHaveAttribute('data-infinite-scroll-page', '1')\n    await expect(user15).toHaveAttribute('data-infinite-scroll-page', '1')\n    await expect(user16).toHaveAttribute('data-infinite-scroll-page', '2')\n    await expect(user30).toHaveAttribute('data-infinite-scroll-page', '2')\n\n    // Scroll to bottom to load page 3\n    requests.requests = [] // Reset request tracking\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 45')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    // Verify page 3 loaded correctly\n    const user31 = await page.locator('[data-user-id=\"31\"]')\n    const user45 = await page.locator('[data-user-id=\"45\"]')\n    await expect(user31).toHaveAttribute('data-infinite-scroll-page', '3')\n    await expect(user45).toHaveAttribute('data-infinite-scroll-page', '3')\n\n    await scrollToBottom(page)\n    await expectQueryString(page, '3')\n  })\n\n  test('it handles starting on page 2, loading pages, refresh, and dataset verification', async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName === 'firefox', 'Firefox has a different scroll position after reload behavior')\n    await page.goto('/infinite-scroll/remember-state?page=2')\n\n    requests.listen(page)\n\n    // Should see page 1 content first, then load page 2\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeHidden()\n    await expect(page.getByText('Manual mode: false')).toBeVisible()\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    // Scroll to bottom to load page 3\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 45')).toBeVisible()\n    await expect(page.getByText('User 46')).toBeHidden()\n    await expect(page.getByText('Manual mode: true')).toBeVisible()\n    await expect(infiniteScrollRequests().length).toBe(2)\n\n    // Scroll to middle to trigger page 2 URL\n    const pageHeight = await page.evaluate(() => document.body.scrollHeight)\n    await smoothScrollTo(page, pageHeight * 0.5)\n    await expectQueryString(page, '2')\n\n    await page.reload()\n\n    // After refresh on ?page=2, loads page 2 content AND loads page 3 automatically (because of scroll position)\n    await expect(page.getByText('User 1', { exact: true })).toBeHidden()\n    await expect(page.getByText('User 15')).toBeHidden()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 45')).toBeVisible()\n    await expect(page.getByText('Manual mode: false')).toBeVisible()\n    expect(page.url()).toContain('page=2')\n\n    // Verify dataset tags for existing elements (pages 2+3 are present)\n    const user16 = await page.locator('[data-user-id=\"16\"]')\n    const user30 = await page.locator('[data-user-id=\"30\"]')\n    const user31 = await page.locator('[data-user-id=\"31\"]')\n    const user45 = await page.locator('[data-user-id=\"45\"]')\n\n    // Check that restored elements have correct page tags\n    await expect(user16).toHaveAttribute('data-infinite-scroll-page', '2')\n    await expect(user30).toHaveAttribute('data-infinite-scroll-page', '2')\n    await expect(user31).toHaveAttribute('data-infinite-scroll-page', '3')\n    await expect(user45).toHaveAttribute('data-infinite-scroll-page', '3')\n\n    // scroll to top, load page 1\n    await scrollToTop(page)\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('Manual mode: true')).toBeVisible() // two requests have been made\n\n    const user1 = await page.locator('[data-user-id=\"1\"]')\n    const user15 = await page.locator('[data-user-id=\"15\"]')\n\n    await expect(user1).toHaveAttribute('data-infinite-scroll-page', '1')\n    await expect(user15).toHaveAttribute('data-infinite-scroll-page', '1')\n  })\n})\n\ntest.describe('Toggle configuration', () => {\n  test('it toggles between automatic and manual loading when manual prop changes', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/toggles')\n\n    // Initially manual is false, should auto-load pages\n    await expect(page.getByText('Manual mode: false')).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n    await expect(page.getByText('Total items on page: 15')).toBeVisible()\n\n    await scrollToBottom(page)\n\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeHidden()\n    await expect(page.getByText('Total items on page: 30')).toBeVisible()\n\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    // Enable manual mode\n    await page.getByLabel('Manual mode: false').check()\n    await expect(page.getByText('Manual mode: true')).toBeVisible()\n\n    // Scroll to bottom again - should NOT auto-load page 3 in manual mode\n    await scrollToBottom(page)\n    await page.waitForTimeout(500)\n\n    await expect(page.getByText('Loading...')).toBeHidden()\n    await expect(page.getByText('User 31')).toBeHidden()\n    await expect(page.getByText('Total items on page: 30')).toBeVisible()\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    // Scroll to top, disable manual mode again\n    await scrollToTop(page)\n    await page.getByLabel('Manual mode: true').uncheck()\n    await expect(page.getByText('Manual mode: false')).toBeVisible()\n\n    // Scroll to bottom - should auto-load page 3 now\n    await scrollToBottom(page)\n\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('Total items on page: 40')).toBeVisible()\n\n    await expect(infiniteScrollRequests().length).toBe(2)\n  })\n\n  test('it toggles between different trigger directions when trigger prop changes', async ({ page }) => {\n    requests.listen(page)\n\n    // Start on page 2 with triggerMode='onlyNext' (default), change to triggerMode='onlyPrevious' to auto-load page 1\n    await page.goto('/infinite-scroll/toggles?page=2')\n\n    await expect(page.getByText('Trigger mode: onlyNext')).toBeVisible()\n    await page.selectOption('select', 'onlyPrevious')\n    await expect(page.getByText('Trigger mode: onlyPrevious')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('Total items on page: 30')).toBeVisible()\n\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    // Verify User 31 is not loaded yet\n    await expect(page.getByText('User 31')).toBeHidden()\n\n    // Scroll to bottom - should NOT load page 3 since triggerMode='onlyPrevious'\n    await scrollToBottom(page)\n    await page.waitForTimeout(500)\n\n    await expect(page.getByText('User 31')).toBeHidden()\n    await expect(page.getByText('Total items on page: 30')).toBeVisible()\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    // Scroll to top, change triggerMode to 'onlyNext' (loads next pages)\n    await scrollToTop(page)\n    await page.selectOption('select', 'onlyNext')\n    await expect(page.getByText('Trigger mode: onlyNext')).toBeVisible()\n\n    // Scroll to bottom - should now load page 3 since triggerMode='onlyNext'\n    await scrollToBottom(page)\n\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('Total items on page: 40')).toBeVisible()\n    await expect(infiniteScrollRequests().length).toBe(2)\n  })\n\n  test('it toggles between preserving and not preserving URL when preserveUrl prop changes', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/toggles')\n\n    await expect(page.getByText('Preserve URL: false')).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n    await expect(page.getByText('Total items on page: 15')).toBeVisible()\n\n    // Load page 2 and scroll to make it the most visible page\n    await scrollToBottom(page)\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('Total items on page: 30')).toBeVisible()\n\n    // Scroll to page 2 content area to trigger URL update\n    await page.getByText('User 20').scrollIntoViewIfNeeded()\n    await expectQueryString(page, '2')\n    await expect(infiniteScrollRequests().length).toBeGreaterThanOrEqual(1)\n\n    // Enable preserveUrl mode - URL should no longer update\n    await page.getByLabel('Preserve URL: false').check()\n    await expect(page.getByText('Preserve URL: true')).toBeVisible()\n\n    // Load page 3 and scroll to bottom\n    await scrollToBottom(page)\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('Total items on page: 40')).toBeVisible()\n\n    // URL should still show page=2\n    await page.waitForTimeout(500)\n    expect(page.url()).toContain('page=2')\n    await expect(infiniteScrollRequests().length).toBeGreaterThanOrEqual(2)\n\n    // Disable preserveUrl again\n    await page.getByLabel('Preserve URL: true').uncheck()\n    await expect(page.getByText('Preserve URL: false')).toBeVisible()\n\n    // Scroll to page 3 content area to trigger URL update\n    await page.getByText('User 35').scrollIntoViewIfNeeded()\n    await expectQueryString(page, '3')\n  })\n})\n\ntest.describe('Buffer margin configuration', () => {\n  test('it loads the next page early when buffer margin is configured', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/trigger-end-buffer')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n\n    // Scroll close to bottom but not all the way - the buffer should trigger loading earlier\n    // With buffer=200, it should trigger when the end element is 200px into the viewport\n    const pageHeight = await page.evaluate(() => document.body.scrollHeight)\n    const viewportHeight = await page.evaluate(() => window.innerHeight)\n\n    // Scroll to a position that's close to the bottom but leaves more than 200px\n    // This should NOT trigger loading yet (without buffer, we'd need to be closer)\n    const scrollPosition = pageHeight - viewportHeight - 300 // 300px from bottom\n    await page.evaluate((pos) => window.scrollTo(0, pos), scrollPosition)\n\n    // Should not have triggered loading yet\n    await expect(infiniteScrollRequests().length).toBe(0)\n    await expect(page.getByText('User 16')).toBeHidden()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    // Now scroll to a position that's within the buffer zone (less than 200px from bottom)\n    // This should trigger loading due to the buffer\n    const bufferScrollPosition = pageHeight - viewportHeight - 150 // 150px from bottom\n    await page.evaluate((pos) => window.scrollTo(0, pos), bufferScrollPosition)\n\n    // Should trigger loading due to buffer\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(1)\n  })\n\n  test('it loads the previous page early when buffer margin is configured', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/trigger-start-buffer?page=3')\n\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeHidden()\n\n    // It automatically loads page 2 because the start trigger is visible\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 15')).toBeHidden()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    // Scroll close to top but not all the way - the buffer should trigger loading earlier\n    // With buffer=200, it should trigger when the start element is 200px into the viewport\n\n    // Scroll to a position that's close to the top but leaves more than 200px\n    // This should NOT trigger loading yet (without buffer, we'd need to be closer)\n    await page.evaluate(() => window.scrollTo(0, 300)) // 300px from top\n\n    // Should not have triggered loading yet\n    await expect(infiniteScrollRequests().length).toBe(1) // Still just the initial load\n    await expect(page.getByText('User 15')).toBeHidden()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    // Now scroll to a position that's within the buffer zone (less than 200px from top)\n    // This should trigger loading due to the buffer\n    await page.evaluate(() => window.scrollTo(0, 150)) // 150px from top\n\n    // Should trigger loading due to buffer\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(2)\n  })\n})\n\ntest.describe('Directional trigger constraints', () => {\n  test('it only loads previous pages when trigger is set to start', async ({ page }) => {\n    requests.listen(page)\n    // Start on page 2 to verify page 1 auto-loads due to visible start trigger\n    await page.goto('/infinite-scroll/trigger-start-buffer?page=2')\n\n    // Initially page 2 should be visible\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeHidden()\n\n    // Page 1 should auto-load because the start trigger is visible\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    // Should have made 1 request to load page 1\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    // Now scroll to the bottom - should NOT trigger loading page 3 since trigger=start\n    await scrollToBottom(page)\n    await page.waitForTimeout(500)\n    await expect(page.getByText('Loading...')).toBeHidden()\n    await expect(page.getByText('User 31')).toBeHidden()\n    // Should still be 1 request (only the initial auto-load of page 1)\n    await expect(infiniteScrollRequests().length).toBe(1)\n  })\n\n  test('it only loads next pages when trigger is set to end', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/trigger-end-buffer?page=2')\n\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 15')).toBeHidden()\n\n    // Scroll to the top of the page - should NOT trigger loading since trigger=end\n    await scrollToTop(page)\n    await page.waitForTimeout(500)\n    await expect(page.getByText('Loading...')).toBeHidden()\n    await expect(page.getByText('User 15')).toBeHidden()\n    await expect(infiniteScrollRequests().length).toBe(0)\n  })\n\n  test('it loads pages in both directions when trigger is set to both', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/trigger-both?page=2')\n\n    // Initially, page 2 should be visible\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeHidden()\n\n    // It automatically loads page 1 because the start trigger is visible\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    // Scroll to bottom to trigger loading page 3\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n    await expect(infiniteScrollRequests().length).toBe(2)\n\n    // Verify all three pages are now loaded (users 1-40)\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible() // Page 1\n    await expect(page.getByText('User 15')).toBeVisible() // Page 1\n    await expect(page.getByText('User 16')).toBeVisible() // Page 2\n    await expect(page.getByText('User 30')).toBeVisible() // Page 2\n    await expect(page.getByText('User 31')).toBeVisible() // Page 3\n    await expect(page.getByText('User 40')).toBeVisible() // Page 3\n  })\n})\n\ntest.describe('DOM element ordering', () => {\n  test('it maintains correct DOM element order when pages load out of sequence', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/trigger-both?page=2')\n\n    // Initially, page 2 should be visible\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n\n    // It automatically loads page 1 because the start trigger is visible\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    // Scroll to bottom to trigger loading page 3\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    // Get all user cards and check their order in the DOM\n    const userIds = await getUserIdsFromDOM(page)\n\n    // Verify the DOM order: should start with user 1, have user 20 somewhere in middle, end with user 40\n    expect(userIds[0]).toBe(1) // First user should be User 1\n    expect(userIds.includes(20)).toBe(true) // User 20 should be present (middle of page 2)\n    expect(userIds[userIds.length - 1]).toBe(40) // Last user should be User 40\n\n    // Verify all users from pages 1-3 are present (users 1-40) and in ascending order\n    expect(userIds).toEqual(Array.from({ length: 40 }, (_, i) => i + 1))\n  })\n\n  test('it maintains correct DOM element order in reverse pagination mode', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/reverse?page=2')\n\n    // Initially, page 2 should be visible (users 11-25 in reverse mode)\n    await expect(page.getByText('User 11')).toBeVisible()\n    await expect(page.getByText('User 25')).toBeVisible()\n\n    // It automatically loads page 3 because the start trigger is visible (users 1-10)\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 10')).toBeVisible()\n\n    // Scroll to bottom to trigger loading page 1 (users 26-40)\n    const page1Response = page.waitForResponse((res) => res.url().includes('/infinite-scroll/reverse?page=1'))\n    await scrollToBottom(page)\n    await page1Response\n    await expect(page.getByText('User 26')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n\n    // Get all user cards and check their order in the DOM\n    const userIds = await getUserIdsFromDOM(page)\n\n    // In reverse mode, DOM order should still be 1-40 (logical order maintained)\n    expect(userIds[0]).toBe(1) // First user should be User 1\n    expect(userIds.includes(20)).toBe(true) // User 20 should be present (middle of page 2)\n    expect(userIds[userIds.length - 1]).toBe(40) // Last user should be User 40\n\n    // Verify all users from pages 1-3 are present (users 1-40) and in ascending order\n    expect(userIds).toEqual(Array.from({ length: 40 }, (_, i) => i + 1))\n  })\n})\n\ntest.describe('Component customization', () => {\n  test('it renders as a custom HTML element when using the as prop', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/custom-element')\n\n    // Verify the InfiniteScroll component renders as a section element\n    const container = await page.locator('section[data-testid=\"infinite-scroll-container\"]')\n    await expect(container).toBeVisible()\n\n    // Verify it still functions as infinite scroll\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n\n    // Scroll to trigger loading next page\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n  })\n})\n\ntest.describe('URL query string management', () => {\n  test('it assigns page tracking attributes to dynamically loaded items', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/update-query-string')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n\n    // Scroll to bottom to load page 2\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    // Scroll to bottom again to load page 3\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    // Verify data attributes are set correctly for infinite scroll\n    const dataAttrs = await page.evaluate(() => {\n      const elements = Array.from(document.querySelectorAll('[data-user-id]'))\n      return elements.map((el) => ({\n        userId: parseInt(el.getAttribute('data-user-id') || '0'),\n        infiniteScrollPage: el.getAttribute('data-infinite-scroll-page'),\n      }))\n    })\n\n    // Verify that we have elements from all 3 pages with correct page attributes\n    const page1Elements = dataAttrs.filter((el) => el.infiniteScrollPage === '1')\n    const page2Elements = dataAttrs.filter((el) => el.infiniteScrollPage === '2')\n    const page3Elements = dataAttrs.filter((el) => el.infiniteScrollPage === '3')\n\n    expect(page1Elements.length).toBe(15) // Users 1-15\n    expect(page2Elements.length).toBe(15) // Users 16-30\n    expect(page3Elements.length).toBe(10) // Users 31-40\n\n    // Verify the page attributes are assigned to the correct user IDs\n    expect(page1Elements.every((el) => el.userId >= 1 && el.userId <= 15)).toBe(true)\n    expect(page2Elements.every((el) => el.userId >= 16 && el.userId <= 30)).toBe(true)\n    expect(page3Elements.every((el) => el.userId >= 31 && el.userId <= 40)).toBe(true)\n  })\n\n  test('it updates the URL to reflect the most visible page during scrolling', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/update-query-string')\n\n    // Initially should be on page 1 (no page param means page 1)\n    expect(page.url()).not.toContain('page=')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n\n    // Scroll to bottom to load page 2\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    // Scroll to bottom again to load page 3\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    const pageHeight = await page.evaluate(() => document.body.scrollHeight)\n\n    // Test URL updates at different scroll positions using smooth scrolling\n    await smoothScrollTo(page, 0)\n    await expectQueryString(page, '1')\n\n    await smoothScrollTo(page, Math.floor(pageHeight / 2))\n    await expectQueryString(page, '2')\n\n    await smoothScrollTo(page, pageHeight)\n    await expectQueryString(page, '3')\n\n    await smoothScrollTo(page, Math.floor(pageHeight / 2))\n    await expectQueryString(page, '2')\n\n    await smoothScrollTo(page, 0)\n    await expectQueryString(page, '1')\n\n    await smoothScrollTo(page, pageHeight)\n    await expectQueryString(page, '3')\n  })\n\n  test('it preserves the original URL when preserveUrl is enabled', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/preserve-url?page=2')\n\n    // Initially should be on page 2 and URL should be preserved\n    expect(page.url()).toContain('page=2')\n\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n\n    // Wait for page 1 to auto-load (trigger=both behavior)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    // Scroll to bottom to load page 3\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    const pageHeight = await page.evaluate(() => document.body.scrollHeight)\n\n    // Test multiple scroll positions - URL should never change from page=2\n    await smoothScrollTo(page, 0) // Top\n    await page.waitForTimeout(250) // Wait for debounce\n    expect(page.url()).toContain('page=2')\n\n    await smoothScrollTo(page, Math.floor(pageHeight / 2)) // Middle\n    await page.waitForTimeout(250)\n    expect(page.url()).toContain('page=2')\n\n    await smoothScrollTo(page, pageHeight) // Bottom\n    await page.waitForTimeout(250)\n    expect(page.url()).toContain('page=2')\n\n    await smoothScrollTo(page, 0) // Back to top\n    await page.waitForTimeout(250)\n    expect(page.url()).toContain('page=2')\n  })\n\n  test('it preserves relative URL format when updating query string', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/update-query-string')\n\n    // Verify we start with a relative URL\n    const initialUrl = await page.evaluate(() => window.testing.pageUrl)\n    expect(initialUrl).toBe('/infinite-scroll/update-query-string')\n    expect(initialUrl).not.toContain('http')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    // Scroll to User 20 area (middle of page 2) to trigger URL update to page=2\n    const user20 = page.getByText('User 20')\n    await user20.scrollIntoViewIfNeeded()\n    await expectQueryString(page, '2')\n\n    // Verify the internal Inertia page URL is still relative\n    const updatedUrl = await page.evaluate(() => window.testing.pageUrl)\n    expect(updatedUrl).toContain('page=2')\n    expect(updatedUrl).not.toContain('http')\n    expect(updatedUrl).toMatch(/^\\/infinite-scroll/)\n  })\n\n  test('it preserves absolute URL format when updating query string', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/update-query-string?absolutePageUrl=1')\n\n    // Verify we start with an absolute URL\n    const initialUrl = await page.evaluate(() => window.testing.pageUrl)\n    expect(initialUrl).toContain('http://localhost')\n    expect(initialUrl).toContain('/infinite-scroll/update-query-string')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    // Scroll to User 20 area (middle of page 2) to trigger URL update to page=2\n    const user20 = page.getByText('User 20')\n    await user20.scrollIntoViewIfNeeded()\n    await expectQueryString(page, '2')\n\n    // Verify the internal Inertia page URL is still absolute\n    const updatedUrl = await page.evaluate(() => window.testing.pageUrl)\n    expect(updatedUrl).toContain('page=2')\n    expect(updatedUrl).toContain('http://localhost')\n    expect(updatedUrl).toContain('/infinite-scroll/update-query-string')\n  })\n})\n\ntest.describe('Scroll position preservation', () => {\n  test('it maintains scroll position when loading previous pages', async ({ page }) => {\n    await page.goto('/infinite-scroll/trigger-both?page=3')\n\n    // Wait for page 2 to load...\n    await expect(page.getByText('User 16')).toBeVisible()\n\n    // Scroll to the top of the page to load page 1\n    await scrollToTop(page)\n\n    // Wait for loading to start so we capture a stable \"before\" state\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    const beforePosition = await getUserCardPosition(page, '16')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    // Wait for scroll restoration to complete\n    await expect\n      .poll(async () => {\n        const position = await getUserCardPosition(page, '16')\n        return position.viewportTop\n      })\n      .toBeCloseTo(beforePosition.viewportTop, 0)\n\n    const afterPosition = await getUserCardPosition(page, '16')\n    expect(afterPosition.viewportTop).toBeCloseTo(beforePosition.viewportTop, 0)\n  })\n\n  test('it maintains scroll position when loading next pages', async ({ page }) => {\n    await page.goto('/infinite-scroll/trigger-both')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n\n    // Scroll to the bottom of the page to load page 2\n    await scrollToBottom(page)\n\n    await expect(page.getByText('Loading...')).toBeVisible()\n    const beforePosition = await getUserCardPosition(page, '15')\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    // Wait for any initial loading to complete\n    await expect(page.getByText('Loading...')).toBeHidden()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeHidden()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    const afterPosition = await getUserCardPosition(page, '15')\n\n    expect(afterPosition.viewportTop).toBeCloseTo(beforePosition.viewportTop, 0)\n  })\n\n  test('it maintains scroll position when loading previous pages with buffer margin', async ({ page }) => {\n    await page.goto('/infinite-scroll/trigger-start-buffer?page=3')\n\n    // Wait for page 2 to load automatically...\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    // Get initial scroll position and User 16 position\n    const initialScrollY = await page.evaluate(() => window.scrollY)\n\n    // Scroll to trigger buffer zone for loading page 1 (within 200px buffer)\n    await page.evaluate(() => window.scrollTo(0, 100))\n    await page.waitForTimeout(50)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n    await expect(page.getByText('User 16')).toBeVisible()\n\n    // Verify the final scroll position accounts for new content\n    const finalScrollY = await page.evaluate(() => window.scrollY)\n    expect(finalScrollY).toBeGreaterThan(initialScrollY) // Should scroll down to maintain relative position\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 31')).toBeVisible() // Page 3 content\n    await expect(page.getByText('User 40')).toBeVisible()\n  })\n\n  test('it maintains scroll position when loading next pages with buffer margin', async ({ page }) => {\n    await page.goto('/infinite-scroll/trigger-end-buffer')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n\n    // Scroll to bottom to trigger loading, similar to the working test\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n    const beforePosition = await getUserCardPosition(page, '15')\n\n    // Wait for loading to complete\n    await expect(page.getByText('Loading...')).toBeHidden()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n\n    const afterPosition = await getUserCardPosition(page, '15')\n\n    expect(afterPosition.viewportTop).toBeCloseTo(beforePosition.viewportTop, 0)\n  })\n\n  test('it maintains scroll position when first child element is invisible', async ({ page }) => {\n    await page.goto('/infinite-scroll/invisible-first-child?page=2')\n\n    // Verify the invisible element exists but is not visible\n    const hiddenElement = await page.locator('text=\"Hidden first element\"')\n    await expect(hiddenElement).toBeAttached()\n    await expect(hiddenElement).toBeHidden()\n\n    // Page 1 loads immediately since the start trigger is visible\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n\n    // Make sure the browser didn't scroll to the top...\n    const scrollY = await page.evaluate(() => window.scrollY)\n    expect(scrollY).toBeGreaterThan(100 * 15)\n  })\n})\n\ntest.describe('Scrollable container support', () => {\n  test('it loads pages in both directions when infinite scroll is within a scrollable container', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/scroll-container?page=2')\n\n    // Get the scrollable container element\n    const scrollContainer = await page.locator('[data-testid=\"scroll-container\"]')\n    await expect(scrollContainer).toBeVisible()\n\n    // Initially, page 2 should be visible\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n\n    // It automatically loads page 1 because the start trigger is visible within the container\n    await expect(page.getByText('Loading more users...')).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('Loading more users...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    // Scroll within the container (not the page) to load page 3\n    await scrollElementToBottom(scrollContainer)\n    await expect(page.getByText('Loading more users...')).toBeVisible()\n\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('Loading more users...')).toBeHidden()\n    await expect(infiniteScrollRequests().length).toBe(2)\n\n    // Verify all three pages are now loaded within the container\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible() // Page 1\n    await expect(page.getByText('User 20')).toBeVisible() // Page 2\n    await expect(page.getByText('User 40')).toBeVisible() // Page 3\n  })\n\n  test('it updates query parameters based on visible content within a scrollable container', async ({ page }) => {\n    test.setTimeout(15_000)\n    requests.listen(page)\n    await page.goto('/infinite-scroll/scroll-container')\n\n    // Initially should be on page 1 (no page param)\n    expect(page.url()).not.toContain('page=')\n\n    const scrollContainer = await page.locator('[data-testid=\"scroll-container\"]')\n    await expect(scrollContainer).toBeVisible()\n\n    // Load all 3 pages first\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n\n    // Scroll container to load page 2\n    await scrollElementToBottom(scrollContainer)\n    await expect(page.getByText('Loading more users...')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('Loading more users...')).toBeHidden()\n\n    // Scroll container again to load page 3\n    await scrollElementToBottom(scrollContainer)\n    await expect(page.getByText('Loading more users...')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('Loading more users...')).toBeHidden()\n\n    // Helper function to scroll container smoothly\n    const smoothScrollContainerTo = async (targetY: number) => {\n      await scrollContainer.evaluate((container, top) => container.scrollTo({ top, behavior: 'smooth' }), targetY)\n      await page.waitForTimeout(250)\n    }\n\n    // Helper function to check URL updates with container scrolling\n    const expectQueryStringInContainer = async (expectedPage: string) => {\n      if (expectedPage === '1') {\n        await page.waitForFunction(() => !window.location.search.includes('page='), { timeout: 1000 })\n        expect(page.url()).not.toContain('page=')\n      } else {\n        await page.waitForFunction((pageNum) => window.location.search.includes(`page=${pageNum}`), expectedPage, {\n          timeout: 1000,\n        })\n        expect(page.url()).toContain(`page=${expectedPage}`)\n      }\n    }\n\n    const containerHeight = await scrollContainer.evaluate((container) => container.scrollHeight)\n\n    // Test URL updates at different container scroll positions\n    await smoothScrollContainerTo(0)\n    await expectQueryStringInContainer('1')\n\n    await smoothScrollContainerTo(Math.floor(containerHeight / 2))\n    await expectQueryStringInContainer('2')\n\n    await smoothScrollContainerTo(containerHeight)\n    await expectQueryStringInContainer('3')\n\n    await smoothScrollContainerTo(0)\n    await expectQueryStringInContainer('1')\n  })\n\n  test('it maintains scroll position when loading previous pages in container', async ({ page }) => {\n    await page.goto('/infinite-scroll/scroll-container?page=3')\n\n    const scrollContainer = await page.locator('[data-testid=\"scroll-container\"]')\n    await expect(scrollContainer).toBeVisible()\n\n    // Wait for page 2 to load automatically...\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('Loading more users...')).toBeHidden()\n\n    // Scroll container to top to trigger loading page 1\n    await scrollElementSmoothTo(scrollContainer, 0)\n\n    // Capture User 16's position immediately after scroll, before prepend\n    const beforePosition = await getUserCardPositionInContainer(page, scrollContainer, '16')\n\n    // Wait for page 1 to load (loading indicator may flash briefly or not at all)\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('Loading more users...')).toBeHidden()\n\n    // Wait for scroll restoration to complete - User 16 should stay in same viewport position\n    await expect\n      .poll(async () => {\n        const position = await getUserCardPositionInContainer(page, scrollContainer, '16')\n        return position.viewportTop\n      })\n      .toBeCloseTo(beforePosition.viewportTop, 0)\n\n    const afterPosition = await getUserCardPositionInContainer(page, scrollContainer, '16')\n    expect(afterPosition.viewportTop).toBeCloseTo(beforePosition.viewportTop, 0)\n  })\n\n  test('it maintains scroll position when loading next pages in container', async ({ page }) => {\n    test.setTimeout(10_000)\n    await page.goto('/infinite-scroll/scroll-container')\n\n    const scrollContainer = await page.locator('[data-testid=\"scroll-container\"]')\n    await expect(scrollContainer).toBeVisible()\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n\n    // Scroll down within container to see User 15 and trigger loading page 2\n    await scrollElementToBottom(scrollContainer)\n\n    const beforePosition = await getUserCardPositionInContainer(page, scrollContainer, '15')\n\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n\n    const afterPosition = await getUserCardPositionInContainer(page, scrollContainer, '15')\n\n    expect(afterPosition.viewportTop).toBeCloseTo(beforePosition.viewportTop, 0)\n  })\n\n  test('it does not treat overflow-x: hidden as a scroll container', async ({ page }) => {\n    await page.setViewportSize({ width: 1200, height: 400 })\n    requests.listen(page)\n\n    await page.goto('/infinite-scroll/overflow-x')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n\n    expect(infiniteScrollRequests().length).toBe(1)\n    await expect(page.getByText('User 31')).toBeHidden()\n\n    await page.waitForTimeout(1000)\n\n    await expect(page.getByText('User 31')).toBeHidden()\n  })\n})\n\ntest.describe('Horizontal scrolling support', () => {\n  test('it loads pages horizontally when scrolling right in a horizontal container', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/horizontal-scroll')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n\n    const scrollContainer = await page.locator('div[style*=\"overflow-x: scroll\"]')\n\n    await expect(infiniteScrollRequests().length).toBe(0)\n\n    // Scroll right to trigger loading page 2\n    await scrollContainer.evaluate((container) => (container.scrollLeft = container.scrollWidth))\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeHidden()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    // Scroll right again to trigger loading page 3\n    await scrollContainer.evaluate((container) => (container.scrollLeft = container.scrollWidth))\n    await expect(page.getByText('Loading...')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n    await expect(infiniteScrollRequests().length).toBe(2)\n    await expect(page.getByText('User 40')).toBeVisible()\n\n    // Try scrolling right once more - should NOT trigger loading since User 40 is the last one\n    await scrollContainer.evaluate((container) => (container.scrollLeft = container.scrollWidth))\n    await expect(page.getByText('Loading...')).toBeHidden()\n    await expect(infiniteScrollRequests().length).toBe(2) // Should still be 2, no additional request\n\n    await page.waitForTimeout(300)\n    expect(page.url()).toContain('page=3')\n\n    // Check if the data-infinite-scroll attribute is set correctly for horizontal scroll\n    const user15 = await page.locator('[data-user-id=\"15\"]')\n    const user16 = await page.locator('[data-user-id=\"16\"]')\n    const user30 = await page.locator('[data-user-id=\"30\"]')\n    const user31 = await page.locator('[data-user-id=\"31\"]')\n    const user40 = await page.locator('[data-user-id=\"40\"]')\n\n    await expect(user15).toHaveAttribute('data-infinite-scroll-page', '1')\n    await expect(user16).toHaveAttribute('data-infinite-scroll-page', '2')\n    await expect(user30).toHaveAttribute('data-infinite-scroll-page', '2')\n    await expect(user31).toHaveAttribute('data-infinite-scroll-page', '3')\n    await expect(user40).toHaveAttribute('data-infinite-scroll-page', '3')\n  })\n})\n\ntest.describe('Programmatic access via component ref', () => {\n  test('it allows manual loading via ref methods', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/programmatic-ref?page=2')\n\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 15')).toBeHidden()\n    await expect(page.getByText('User 31')).toBeHidden()\n\n    await expect(page.getByText('Has more previous items: true')).toBeVisible()\n    await expect(page.getByText('Has more next items: true')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Load Previous (Ref)' }).click()\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    await expect(page.getByText('Has more previous items: false')).toBeVisible()\n    await expect(page.getByText('Has more next items: true')).toBeVisible()\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    await page.getByRole('button', { name: 'Load Next (Ref)' }).click()\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await expect(page.getByText('User 31')).toBeVisible()\n    await expect(page.getByText('User 40')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    await expect(page.getByText('Has more previous items: false')).toBeVisible()\n    await expect(page.getByText('Has more next items: false')).toBeVisible()\n    await expect(infiniteScrollRequests().length).toBe(2)\n  })\n\n  test('it correctly reports hasMore states at page boundaries', async ({ page }) => {\n    requests.listen(page)\n\n    await page.goto('/infinite-scroll/programmatic-ref?page=1')\n    await expect(page.getByText('Has more previous items: false')).toBeVisible()\n    await expect(page.getByText('Has more next items: true')).toBeVisible()\n\n    await page.goto('/infinite-scroll/programmatic-ref?page=3')\n    await expect(page.getByText('Has more previous items: true')).toBeVisible()\n    await expect(page.getByText('Has more next items: false')).toBeVisible()\n  })\n})\n\ntest.describe('Grid layout support', () => {\n  test('it loads pages in a CSS grid layout', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/grid')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 60')).toBeVisible()\n    await expect(page.getByText('User 61')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(0)\n\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading more users...')).toBeVisible()\n\n    await expect(page.getByText('User 61')).toBeVisible()\n    await expect(page.getByText('User 120')).toBeVisible()\n    await expect(page.getByText('User 121')).toBeHidden()\n    await expect(page.getByText('Loading more users...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading more users...')).toBeVisible()\n\n    await expect(page.getByText('User 121')).toBeVisible()\n    await expect(page.getByText('User 180')).toBeVisible()\n    await expect(page.getByText('User 181')).toBeHidden()\n    await expect(page.getByText('Loading more users...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(2)\n\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading more users...')).toBeVisible()\n\n    await expect(page.getByText('User 181')).toBeVisible()\n    await expect(page.getByText('User 240')).toBeVisible()\n    await expect(page.getByText('Loading more users...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(3)\n\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading more users...')).toBeHidden()\n    await expect(infiniteScrollRequests().length).toBe(3)\n  })\n})\n\ntest.describe('Data table layout support', () => {\n  test('it loads pages in a table layout with large datasets', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/data-table')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 250')).toBeVisible()\n    await expect(page.getByText('User 251')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(0)\n\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await expect(page.getByText('User 251')).toBeVisible()\n    await expect(page.getByText('User 500')).toBeVisible()\n    await expect(page.getByText('User 501')).toBeHidden()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(1)\n\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await expect(page.getByText('User 501')).toBeVisible()\n    await expect(page.getByText('User 750')).toBeVisible()\n    await expect(page.getByText('User 751')).toBeHidden()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(2)\n\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeVisible()\n\n    await expect(page.getByText('User 751')).toBeVisible()\n    await expect(page.getByText('User 1000')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(3)\n\n    await scrollToBottom(page)\n    await expect(page.getByText('Loading...')).toBeHidden()\n    await expect(infiniteScrollRequests().length).toBe(3)\n\n    const user500 = await page.locator('[data-user-id=\"500\"]')\n    const user501 = await page.locator('[data-user-id=\"501\"]')\n    const user1000 = await page.locator('[data-user-id=\"1000\"]')\n\n    await expect(user500).toHaveAttribute('data-infinite-scroll-page', '2')\n    await expect(user501).toHaveAttribute('data-infinite-scroll-page', '3')\n    await expect(user1000).toHaveAttribute('data-infinite-scroll-page', '4')\n  })\n})\n\ntest.describe('Empty dataset handling', () => {\n  test('it handles empty datasets gracefully', async ({ page }) => {\n    requests.listen(page)\n    await page.goto('/infinite-scroll/empty')\n\n    await expect(page.getByText('Empty Dataset Test')).toBeVisible()\n    await expect(page.getByText('No users found.')).toBeVisible()\n    await expect(page.getByText('Loading...')).toBeHidden()\n\n    await expect(infiniteScrollRequests().length).toBe(0)\n\n    await scrollToBottom(page)\n    await page.waitForTimeout(500)\n\n    await expect(page.getByText('Loading...')).toBeHidden()\n    await expect(infiniteScrollRequests().length).toBe(0)\n\n    await expect(page.getByText('No users found.')).toBeVisible()\n  })\n})\n\nObject.entries({\n  ref: '/infinite-scroll/custom-triggers-ref',\n  selector: '/infinite-scroll/custom-triggers-selector',\n  'ref-object': '/infinite-scroll/custom-triggers-ref-object',\n}).forEach(([key, path]) => {\n  test.describe('Custom triggers and slot using ' + key, () => {\n    test('it loads pages when scrolling to custom triggers and updates URL', async ({ page }) => {\n      requests.listen(page)\n      await page.goto(path)\n\n      // Initially should only see users 1-15\n      await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n      await expect(page.getByText('User 15')).toBeVisible()\n      await expect(page.getByText('User 16')).toBeHidden()\n\n      // URL should not have page param initially\n      expect(page.url()).not.toContain('page=')\n\n      // Scroll to bottom to trigger loading users 16-30\n      await scrollToBottom(page)\n      // Wait for loading to start or data to appear (whichever comes first)\n      await expect(page.getByText('Loading...').or(page.getByText('User 16'))).toBeVisible()\n      await expect(page.getByText('User 16')).toBeVisible()\n      await expect(page.getByText('User 30')).toBeVisible()\n      await expect(page.getByText('Loading...')).toBeHidden()\n      await expect(infiniteScrollRequests().length).toBe(1)\n\n      // Load page 3 by scrolling to tfoot (custom after trigger)\n      await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight - 500))\n      // Wait for loading to start or data to appear (whichever comes first)\n      await expect(page.getByText('Loading...').or(page.getByText('User 31'))).toBeVisible()\n      await expect(page.getByText('User 31')).toBeVisible()\n      await expect(page.getByText('User 40')).toBeVisible()\n      await expect(page.getByText('Loading...')).toBeHidden()\n      await expect(infiniteScrollRequests().length).toBe(2)\n\n      const pageHeight = await page.evaluate(() => document.body.scrollHeight)\n\n      // Test URL updates at different scroll positions using smooth scrolling\n      await smoothScrollTo(page, 0)\n      await expectQueryString(page, '1')\n\n      await smoothScrollTo(page, Math.floor(pageHeight / 2))\n      await expectQueryString(page, '2')\n\n      await smoothScrollTo(page, pageHeight)\n      await expectQueryString(page, '3')\n\n      await smoothScrollTo(page, 0)\n      await expectQueryString(page, '1')\n    })\n\n    test('it auto-loads previous pages and responds to custom before trigger', async ({ page }) => {\n      requests.listen(page)\n      await page.goto(path + '?page=3')\n\n      // Initially should see users 31-40\n      await expect(page.getByText('User 31')).toBeVisible()\n      await expect(page.getByText('User 40')).toBeVisible()\n      await expect(page.getByText('User 30')).toBeHidden()\n\n      // Page 2 should auto-load because the before trigger (thead) is visible\n      await expect(page.getByText('User 30')).toBeVisible()\n      await expect(page.getByText('User 16')).toBeVisible()\n      await expect(page.getByText('User 15')).toBeHidden()\n      await expect(infiniteScrollRequests().length).toBe(1)\n\n      // Scroll up to thead to trigger loading page 1\n      await page.evaluate(() => window.scrollTo(0, 300))\n\n      await expect(page.getByText('User 15')).toBeVisible()\n      await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n      await expect(infiniteScrollRequests().length).toBe(2)\n\n      // Verify all three pages are loaded with correct data attributes\n      const user1 = await page.locator('[data-user-id=\"1\"]')\n      const user16 = await page.locator('[data-user-id=\"16\"]')\n      const user40 = await page.locator('[data-user-id=\"40\"]')\n\n      await expect(user1).toHaveAttribute('data-infinite-scroll-page', '1')\n      await expect(user16).toHaveAttribute('data-infinite-scroll-page', '2')\n      await expect(user40).toHaveAttribute('data-infinite-scroll-page', '3')\n    })\n  })\n})\n\nObject.entries({\n  'refresh state': '/infinite-scroll/filtering/refresh-state',\n  'preserve state': '/infinite-scroll/filtering/preserve-state',\n}).forEach(([key, path]) => {\n  test.describe(`Query parameter handling (${key})`, () => {\n    test('it keeps the existing query parameters intact when updating the page param', async ({ page }) => {\n      requests.listen(page)\n      await page.goto(path)\n      await page.setViewportSize({ width: 1200, height: 400 })\n\n      await page.getByRole('link', { name: 'N-Z' }).first().click()\n\n      await expect(page.getByText('Niko Christiansen Jr.')).toBeVisible()\n      await expect(page.getByText('Current filter: n-z').first()).toBeVisible()\n      expect(page.url()).toContain('filter=n-z')\n      expect(page.url()).not.toContain('page=')\n\n      // Scroll to bottom to load page 2\n      await scrollToBottom(page)\n      await expect(page.getByText('Woodrow Kuvalis')).toBeVisible()\n\n      // Assert filter=n-z&page=2\n      await scrollToBottom(page)\n      await expectQueryString(page, '2')\n      expect(page.url()).toContain('filter=n-z')\n      expect(page.url()).toContain('page=2')\n\n      await expect(page.getByText('Niko Christiansen Jr.')).toBeVisible()\n      await expect(page.getByText('Woodrow Kuvalis')).toBeVisible()\n\n      await expect(infiniteScrollRequests().length).toBe(1)\n    })\n\n    test('it resets the infinite scroll component when navigating to the same page with different query params', async ({\n      page,\n    }) => {\n      requests.listen(page)\n      await page.goto(path)\n\n      await page.getByRole('link', { name: 'A-M' }).first().click()\n\n      await expect(page.getByText('Adelle Crona DVM')).toBeVisible()\n      await expect(page.getByText('Breana Herzog')).toBeVisible()\n      await expect(page.getByText('Current filter: a-m').first()).toBeVisible()\n\n      await scrollToBottom(page)\n      await expect(page.getByText('Camylle Metz Sr.')).toBeVisible()\n\n      await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight - 1000))\n      await expectQueryString(page, '2')\n      expect(page.url()).toContain('filter=a-m')\n      expect(page.url()).toContain('page=2')\n\n      await expect(infiniteScrollRequests().length).toBe(1)\n\n      await page.getByRole('link', { name: 'N-Z' }).first().click()\n\n      await expect(page.getByText('Niko Christiansen Jr.')).toBeVisible()\n      await expect(page.getByText('Current filter: n-z').first()).toBeVisible()\n\n      await expect(page.getByText('Adelle Crona DVM')).toBeHidden()\n      await expect(page.getByText('Camylle Metz Sr.')).toBeHidden()\n\n      expect(page.url()).toContain('filter=n-z')\n      expect(page.url()).not.toContain('page=')\n\n      await scrollToBottom(page)\n      await expect(page.getByText('Woodrow Kuvalis')).toBeVisible()\n      await expect(page.getByText('Niko Christiansen Jr.')).toBeVisible()\n      await expect(infiniteScrollRequests().length).toBe(2)\n    })\n\n    test('it resets the page and filter params when searching for a user', async ({ page }) => {\n      requests.listen(page)\n      await page.goto(path)\n      await page.setViewportSize({ width: 1200, height: 400 })\n\n      await page.getByRole('link', { name: 'N-Z' }).first().click()\n      await expect(page.getByText('Niko Christiansen Jr.')).toBeVisible()\n      await expect(page.getByText('Current filter: n-z').first()).toBeVisible()\n\n      await scrollToBottom(page)\n      await expect(page.getByText('Woodrow Kuvalis')).toBeVisible()\n\n      await scrollToBottom(page)\n      await expectQueryString(page, '2')\n      expect(page.url()).toContain('filter=n-z')\n      expect(page.url()).toContain('page=2')\n\n      // Search for 'adelle' in bottom input box\n      await page.locator('input').nth(1).fill('adelle')\n\n      await expect(page.getByText('Adelle Crona DVM')).toBeVisible()\n\n      // Assert search=adelle (no page param, no filter param)\n      expect(page.url()).toContain('search=adelle')\n      expect(page.url()).not.toContain('page=')\n      expect(page.url()).not.toContain('filter=')\n      await expect(page.getByText('Current search: adelle').first()).toBeVisible()\n      await expect(page.getByText('Current filter: none').first()).toBeVisible()\n\n      // Assert only 'Adelle Crona DVM' is visible\n      await expect(page.getByText('Niko Christiansen Jr.')).toBeHidden()\n      await expect(page.getByText('Woodrow Kuvalis')).toBeHidden()\n\n      // Click N-Z again (this should reset search and apply filter)\n      await page.getByRole('link', { name: 'N-Z' }).first().click()\n      await expect(page.getByText('Niko Christiansen Jr.')).toBeVisible()\n\n      // Assert filter=n-z (no page param, no search param)\n      expect(page.url()).toContain('filter=n-z')\n      expect(page.url()).not.toContain('page=')\n      expect(page.url()).not.toContain('search=')\n      await expect(page.getByText('Current filter: n-z').first()).toBeVisible()\n      await expect(page.getByText('Current search: none').first()).toBeVisible()\n\n      // Assert 'Adelle Crona DVM' is hidden, 'Niko Christiansen Jr.' is visible\n      await expect(page.getByText('Adelle Crona DVM')).toBeHidden()\n      await expect(page.getByText('Niko Christiansen Jr.')).toBeVisible()\n\n      await scrollToBottom(page)\n      await expect(page.getByText('Woodrow Kuvalis')).toBeVisible()\n\n      await scrollToBottom(page)\n      await expectQueryString(page, '2')\n      expect(page.url()).toContain('filter=n-z')\n      expect(page.url()).toContain('page=2')\n\n      await expect(page.getByText('Niko Christiansen Jr.')).toBeVisible()\n      await expect(page.getByText('Woodrow Kuvalis')).toBeVisible()\n    })\n\n    test('it can load additional content after removing the search filter', async ({ page }) => {\n      requests.listen(page)\n      await page.goto(path + '?filter=n-z')\n\n      await page.locator('input').nth(0).fill('adelle')\n      await expect(page.getByText('Adelle Crona DVM')).toBeVisible()\n\n      await page.waitForTimeout(500)\n\n      const userIds = await getUserIdsFromDOM(page)\n      expect(userIds.length).toBe(1)\n\n      await page.locator('input').nth(0).fill('')\n\n      // Wait for second user\n      await expect(page.getByText('Alison Walter PhD')).toBeVisible()\n\n      // Scroll to bottom to load more users\n      await scrollToBottom(page)\n      await expect(page.getByText('Camylle Metz Sr.')).toBeVisible()\n    })\n  })\n})\n\ntest.describe('Reset triggers', () => {\n  test('it auto-loads additional pages after clearing search filter', async ({ page }) => {\n    await page.goto('/infinite-scroll/filtering-reset')\n\n    await expect(page.getByText('Adelle Crona DVM')).toBeVisible()\n    await expect(page.getByText('Camylle Metz Sr.')).toBeVisible({ timeout: 3000 })\n\n    await page.locator('input').nth(0).fill('adelle')\n    await expect(page.getByText('Current search: adelle')).toBeVisible()\n\n    const userIds = await getUserIdsFromDOM(page)\n    expect(userIds.length).toBe(1)\n\n    await page.locator('input').nth(0).fill('')\n    await expect(page.getByText('Current search: none')).toBeVisible()\n    await expect(page.getByText('Camylle Metz Sr.')).toBeVisible({ timeout: 3000 })\n  })\n})\n\ntest.describe('Router', () => {\n  test('it can reload unrelated props without affecting infinite scroll', async ({ page }) => {\n    await page.goto('/infinite-scroll/reload-unrelated')\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n\n    const initialTime = await page.locator('#time-display').textContent()\n\n    await page.locator('#reload-button').click()\n\n    // Wait for reload to complete and verify timestamp changed\n    await page.waitForTimeout(300)\n    const updatedTime = await page.locator('#time-display').textContent()\n    expect(updatedTime).not.toBe(initialTime)\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n\n    await scrollToBottom(page)\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeHidden()\n  })\n\n  test('it can prefetch a page with scroll props', async ({ page }) => {\n    await page.goto('/infinite-scroll')\n\n    const prefetchPromise = page.waitForResponse('/infinite-scroll-with-link')\n    await page.getByRole('link', { name: 'Go to InfiniteScrollWithLink (Prefetch)' }).hover()\n    await page.waitForTimeout(75)\n    await prefetchPromise\n\n    requests.listen(page)\n    await page.getByRole('link', { name: 'Go to InfiniteScrollWithLink (Prefetch)' }).click()\n    await page.waitForURL('/infinite-scroll-with-link')\n    await expect(requests.requests.length).toBe(0)\n\n    // Verify infinite scroll works - check initial users\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n\n    await scrollToBottom(page)\n    await page.waitForTimeout(300)\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeHidden()\n\n    await scrollToTop(page)\n    await page.waitForTimeout(100)\n    await page.getByRole('link', { name: 'Go back to Links' }).click()\n    await page.waitForURL('/infinite-scroll')\n\n    // Click the link again, should behave the same\n    const prefetchPromise2 = page.waitForResponse('/infinite-scroll-with-link')\n    await page.getByRole('link', { name: 'Go to InfiniteScrollWithLink (Prefetch)' }).hover()\n    await page.waitForTimeout(75)\n    await prefetchPromise2\n\n    requests.listen(page)\n    await page.getByRole('link', { name: 'Go to InfiniteScrollWithLink (Prefetch)' }).click()\n    await page.waitForURL('/infinite-scroll-with-link')\n    await expect(requests.requests.length).toBe(0)\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n\n    await scrollToBottom(page)\n    await page.waitForTimeout(300)\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeHidden()\n  })\n\n  test('it can navigate rapidly between pages with infinite scroll without errors', async ({ page }) => {\n    test.setTimeout(10_000)\n    consoleMessages.listen(page)\n\n    await page.goto('/infinite-scroll')\n\n    // Navigate back and forth 20 times rapidly\n    for (let i = 0; i < 20; i++) {\n      await page.getByRole('link', { name: 'Go to InfiniteScrollWithLink', exact: true }).click()\n      await expect(page.getByRole('link', { name: 'Go back to Links' })).toBeVisible()\n      expect(consoleMessages.errors).toHaveLength(0)\n      await page.getByRole('link', { name: 'Go back to Links' }).click()\n      await expect(page.getByRole('link', { name: 'Go to InfiniteScrollWithLink', exact: true })).toBeVisible()\n      expect(consoleMessages.errors).toHaveLength(0)\n    }\n\n    await page.getByRole('link', { name: 'Go to InfiniteScrollWithLink', exact: true }).click()\n\n    // Check if the infinite scroll content is still functional\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n\n    await scrollToBottom(page)\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('User 31')).toBeHidden()\n  })\n\n  test('it preserves URL-encoded indices notation in query string when fetching pages', async ({ page }) => {\n    requests.listen(page)\n\n    await page.goto('/infinite-scroll/filtering/refresh-state?foo%5B0%5D%5Bbar%5D=baz')\n    await expect(page.getByText('Adelle Crona DVM')).toBeVisible()\n\n    await scrollToBottom(page)\n    await page.waitForTimeout(500)\n\n    const pageRequests = infiniteScrollRequests()\n    expect(pageRequests.length).toBeGreaterThan(0)\n\n    const requestUrl = pageRequests[pageRequests.length - 1].url()\n    expect(requestUrl).toContain('foo[0][bar]=baz')\n    expect(requestUrl).not.toContain('foo[][bar]')\n  })\n})\n\ntest.describe('Deferred scroll props', () => {\n  test('it loads deferred scroll props and merges scrollProps correctly', async ({ page }) => {\n    requests.listen(page)\n\n    await gotoPageAndWaitForContent(page, '/infinite-scroll/deferred')\n\n    await expect(page.getByText('Loading deferred scroll prop...')).toBeVisible()\n\n    await expect(page.getByText('User 1', { exact: true })).toBeVisible()\n    await expect(page.getByText('Loading deferred scroll prop...')).toBeHidden()\n\n    await expect(page.getByText('User 15')).toBeVisible()\n    await expect(page.getByText('User 16')).toBeHidden()\n\n    await expect(page.getByText('Has more next items: true')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Load next items' }).click()\n    await expect(page.getByText('Loading next items...')).toBeVisible()\n\n    await expect(page.getByText('User 16')).toBeVisible()\n    await expect(page.getByText('User 30')).toBeVisible()\n    await expect(page.getByText('Loading next items...')).toBeHidden()\n\n    // Verify the requests: 1 for deferred props, 1 for loading next page\n    const pageRequests = infiniteScrollRequests()\n    expect(pageRequests.length).toBe(2)\n  })\n})\n"
  },
  {
    "path": "tests/initial-visit.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport { requests } from './support'\n\ntest('it does not trigger unnecessary reload when history state has no Inertia data', async ({ page }) => {\n  await page.goto('/navigate-non-inertia')\n  await expect(page.getByText('Navigate Non-Inertia')).toBeVisible()\n\n  await page.click('a[href=\"/non-inertia\"]')\n  await expect(page.locator('body')).toContainText('This is a page that does not have the Inertia app loaded')\n\n  requests.listen(page)\n\n  await page.goBack()\n  await page.waitForURL('/navigate-non-inertia')\n  await expect(page.getByText('Navigate Non-Inertia')).toBeVisible()\n\n  const pageRequests = requests.requests.filter((r) => r.url().includes('/navigate-non-inertia'))\n  expect(pageRequests.length).toBe(1)\n})\n\ntest('it handles back/forward navigation between Inertia and non-Inertia pages correctly', async ({ page }) => {\n  await page.goto('/non-inertia')\n  await expect(page.locator('body')).toContainText('This is a page that does not have the Inertia app loaded')\n\n  await page.click('a[href=\"/navigate-non-inertia\"]')\n  await expect(page.getByText('Navigate Non-Inertia')).toBeVisible()\n\n  await page.click('a[href=\"/non-inertia\"]')\n  await expect(page.locator('body')).toContainText('This is a page that does not have the Inertia app loaded')\n\n  requests.listen(page)\n\n  await page.goBack()\n  await page.waitForURL('/navigate-non-inertia')\n  await expect(page.getByText('Navigate Non-Inertia')).toBeVisible()\n\n  await page.goBack()\n  await page.waitForURL('/non-inertia')\n  await expect(page.locator('body')).toContainText('This is a page that does not have the Inertia app loaded')\n\n  await page.goForward()\n  await page.waitForURL('/navigate-non-inertia')\n  await expect(page.getByText('Navigate Non-Inertia')).toBeVisible()\n\n  const inertiaRequests = requests.requests.filter(\n    (r) => r.url().includes('/navigate-non-inertia') && r.headers()['x-inertia'] === 'true',\n  )\n  expect(inertiaRequests.length).toBe(0)\n})\n"
  },
  {
    "path": "tests/links.spec.ts",
    "content": "import { expect, Page, test } from '@playwright/test'\nimport {\n  consoleMessages,\n  pageLoads,\n  requests,\n  scrollElementTo,\n  shouldBeDumpPage,\n  waitForFragmentScroll,\n} from './support'\n\ndeclare const process: { env: { PACKAGE?: string } }\n\ntest.beforeEach(async ({ page }) => {})\n\ntest('visits a different page', async ({ page }) => {\n  pageLoads.watch(page)\n\n  await page.goto('/')\n  await page.getByRole('link', { name: 'Basic Links' }).click()\n  await expect(page).toHaveURL('/links/method')\n  await expect(page.getByText('This is the links page that demonstrates inertia-link methods')).toBeVisible()\n})\n\ntest('can make a location visit', async ({ page }) => {\n  pageLoads.watch(page, 2)\n\n  await page.goto('/links/location')\n  await page.getByRole('link', { name: 'Location visit' }).click()\n  const dump = await shouldBeDumpPage(page, 'get')\n  await expect(dump['x-inertia']).toBeUndefined()\n})\n\ntest('will avoid an extra reload after a location visit', async ({ page }) => {\n  pageLoads.watch(page, 2)\n\n  await page.goto('/links/location')\n  requests.listen(page)\n\n  await expect(requests.requests.length).toBe(0)\n  await page.getByRole('link', { name: 'Location visit' }).click()\n  const dump = await shouldBeDumpPage(page, 'get')\n  await expect(dump['x-inertia']).toBeUndefined()\n  // Requests made: /location (redirect), /dump/get, /assets/index-*.js, /assets/index-*.css\n  // Filter to only count page requests (assets may vary by browser)\n  const pageRequests = requests.requests.filter((r) => !r.url().includes('/assets/'))\n  await expect(pageRequests.length).toBe(2)\n})\n\ntest('will automatically cancel a pending visits when a new request is made', async ({ page }) => {\n  pageLoads.watch(page)\n\n  consoleMessages.listen(page)\n\n  await page.goto('/links/automatic-cancellation')\n\n  await page.getByRole('link', { name: 'Link' }).click()\n  await page.getByRole('link', { name: 'Link' }).click()\n\n  await expect(consoleMessages.messages).toHaveLength(3)\n  await expect(consoleMessages.messages[0]).toBe('started')\n  await expect(consoleMessages.messages[1]).toBe('cancelled')\n  await expect(consoleMessages.messages[2]).toBe('started')\n})\n\ntest.describe('methods', () => {\n  test.beforeEach(async ({ page }) => {\n    pageLoads.watch(page)\n\n    await page.goto('/links/method')\n  })\n\n  const data = [\n    { method: 'get', label: 'GET', el: 'link' },\n    { method: 'post', label: 'POST', el: 'button' },\n    { method: 'put', label: 'PUT', el: 'button' },\n    { method: 'patch', label: 'PATCH', el: 'button' },\n    { method: 'delete', label: 'DELETE', el: 'button' },\n    { method: 'post', label: 'OBJECT', el: 'button' },\n    { method: 'post', label: 'OBJECT METHOD OVERRIDE', el: 'button' },\n  ] as const\n\n  data.forEach(({ method, label, el }) => {\n    test(`can use the ${label} method`, async ({ page }) => {\n      await page.getByRole(el, { name: `${label} Link` }).click()\n\n      const dump = await shouldBeDumpPage(page, method)\n\n      await expect(dump.query).toEqual({})\n      await expect(dump.method).toBe(method)\n      await expect(dump.form).toEqual({})\n    })\n  })\n})\n\ntest.describe('data', () => {\n  test.describe('query string array formatter', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n\n      await page.goto('/links/data/object')\n    })\n\n    const data = [\n      { label: 'QSAF Brackets', formatter: 'brackets', expected: '?a[]=b&a[]=c' },\n      { label: 'QSAF Indices', formatter: 'indices', expected: '?a[0]=b&a[1]=c' },\n      { label: 'QSAF Default', formatter: 'default', expected: '?a[]=b&a[]=c' },\n    ]\n\n    data.forEach(({ label, formatter, expected }) => {\n      test(`can use the ${formatter} query string array formatter`, async ({ page }) => {\n        await page.getByRole('link', { name: label }).click()\n\n        const dump = await shouldBeDumpPage(page, 'get')\n\n        await expect(dump.query).toEqual({ a: ['b', 'c'] })\n        await expect(dump.method).toBe('get')\n        await expect(dump.form).toEqual({})\n        await expect(dump.headers['content-type']).not.toBe('application/json')\n      })\n    })\n  })\n\n  test.describe('plain objects', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n\n      await page.goto('/links/data/object')\n    })\n\n    test('passes data as query params', async ({ page }) => {\n      await page.getByRole('link', { name: 'GET Link' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'get')\n\n      await expect(page).toHaveURL('/dump/get?foo=get')\n      await expect(dump.query).toEqual({ foo: 'get' })\n      await expect(dump.method).toBe('get')\n      await expect(dump.form).toEqual({})\n      await expect(dump.headers['content-type']).not.toBe('application/json')\n    })\n\n    const data = [\n      { method: 'post', label: 'POST', form: { bar: 'post' } },\n      { method: 'put', label: 'PUT', form: { baz: 'put' } },\n      { method: 'patch', label: 'PATCH', form: { foo: 'patch' } },\n      { method: 'delete', label: 'DELETE', form: { bar: 'delete' } },\n    ] as const\n\n    data.forEach(({ method, label, form }) => {\n      test(`can pass data using the ${label} method`, async ({ page }) => {\n        await page.getByRole('button', { name: `${label} Link` }).click()\n\n        const dump = await shouldBeDumpPage(page, method)\n\n        await expect(dump.method).toBe(method)\n        await expect(dump.form).toEqual(form)\n        await expect(dump.files).toEqual({})\n        await expect(dump.headers['content-type']).toBe('application/json')\n      })\n    })\n  })\n\n  test.describe('form data objects', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n\n      await page.goto('/links/data/form-data')\n    })\n\n    const data = [\n      { method: 'post', label: 'POST' },\n      { method: 'put', label: 'PUT' },\n      { method: 'patch', label: 'PATCH' },\n      { method: 'delete', label: 'DELETE' },\n    ] as const\n\n    data.forEach(({ method, label }) => {\n      test(`can pass data using the ${label} method`, async ({ page }) => {\n        await page.getByRole('button', { name: `${label} Link` }).click()\n\n        const dump = await shouldBeDumpPage(page, method)\n\n        await expect(dump.method).toBe(method)\n        await expect(dump.form).toEqual({ bar: 'baz' })\n        await expect(dump.files).toEqual([])\n        await expect(dump.headers['content-type']).toContain('multipart/form-data; boundary=')\n      })\n    })\n  })\n\n  test.describe('auto-converted objects to form-data when files are present', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n\n      await page.goto('/links/data/auto-converted')\n    })\n\n    const data = [\n      { method: 'post', label: 'POST' },\n      { method: 'put', label: 'PUT' },\n      { method: 'patch', label: 'PATCH' },\n      { method: 'delete', label: 'DELETE' },\n    ] as const\n\n    data.forEach(({ method, label }) => {\n      test(`auto-converts objects using the ${label} method`, async ({ page }) => {\n        await page.getByRole('button', { name: `${label} Link` }).click()\n\n        const dump = await shouldBeDumpPage(page, method)\n\n        await expect(dump.method).toBe(method)\n        await expect(dump.form).toEqual({ foo: 'bar' })\n        await expect(dump.files).not.toEqual([])\n        await expect(dump.files[0].originalname).toBe('example.jpg')\n        await expect(dump.headers['content-type']).toContain('multipart/form-data; boundary=')\n      })\n    })\n  })\n})\n\ntest.describe('headers', () => {\n  test('has the default set of headers', async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/links/headers')\n\n    await page.getByRole('link', { name: 'Standard visit Link' }).click()\n\n    const dump = await shouldBeDumpPage(page, 'get')\n\n    await expect(dump.headers['x-inertia']).toBe('true')\n    await expect(dump.headers['x-inertia-version']).toBeUndefined()\n    await expect(dump.headers['x-requested-with']).toBe('XMLHttpRequest')\n    await expect(dump.headers['accept']).toBe('text/html, application/xhtml+xml')\n  })\n\n  test('starts using the x-inertia-version header when a version was given from the back-end', async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/links/headers/version')\n\n    await page.getByRole('link', { name: 'Standard visit Link' }).click()\n\n    const dump = await shouldBeDumpPage(page, 'get')\n\n    await expect(dump.headers['x-inertia-version']).toBe('example-version-header')\n  })\n\n  test('allows to set custom headers', async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/links/headers')\n\n    await page.getByRole('link', { name: 'GET Link' }).click()\n\n    const dump = await shouldBeDumpPage(page, 'get')\n\n    await expect(dump.headers['x-inertia']).toBe('true')\n    await expect(dump.headers['x-requested-with']).toBe('XMLHttpRequest')\n    await expect(dump.headers['accept']).toBe('text/html, application/xhtml+xml')\n    await expect(dump.headers['foo']).toBe('bar')\n  })\n\n  test('cannot override built-in Inertia headers', async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/links/headers')\n\n    await page.getByRole('button', { name: 'POST Link' }).click()\n\n    const dump = await shouldBeDumpPage(page, 'post')\n\n    await expect(dump.headers['x-inertia']).toBe('true')\n    await expect(dump.headers['x-requested-with']).toBe('XMLHttpRequest')\n    await expect(dump.headers['accept']).toBe('text/html, application/xhtml+xml')\n    await expect(dump.headers['bar']).toBe('baz')\n  })\n})\n\ntest.describe('replace', () => {\n  test.beforeEach(async ({ page }) => {\n    pageLoads.watch(page)\n\n    await page.goto('/')\n    await page.getByRole('link', { name: \"'Replace' Links\" }).click()\n    await expect(page).toHaveURL('/links/replace')\n  })\n\n  test('replaces the current history state', async ({ page }) => {\n    await page.getByRole('link', { name: '[State] Replace: true' }).click()\n    await shouldBeDumpPage(page, 'get')\n\n    await page.goBack()\n    await expect(page).toHaveURL('/')\n\n    await page.goForward()\n    await expect(page).toHaveURL('/dump/get')\n  })\n\n  test('does not replace the current history state when it is set to false', async ({ page }) => {\n    await page.getByRole('link', { name: '[State] Replace: false' }).click()\n    await shouldBeDumpPage(page, 'get')\n\n    await page.goBack()\n    await expect(page).toHaveURL('/links/replace')\n\n    await page.goForward()\n    await expect(page).toHaveURL('/dump/get')\n  })\n})\n\ntest.describe('preserve state', () => {\n  test.beforeEach(async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/links/preserve-state')\n  })\n\n  const preserveData = [\n    {\n      testLabel: 'default',\n      label: '[State] Preserve: true',\n      expected: 'bar',\n    },\n    {\n      testLabel: 'callback',\n      label: '[State] Preserve Callback: true',\n      expected: 'callback-bar',\n    },\n  ] as const\n\n  preserveData.forEach(({ label, expected, testLabel }) => {\n    test(`preserves the page's local state (${testLabel})`, async ({ page }) => {\n      await expect(page.getByText('Foo is now default')).toBeVisible()\n      await page.getByLabel('Example Field').fill('Example value')\n\n      const componentKey = await page.evaluate(() => (window as any)._inertia_page_key)\n      await expect(componentKey).not.toBeUndefined()\n\n      await page.getByRole('link', { name: label }).click()\n      await expect(page).toHaveURL(`/links/preserve-state-page-two?foo=${expected}`)\n\n      const newComponentKey = await page.evaluate(() => (window as any)._inertia_page_key)\n      await expect(newComponentKey).not.toBeUndefined()\n\n      await expect(newComponentKey).toBe(componentKey)\n      await expect(page.getByLabel('Example Field')).toHaveValue('Example value')\n      await expect(page.getByText(`Foo is now ${expected}`)).toBeVisible()\n    })\n  })\n\n  const dontPreserveData = [\n    {\n      testLabel: 'default',\n      label: '[State] Preserve: false',\n      expected: 'baz',\n    },\n    {\n      testLabel: 'callback',\n      label: '[State] Preserve Callback: false',\n      expected: 'callback-baz',\n    },\n  ] as const\n\n  dontPreserveData.forEach(({ label, testLabel, expected }) => {\n    test(`does not preserve the page's local state (${testLabel})`, async ({ page }) => {\n      await expect(page.getByText('Foo is now default')).toBeVisible()\n      await page.getByLabel('Example Field').fill('Another value')\n\n      // @ts-ignore\n      const componentKey = await page.evaluate(() => window._inertia_page_key)\n      await expect(componentKey).not.toBeUndefined()\n\n      await page.getByRole('link', { name: label }).click()\n      await expect(page).toHaveURL(`/links/preserve-state-page-two?foo=${expected}`)\n\n      // @ts-ignore\n      const newComponentKey = await page.evaluate(() => window._inertia_page_key)\n      await expect(newComponentKey).not.toBeUndefined()\n\n      await expect(newComponentKey).not.toBe(componentKey)\n      await expect(page.getByLabel('Example Field')).toHaveValue('')\n      await expect(page.getByText(`Foo is now ${expected}`)).toBeVisible()\n    })\n  })\n})\n\ntest.describe('preserve url', () => {\n  test.beforeEach(async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/links/preserve-url')\n  })\n\n  test('preserves the current URL', async ({ page }) => {\n    await expect(page.getByText('Foo is now default')).toBeVisible()\n    const initialUrl = page.url()\n\n    await page.getByRole('link', { name: '[URL] Preserve: true' }).click()\n    await expect(page.getByText('Foo is now bar')).toBeVisible()\n    await expect(page).toHaveURL(initialUrl) // URL should remain the same\n  })\n\n  test('does not preserve the current URL', async ({ page }) => {\n    await expect(page.getByText('Foo is now default')).toBeVisible()\n    const initialUrl = page.url()\n\n    await page.getByRole('link', { name: '[URL] Preserve: false' }).click()\n    await expect(page).toHaveURL('/links/preserve-url-page-two?foo=baz')\n    await expect(page.getByText('Foo is now baz')).toBeVisible()\n    await expect(page.url()).not.toBe(initialUrl) // URL should have changed\n  })\n\n  test('can load more items with preserveUrl via Link', async ({ page }) => {\n    await expect(page.getByText('Items loaded: 3')).toBeVisible()\n    await expect(page.locator('.has-next-page')).toHaveText('true')\n\n    await page.getByRole('link', { name: 'Load More' }).click()\n\n    // With mergeProps, the items.data array should be merged, giving us 6 total items\n    await expect(page.getByText('Items loaded: 6')).toBeVisible()\n    await expect(page).toHaveURL('/links/preserve-url')\n  })\n\n  test('can load more items with preserveUrl via router.visit', async ({ page }) => {\n    await expect(page.getByText('Items loaded: 3')).toBeVisible()\n    await expect(page.locator('.has-next-page')).toHaveText('true')\n\n    await page.getByRole('button', { name: 'Load More Router' }).click()\n\n    // With mergeProps, the items.data array should be merged, giving us 6 total items\n    await expect(page.getByText('Items loaded: 6')).toBeVisible()\n    await expect(page).toHaveURL('/links/preserve-url')\n  })\n})\n\ntest.describe('preserve scroll', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/links/preserve-scroll-false')\n    await expect(page.getByText('Foo is now default')).toBeVisible()\n\n    await scrollElementTo(\n      page,\n      page.evaluate(() => window.scrollTo(5, 7)),\n    )\n    await scrollElementTo(\n      page,\n      page.evaluate(() => document.querySelector('#slot')?.scrollTo(10, 15)),\n    )\n\n    await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n    await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n    await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n  })\n\n  test('does not reset untracked scroll regions in persistent layouts', async ({ page }) => {\n    await page.getByRole('link', { exact: true, name: 'Reset Scroll' }).click()\n    await expect(page).toHaveURL('/links/preserve-scroll-false-page-two?foo=bar')\n    await expect(page.getByText('Foo is now bar')).toBeVisible()\n    await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n    await expect(page.getByText('Document scroll position is 0 & 0')).toBeVisible()\n    await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n  })\n\n  test('does not reset untracked scroll regions in persistent layouts when returning false from a preserveScroll callback', async ({\n    page,\n  }) => {\n    consoleMessages.listen(page)\n\n    await page.getByRole('link', { exact: true, name: 'Reset Scroll (Callback)' }).click({ position: { x: 50, y: 5 } })\n    await expect(page).toHaveURL('/links/preserve-scroll-false-page-two?foo=foo')\n\n    await expect(page.getByText('Foo is now foo')).toBeVisible()\n\n    await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n    await expect(page.getByText('Document scroll position is 0 & 0')).toBeVisible()\n    await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n\n    await expect(consoleMessages.messages).toHaveLength(1)\n\n    const message = JSON.parse(consoleMessages.messages[0])\n\n    await expect(message.component).not.toBeUndefined()\n    await expect(message.props).not.toBeUndefined()\n    await expect(message.url).not.toBeUndefined()\n    await expect(message.version).not.toBeUndefined()\n  })\n\n  test('does not restore untracked scroll regions when pressing the back button', async ({ page }) => {\n    await page.getByRole('link', { exact: true, name: 'Reset Scroll' }).click()\n\n    await expect(page).toHaveURL('/links/preserve-scroll-false-page-two?foo=bar')\n    await expect(page.getByText('Foo is now bar')).toBeVisible()\n\n    await scrollElementTo(\n      page,\n      page.evaluate(() => document.querySelector('#slot')?.scrollTo(0, 0)),\n    )\n    await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n\n    await page.waitForTimeout(100)\n    await page.goBack()\n\n    await expect(page).toHaveURL('/links/preserve-scroll-false')\n    await expect(page.getByText('Foo is now default')).toBeVisible()\n    await expect(page.getByRole('button', { exact: true, name: 'Update scroll positions' })).toBeVisible()\n\n    await page.waitForFunction(\n      () => document.documentElement.scrollTop === 7 && document.documentElement.scrollLeft === 5,\n    )\n\n    await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n    await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n    await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n  })\n\n  test('does not restore untracked scroll regions when returning true from a preserveScroll callback', async ({\n    page,\n  }) => {\n    consoleMessages.listen(page)\n    await page.getByRole('link', { exact: true, name: 'Preserve Scroll (Callback)' }).click()\n\n    await expect(page).toHaveURL('/links/preserve-scroll-false-page-two?foo=baz')\n    await expect(page.getByText('Foo is now baz')).toBeVisible()\n\n    await scrollElementTo(\n      page,\n      page.evaluate(() => document.querySelector('#slot')?.scrollTo(0, 0)),\n    )\n    await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n\n    const message = JSON.parse(consoleMessages.messages[0])\n\n    await expect(message.component).not.toBeUndefined()\n    await expect(message.props).not.toBeUndefined()\n    await expect(message.url).not.toBeUndefined()\n    await expect(message.version).not.toBeUndefined()\n\n    await page.goBack()\n\n    await expect(page).toHaveURL('/links/preserve-scroll-false')\n    await expect(page.getByText('Foo is now default')).toBeVisible()\n\n    await page.waitForFunction(\n      () => document.documentElement.scrollTop === 7 && document.documentElement.scrollLeft === 5,\n    )\n\n    await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n    await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n    await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n  })\n\n  test.skip('does not restore untracked scroll regions when pressing the back button from another website', async ({\n    page,\n  }) => {\n    await page.getByRole('link', { name: 'Off-site link' }).click()\n\n    await expect(page).toHaveURL('non-inertia')\n\n    await page.goBack()\n\n    await expect(page).toHaveURL('/links/preserve-scroll-false')\n    await expect(page.getByText('Foo is now default')).toBeVisible()\n\n    await page.waitForFunction(\n      () => document.documentElement.scrollTop === 7 && document.documentElement.scrollLeft === 5,\n    )\n\n    await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n    await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n    await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n  })\n})\n\ntest.describe('enabled', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/links/preserve-scroll')\n    await expect(page.getByText('Foo is now default')).toBeVisible()\n\n    await scrollElementTo(\n      page,\n      page.evaluate(() => window.scrollTo(5, 7)),\n    )\n    await scrollElementTo(\n      page,\n      page.evaluate(() => document.querySelector('#slot')?.scrollTo(10, 15)),\n    )\n    await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n    await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n    await page.waitForTimeout(100)\n  })\n\n  test('resets scroll regions to the top when doing a regular visit', async ({ page }) => {\n    await page.getByText('Reset Scroll', { exact: true }).click()\n    await expect(page).toHaveURL('/links/preserve-scroll-page-two?foo=bar')\n    await expect(page.getByText('Foo is now bar')).toBeVisible()\n    await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n    await expect(page.getByText('Document scroll position is 0 & 0')).toBeVisible()\n    await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n  })\n\n  test('resets scroll regions to the top when returning false from a preserveScroll callback', async ({ page }) => {\n    consoleMessages.listen(page)\n    await page.getByText('Reset Scroll (Callback)', { exact: true }).click()\n\n    await expect(page).toHaveURL('/links/preserve-scroll-page-two?foo=foo')\n    await expect(page.getByText('Foo is now foo')).toBeVisible()\n    await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n    await expect(page.getByText('Document scroll position is 0 & 0')).toBeVisible()\n    await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n\n    await expect(consoleMessages.messages).toHaveLength(1)\n    const message = JSON.parse(consoleMessages.messages[0])\n\n    await expect(message.component).not.toBeUndefined()\n    await expect(message.props).not.toBeUndefined()\n    await expect(message.url).not.toBeUndefined()\n    await expect(message.version).not.toBeUndefined()\n  })\n\n  test('preserves scroll regions when using the \"preserve-scroll\" feature', async ({ page, browserName }) => {\n    test.skip(browserName === 'firefox', 'Firefox on Linux auto-adjusts scroll on content change')\n\n    await page.getByText('Preserve Scroll', { exact: true }).click()\n\n    await expect(page).toHaveURL('/links/preserve-scroll-page-two?foo=baz')\n    await expect(page.getByText('Foo is now baz')).toBeVisible()\n    await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n    await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n    await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n  })\n\n  test('preserves scroll regions when using the \"preserve-scroll\" feature from a callback', async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName === 'firefox', 'Firefox on Linux auto-adjusts scroll on content change')\n\n    consoleMessages.listen(page)\n    await page.getByTestId('preserve-callback').click()\n\n    await expect(page).toHaveURL('/links/preserve-scroll-page-two?foo=baz')\n    await expect(page.getByText('Foo is now baz')).toBeVisible()\n    await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n    await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n    await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n\n    const message = JSON.parse(consoleMessages.messages[0])\n\n    await expect(message.component).not.toBeUndefined()\n    await expect(message.props).not.toBeUndefined()\n    await expect(message.url).not.toBeUndefined()\n    await expect(message.version).not.toBeUndefined()\n  })\n\n  test('restores all tracked scroll regions when pressing the back button', async ({ page }) => {\n    await page.getByTestId('preserve').click()\n    await expect(page).toHaveURL('/links/preserve-scroll-page-two?foo=baz')\n    await page.waitForTimeout(100)\n\n    await scrollElementTo(\n      page,\n      page.evaluate(() => document.querySelector('#slot')?.scrollTo(0, 0)),\n    )\n\n    await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n\n    await page.goBack()\n\n    await expect(page).toHaveURL('/links/preserve-scroll')\n    await expect(page.getByText('Foo is now default')).toBeVisible()\n\n    await page.waitForFunction(\n      () => document.documentElement.scrollTop === 7 && document.documentElement.scrollLeft === 5,\n    )\n\n    await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n    await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n    await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n  })\n\n  test('restores the document scroll position when pressing the back button with history encryption enabled', async ({\n    page,\n  }) => {\n    await page.getByTestId('article').click()\n\n    await expect(page).toHaveURL('/article')\n    await expect(page.getByText('Article Header')).toBeVisible()\n\n    await scrollElementTo(\n      page,\n      page.evaluate(() => document.querySelector('#home')?.scrollIntoView()),\n    )\n\n    const bottomScrollPosition = await page.evaluate(() => document.documentElement.scrollTop)\n    expect(bottomScrollPosition).toBeGreaterThan(500)\n\n    await page.getByTestId('home').click()\n\n    await expect(page).toHaveURL('/')\n    await expect(page.getByText('This is the Test App Entrypoint page')).toBeVisible()\n\n    const homeScrollPosition = await page.evaluate(() => document.documentElement.scrollTop)\n    expect(homeScrollPosition).toBe(0)\n\n    await page.goBack()\n\n    await expect(page).toHaveURL('/article')\n    await expect(page.getByText('Article Header')).toBeVisible()\n\n    await page.waitForFunction(\n      (expectedPosition) => document.documentElement.scrollTop === expectedPosition,\n      bottomScrollPosition,\n      { timeout: 1000 },\n    )\n  })\n\n  test.skip('restores all tracked scroll regions when pressing the back button from another website', async ({\n    page,\n  }) => {\n    await page.getByRole('link', { name: 'Off-site link' }).click()\n\n    await expect(page).toHaveURL('non-inertia')\n\n    await page.goBack()\n\n    await expect(page).toHaveURL('/links/preserve-scroll')\n\n    await page.waitForFunction(\n      () => document.documentElement.scrollTop === 7 && document.documentElement.scrollLeft === 5,\n    )\n\n    await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n    await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n    await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n  })\n})\n\ntest.describe('scroll region with scrollable list', () => {\n  const preparePage = async (page: Page, url: string) => {\n    await page.goto('/links/scroll-region-list')\n    await expect(page.getByText('Scrollable list with scroll region')).toBeVisible()\n    await expect(page.getByText('Clicked user: none')).toBeVisible()\n\n    await page.evaluate(() => {\n      // @ts-ignore\n      window.navigateEvents = window.navigateEvents || []\n\n      document.addEventListener('inertia:navigate', (e) => {\n        // @ts-ignore\n        window.navigateEvents.push(e)\n      })\n    })\n\n    await scrollElementTo(\n      page,\n      page.evaluate(() => window.scrollTo(5, 7)),\n    )\n\n    await scrollElementTo(\n      page,\n      page.evaluate(() => document.querySelector('#slot')?.scrollTo(10, 15)),\n    )\n\n    await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n\n    await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n    await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n  }\n\n  Object.entries({\n    '/links/scroll-region-list': 'navigate to another url',\n    '/links/scroll-region-list?user_id=1': 'stay on the same url',\n  }).forEach(([url, description]) => {\n    test.describe(`when visiting a URL that would ${description}`, () => {\n      test.beforeEach(async ({ page }) => await preparePage(page, url))\n\n      test('resets scroll regions when clicking default button', async ({ page }) => {\n        await page.waitForFunction(() => (window as any).navigateEvents.length === 0)\n        await page.getByRole('button', { exact: true, name: 'Default' }).first().click()\n\n        await expect(page).toHaveURL('/links/scroll-region-list?user_id=1')\n        await expect(page.getByText('Clicked user: 1')).toBeVisible()\n        await page.waitForFunction(() => (window as any).navigateEvents.length === 1)\n\n        await page.waitForTimeout(100)\n        await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n        await page.waitForTimeout(100)\n\n        await expect(page.getByText('Document scroll position is 0 & 0')).toBeVisible()\n        await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n      })\n\n      test('resets scroll regions when clicking preserve false button', async ({ page }) => {\n        await page.waitForFunction(() => (window as any).navigateEvents.length === 0)\n        await page.getByRole('button', { exact: true, name: 'Preserve False' }).first().click()\n\n        await expect(page).toHaveURL('/links/scroll-region-list?user_id=1')\n        await expect(page.getByText('Clicked user: 1')).toBeVisible()\n        await page.waitForFunction(() => (window as any).navigateEvents.length === 1)\n\n        await page.waitForTimeout(100)\n        await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n        await page.waitForTimeout(100)\n\n        await expect(page.getByText('Document scroll position is 0 & 0')).toBeVisible()\n        await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n      })\n\n      test('preserves scroll regions when clicking preserve true button', async ({ page }) => {\n        await page.waitForFunction(() => (window as any).navigateEvents.length === 0)\n        await page.getByRole('button', { exact: true, name: 'Preserve True' }).first().click()\n\n        await expect(page).toHaveURL('/links/scroll-region-list?user_id=1')\n        await expect(page.getByText('Clicked user: 1')).toBeVisible()\n        await page.waitForFunction(() => (window as any).navigateEvents.length === 1)\n\n        await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n\n        await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n        await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n      })\n    })\n  })\n})\n\ntest.describe('URL fragment navigation (& automatic scrolling)', () => {\n  /** @see https://github.com/inertiajs/inertia/pull/257 */\n\n  test.beforeEach(async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/links/url-fragments')\n    await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n    await expect(page.getByText('Document scroll position is 0 & 0')).toBeVisible()\n  })\n\n  test('scrolls to the fragment element when making a visit to a different page', async ({ page }) => {\n    await page.getByRole('link', { name: 'Basic link' }).click()\n    await expect(page).toHaveURL('/links/url-fragments#target')\n    await waitForFragmentScroll(page)\n    await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n    await expect(page.getByText('Document scroll position is 0 & 0')).not.toBeVisible()\n  })\n\n  test('scrolls to the fragment element when making a visit to the same page', async ({ page }) => {\n    await page.getByRole('link', { exact: true, name: 'Fragment link' }).click()\n    await expect(page).toHaveURL('/links/url-fragments#target')\n    await waitForFragmentScroll(page)\n    await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n    await expect(page.getByText('Document scroll position is 0 & 0')).not.toBeVisible()\n  })\n\n  test('does not scroll to the fragment element when it does not exist on the page', async ({ page }) => {\n    await page.getByRole('link', { exact: true, name: 'Non-existent fragment link' }).click()\n    await expect(page).toHaveURL('/links/url-fragments#non-existent-fragment')\n    await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n    await expect(page.getByText('Document scroll position is 0 & 0')).toBeVisible()\n  })\n})\n\ntest.describe('scroll', () => {\n  test('scrolls to the fragment on initial page load', async ({ page }) => {\n    await page.goto('/article#far-down')\n    await expect(page.getByRole('heading', { name: 'Article Header' })).toBeVisible()\n\n    const scrollTop = await page.evaluate(() => document.documentElement.scrollTop)\n    expect(scrollTop).toBeGreaterThan(500)\n  })\n\n  test('does not scroll when clicking the same fragment link', async ({ page }) => {\n    /** @see https://github.com/inertiajs/inertia/issues/1921 */\n    await page.goto('/article#far-down')\n\n    await page.getByRole('button', { exact: true, name: 'Enable Smooth Scroll' }).click()\n    await page.getByRole('button', { exact: true, name: 'Clear Scroll Log' }).click()\n    await expect(page.getByText('Scroll log: []')).toBeVisible()\n\n    // Click the same link again\n    for (let i = 0; i < 5; i++) {\n      await page.getByRole('link', { exact: true, name: 'Article Far Down' }).click()\n    }\n    await expect(page.getByText('Scroll log: []')).toBeVisible()\n  })\n\n  test('scrolls to top after the page has been rendered', async ({ page, browserName }) => {\n    // Firefox in CI is slower, needs more time for multiple navigations\n    test.setTimeout(browserName === 'firefox' ? 30_000 : 10_000)\n\n    await page.goto('/scroll-after-render/1')\n\n    consoleMessages.listen(page)\n\n    const tries = 10\n\n    for (let i = 2; i < tries + 2; i++) {\n      await page.getByRole('link', { exact: true, name: 'Go to page ' + i }).click()\n      await expect(page.getByText('Page ' + i)).toBeVisible()\n      await expect(page).toHaveURL('/scroll-after-render/' + i)\n    }\n\n    const expectedMessages = Array.from({ length: tries }, () => ['ScrollY 100', 'Render', 'ScrollY 0']).flat()\n    await expect(consoleMessages.messages).toEqual(expectedMessages)\n  })\n\n  test('preserves scroll position within a scroll region while keeping scrolling when navigating', async ({ page }) => {\n    await page.goto('/scroll-region-preserve-url/1')\n    await expect(page.getByText('Page: 1')).toBeVisible()\n\n    await page.click('#scroll-and-navigate')\n    await expect(page.getByText('Page: 2')).toBeVisible()\n\n    // Verify scroll position was preserved (should be +100px, not 0)\n    const finalScroll = await page.locator('#scroll-container').evaluate((el) => el.scrollTop)\n    expect(finalScroll).toBeGreaterThan(100)\n  })\n})\n\ntest.describe('partial reloads', () => {\n  test.beforeEach(async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/links/partial-reloads')\n    await expect(page.getByText('Foo is now 1')).toBeVisible()\n    await expect(page.getByText('Bar is now 2')).toBeVisible()\n    await expect(page.getByText('Baz is now 3')).toBeVisible()\n  })\n\n  test('does not have headers specific to partial reloads when the feature is not being used', async ({ page }) => {\n    requests.listen(page)\n\n    await page.getByRole('link', { name: 'Update All' }).click()\n    await expect(page).toHaveURL('/links/partial-reloads?foo=1')\n\n    await expect(requests.requests).toHaveLength(1)\n\n    const request = requests.requests[0]\n\n    await expect(request.headers()['x-inertia-partial-component']).toBeUndefined()\n    await expect(request.headers()['x-inertia-partial-data']).toBeUndefined()\n  })\n\n  test('has headers specific to partial reloads', async ({ page }) => {\n    requests.listen(page)\n\n    await page.getByRole('link', { name: 'Only foo + bar' }).click()\n    await expect(page).toHaveURL('/links/partial-reloads?foo=1')\n\n    await expect(requests.requests).toHaveLength(1)\n\n    const request = requests.requests[0]\n\n    await expect(request.headers()['x-inertia-partial-component']).toBe('Links/PartialReloads')\n    await expect(request.headers()['x-inertia-partial-data']).toBe('headers,foo,bar')\n    await expect(request.headers()['accept']).toBe('text/html, application/xhtml+xml')\n    await expect(request.headers()['x-requested-with']).toBe('XMLHttpRequest')\n    await expect(request.headers()['x-inertia']).toBe('true')\n  })\n\n  test('it updates all props when the feature is not being used', async ({ page }) => {\n    await page.getByRole('link', { name: 'Update All' }).click()\n    await expect(page).toHaveURL('/links/partial-reloads?foo=1')\n\n    await expect(page.getByText('Foo is now 2')).toBeVisible()\n    await expect(page.getByText('Bar is now 3')).toBeVisible()\n    await expect(page.getByText('Baz is now 4')).toBeVisible()\n  })\n\n  test('it only updates props that are passed through \"only\"', async ({ page }) => {\n    await page.getByRole('link', { name: 'Only foo + bar' }).click()\n    await expect(page).toHaveURL('/links/partial-reloads?foo=1')\n\n    await expect(page.getByText('Foo is now 2')).toBeVisible()\n    await expect(page.getByText('Bar is now 3')).toBeVisible()\n    await expect(page.getByText('Baz is now 3')).toBeVisible()\n\n    await page.getByRole('link', { name: 'Only baz' }).click()\n    await expect(page).toHaveURL('/links/partial-reloads?foo=2')\n\n    await expect(page.getByText('Foo is now 2')).toBeVisible()\n    await expect(page.getByText('Bar is now 3')).toBeVisible()\n    await expect(page.getByText('Baz is now 5')).toBeVisible()\n\n    await page.getByRole('link', { name: 'Update All' }).click()\n    await expect(page).toHaveURL('/links/partial-reloads?foo=2')\n\n    await expect(page.getByText('Foo is now 3')).toBeVisible()\n    await expect(page.getByText('Bar is now 4')).toBeVisible()\n    await expect(page.getByText('Baz is now 5')).toBeVisible()\n  })\n\n  test('it only updates props that are not passed through \"except\"', async ({ page }) => {\n    await page.getByRole('link', { name: 'Except foo + bar' }).click()\n    await expect(page).toHaveURL('/links/partial-reloads?foo=1')\n\n    await expect(page.getByText('Foo is now 1')).toBeVisible()\n    await expect(page.getByText('Bar is now 2')).toBeVisible()\n    await expect(page.getByText('Baz is now 4')).toBeVisible()\n\n    await page.getByRole('link', { name: 'Except baz' }).click()\n    await expect(page).toHaveURL('/links/partial-reloads?foo=1')\n\n    await expect(page.getByText('Foo is now 2')).toBeVisible()\n    await expect(page.getByText('Bar is now 3')).toBeVisible()\n    await expect(page.getByText('Baz is now 4')).toBeVisible()\n  })\n})\n\ntest.describe('redirects', () => {\n  test('follows 303 redirects', async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/')\n\n    await page.getByRole('button', { name: 'Internal Redirect Link' }).click()\n    await shouldBeDumpPage(page, 'get')\n  })\n\n  test('follows external redirects', async ({ page }) => {\n    pageLoads.watch(page, 2)\n    await page.goto('/')\n\n    await page.getByRole('button', { name: 'External Redirect Link' }).click()\n    await expect(page).toHaveURL('/non-inertia')\n    await expect(pageLoads.count).toBe(2)\n  })\n})\n\ntest.describe('\"as\" attribute', () => {\n  test('GET defaults to link', async ({ page }) => {\n    await page.goto('/links/as-warning/get')\n    await expect(page.getByRole('link', { name: 'GET Link' })).toBeVisible()\n    await expect(page.getByRole('button', { name: 'GET Link' })).not.toBeVisible()\n  })\n\n  test('GET can display as button', async ({ page }) => {\n    await page.goto('/links/as-warning-false/get')\n    await expect(page.getByRole('link', { name: 'GET button Link' })).not.toBeVisible()\n    await expect(page.getByRole('button', { name: 'GET button Link' })).toBeVisible()\n  })\n\n  const data = [\n    { method: 'post', label: 'POST' },\n    { method: 'put', label: 'PUT' },\n    { method: 'patch', label: 'PATCH' },\n    { method: 'delete', label: 'DELETE' },\n  ] as const\n\n  data.forEach(({ method, label }) => {\n    test(`forces a button for non-GET ${label} links`, async ({ page }) => {\n      await page.goto(`/links/as-warning/${method}`)\n      await expect(page.getByRole('link', { name: `${label} Link` })).not.toBeVisible()\n      await expect(page.getByRole('button', { name: `${label} Link` })).toBeVisible()\n\n      await page.goto(`/links/as-warning-false/${method}`)\n      await expect(page.getByRole('link', { name: `${label} button Link` })).not.toBeVisible()\n      await expect(page.getByRole('button', { name: `${label} button Link` })).toBeVisible()\n    })\n  })\n})\n\ntest.describe('as component', () => {\n  test.skip(process.env.PACKAGE === 'svelte', 'Feature not supported by the Svelte adapter')\n\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/links/as-component/1')\n  })\n\n  test('can render', async ({ page }) => {\n    const button = await page.getByRole('button', { name: 'GET Custom Component' }).first()\n    await expect(button).toHaveCSS('background-color', 'rgb(0, 0, 255)')\n    await expect(button).toHaveCSS('color', 'rgb(255, 255, 255)')\n    await expect(button).toHaveCSS('padding', '10px')\n\n    await button.click()\n\n    const dump = await shouldBeDumpPage(page, 'get')\n    await expect(dump.method).toBe('get')\n  })\n\n  test('can render with different methods', async ({ page }) => {\n    await page.getByText('POST Custom Component').click()\n\n    const dump = await shouldBeDumpPage(page, 'post')\n    await expect(dump.method).toBe('post')\n  })\n\n  test('can render with data', async ({ page }) => {\n    await page.getByText('Custom Component with Data').click()\n\n    const dump = await shouldBeDumpPage(page, 'post')\n    await expect(dump.form).toEqual({ test: 'data' })\n  })\n\n  test('can render with headers', async ({ page }) => {\n    await page.getByText('Custom Component with Headers').click()\n\n    const dump = await shouldBeDumpPage(page, 'get')\n    await expect(dump.headers['x-test']).toBe('header')\n  })\n\n  test('can render with event handlers', async ({ page }) => {\n    await page.getByText('Custom Component with Events').click()\n\n    const dump = await shouldBeDumpPage(page, 'get')\n    await expect(dump.method).toBe('get')\n\n    // Check that events were tracked\n    const events = await page.evaluate(() => window.componentEvents)\n    await expect(events.length).toBe(3)\n\n    await expect(events.map((e) => e.eventName)).toEqual(['onStart', 'onSuccess', 'onFinish'])\n  })\n\n  test('can render with \"replace\" prop', async ({ page }) => {\n    await page.goto('/links/as-component/2')\n\n    await page.getByRole('button', { name: 'Custom Component with Replace' }).click()\n    await expect(page).toHaveURL('/links/as-component/3')\n\n    await page.goBack()\n    await expect(page).toHaveURL('/links/as-component/1')\n  })\n\n  test('can render with \"preserveState\" prop', async ({ page }) => {\n    await page.goto('/links/as-component/1')\n\n    const componentState = await page.locator('#state').textContent()\n\n    await page.getByRole('button', { name: 'Custom Component with Preserve State' }).click()\n    await expect(page).toHaveURL('/links/as-component/2')\n\n    const newComponentState = await page.locator('#state').textContent()\n\n    await expect(newComponentState).toBe(componentState)\n  })\n})\n\ntest.describe('as element', () => {\n  test.skip(process.env.PACKAGE === 'svelte', 'Feature not supported by the Svelte adapter')\n\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/links/as-element/1')\n  })\n\n  test('can render', async ({ page }) => {\n    const button = await page.getByText('GET Custom Element').first()\n    // Assert that it's a <div>\n    await expect(button.evaluate((node) => node.tagName)).resolves.toBe('DIV')\n\n    await expect(button).toHaveCSS('background-color', 'rgb(0, 0, 255)')\n    await expect(button).toHaveCSS('color', 'rgb(255, 255, 255)')\n    await expect(button).toHaveCSS('padding', '10px')\n\n    await button.click()\n\n    const dump = await shouldBeDumpPage(page, 'get')\n    await expect(dump.method).toBe('get')\n  })\n\n  test('can render with different methods', async ({ page }) => {\n    await page.getByText('POST Custom Element').click()\n\n    const dump = await shouldBeDumpPage(page, 'post')\n    await expect(dump.method).toBe('post')\n  })\n\n  test('can render with data', async ({ page }) => {\n    await page.getByText('Custom Element with Data').click()\n\n    const dump = await shouldBeDumpPage(page, 'post')\n    await expect(dump.form).toEqual({ test: 'data' })\n  })\n\n  test('can render with headers', async ({ page }) => {\n    await page.getByText('Custom Element with Headers').click()\n\n    const dump = await shouldBeDumpPage(page, 'get')\n    await expect(dump.headers['x-test']).toBe('header')\n  })\n\n  test('can render with event handlers', async ({ page }) => {\n    await page.getByText('Custom Element with Events').click()\n\n    const dump = await shouldBeDumpPage(page, 'get')\n    await expect(dump.method).toBe('get')\n\n    // Check that events were tracked\n    const events = await page.evaluate(() => window.componentEvents)\n    await expect(events.length).toBe(3)\n\n    await expect(events.map((e) => e.eventName)).toEqual(['onStart', 'onSuccess', 'onFinish'])\n  })\n\n  test('can render with \"replace\" prop', async ({ page }) => {\n    await page.goto('/links/as-element/2')\n\n    await page.getByText('Custom Element with Replace').click()\n    await expect(page).toHaveURL('/links/as-element/3')\n\n    await page.goBack()\n    await expect(page).toHaveURL('/links/as-element/1')\n  })\n\n  test('can render with \"preserveState\" prop', async ({ page }) => {\n    await page.goto('/links/as-element/1')\n\n    const componentState = await page.locator('#state').textContent()\n\n    await page.getByText('Custom Element with Preserve State').click()\n    await expect(page).toHaveURL('/links/as-element/2')\n\n    const newComponentState = await page.locator('#state').textContent()\n\n    await expect(newComponentState).toBe(componentState)\n  })\n})\n\ntest.describe('data-loading attribute', () => {\n  test('adds data-loading attribute to link component', async ({ page }) => {\n    await page.goto('/links/data-loading')\n    const link = await page.getByRole('link', { name: 'First' })\n    await link.click()\n    await expect(link).toHaveAttribute('data-loading', '')\n    await page.waitForResponse('sleep')\n    await expect(link).not.toHaveAttribute('data-loading')\n  })\n\n  test('handles data-loading attribute for cancelled requests', async ({ page }) => {\n    await page.goto('/links/data-loading')\n    const link1 = await page.getByRole('link', { name: 'First' })\n    const link2 = await page.getByRole('link', { name: 'Second' })\n    await link1.click()\n    await expect(link1).toHaveAttribute('data-loading', '')\n    await expect(link2).not.toHaveAttribute('data-loading', '')\n    await link2.click()\n    await expect(link1).not.toHaveAttribute('data-loading', '')\n    await expect(link2).toHaveAttribute('data-loading', '')\n    await page.waitForResponse('sleep')\n    await expect(link2).not.toHaveAttribute('data-loading')\n  })\n})\n\ntest('cancels pending request when navigating back', async ({ page }) => {\n  await page.goto('/links/cancel-sync-request/1')\n  await page.getByRole('link', { name: 'Go to Page 2' }).click()\n  await expect(page).toHaveURL('/links/cancel-sync-request/2')\n  await page.getByRole('link', { name: 'Go to Page 3' }).click() // This one is slow (500ms)\n  await page.goBack()\n  await expect(page).toHaveURL('/links/cancel-sync-request/1')\n  await page.waitForTimeout(750)\n  await expect(page).toHaveURL('/links/cancel-sync-request/1')\n  // make sure page 2 is still in the history stack\n  await page.goForward()\n  await expect(page).toHaveURL('/links/cancel-sync-request/2')\n  await page.goBack()\n  await expect(page).toHaveURL('/links/cancel-sync-request/1')\n})\n\ntest.describe('reactivity', () => {\n  test('will update href if prop is updated', async ({ page }) => {\n    await page.goto('/links/prop-update')\n    const link = await page.getByRole('link', { name: 'The Link' })\n    const button = await page.getByRole('button', { name: 'Change URL' })\n    await expect(link).toHaveAttribute('href', /\\/sleep$/)\n    await button.click()\n    await expect(link).toHaveAttribute('href', /\\/something-else$/)\n  })\n\n  test('will update the method, href, data, and headers when props are updated', async ({ page }) => {\n    await page.goto('/links/reactivity')\n\n    const link = await page.getByRole('link', { name: 'Submit' })\n    await expect(link).toHaveAttribute('href', /\\/dump\\/get\\?foo=bar$/)\n\n    await page.getByRole('button', { name: 'Change Link Props' }).click()\n\n    await expect(link).not.toBeVisible()\n    const button = await page.getByRole('button', { name: 'Submit' })\n    await button.click()\n\n    const dump = await shouldBeDumpPage(page, 'post')\n\n    await expect(dump.method).toBe('post')\n    await expect(dump.form).toEqual({ foo: 'baz' })\n    await expect(dump.headers['x-custom-header']).toBe('new-value')\n  })\n\n  test('will update prefetch and cacheFor when props are updated', async ({ page }) => {\n    await page.goto('/links/reactivity')\n\n    await page.getByRole('button', { name: 'Enable Prefetch (1s cache)' }).click()\n    const link = await page.getByRole('link', { name: 'Prefetch Link' })\n    const prefetchPromise = page.waitForRequest(\n      (request) => request.url().includes('/dump/get') && request.headers().purpose === 'prefetch',\n    )\n\n    // Wait for the page to be prefetched\n    await link.hover()\n    await prefetchPromise\n\n    // Visit the page and check that it was prefetched\n    requests.listen(page)\n    await link.click()\n    await expect(page).toHaveURL('dump/get')\n    await expect(requests.requests.length).toBe(0)\n\n    // Wait for cache to expire\n    await page.waitForTimeout(1200)\n\n    // Click the link again without hovering first\n    await page.goBack()\n    await page.getByRole('button', { name: 'Enable Prefetch (1s cache)' }).click()\n    const nonPrefetchPromise = page.waitForRequest(\n      (request) => request.url().includes('/dump/get') && request.headers().purpose !== 'prefetch',\n    )\n    await link.click()\n    await nonPrefetchPromise\n\n    await expect(requests.requests.length).toBe(1)\n  })\n})\n\ntest.describe('path traversal', () => {\n  test('it goes one level up', async ({ page }) => {\n    await page.goto('/links/sub/sub/')\n\n    await page.getByRole('link', { name: 'Up one level' }).click()\n    await expect(page).toHaveURL('/links/sub/')\n  })\n\n  test('it goes two levels up with a new path', async ({ page }) => {\n    await page.goto('/links/sub/sub/')\n\n    await page.getByRole('link', { name: 'Up two levels and open method' }).click()\n    await expect(page).toHaveURL('/links/method')\n  })\n\n  test('it goes three levels up', async ({ page }) => {\n    await page.goto('/links/sub/sub/')\n\n    await page.getByRole('link', { name: 'Up three levels' }).click()\n    await expect(page).toHaveURL('/')\n  })\n})\n"
  },
  {
    "path": "tests/manual-visits.spec.ts",
    "content": "import test, { expect } from '@playwright/test'\nimport {\n  clickAndWaitForResponse,\n  consoleMessages,\n  pageLoads,\n  requests,\n  scrollElementTo,\n  shouldBeDumpPage,\n  waitForFragmentScroll,\n} from './support'\n\ntest('visits a different page', async ({ page }) => {\n  pageLoads.watch(page)\n  await page.goto('/')\n  await page.getByRole('link', { name: 'Manual basic visits' }).click()\n  await expect(page).toHaveURL('visits/method')\n  await expect(page.getByText('This is the page that demonstrates manual visit methods')).toBeVisible()\n})\n\ntest('can make a location visit', async ({ page }) => {\n  test.skip(process.env.PACKAGE === 'svelte', 'Skipping for now until we diagnose')\n\n  pageLoads.watch(page, 2)\n  await page.goto('/visits/location')\n  await clickAndWaitForResponse(page, 'Location visit', 'dump/get')\n  await page.waitForLoadState('networkidle')\n  await expect(pageLoads.count).toBe(2)\n\n  const dump = await shouldBeDumpPage(page, 'get')\n\n  await expect(dump.headers).not.toHaveProperty('x-inertia')\n})\n\ntest.describe('Auto-cancellation', () => {\n  test('will automatically cancel a pending visits when a new request is made', async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/visits/automatic-cancellation')\n\n    consoleMessages.listen(page)\n\n    await page.getByRole('link', { name: 'Link' }).click()\n    await page.getByRole('link', { name: 'Link' }).click()\n\n    await expect(consoleMessages.messages).toHaveLength(3)\n\n    await expect(consoleMessages.messages[0]).toBe('started')\n    await expect(consoleMessages.messages[1]).toBe('cancelled')\n    await expect(consoleMessages.messages[2]).toBe('started')\n  })\n})\n\ntest.describe('Method', () => {\n  test.beforeEach(async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/visits/method')\n  })\n\n  test('can use the visit method without any options to make a GET request', async ({ page }) => {\n    await page.getByRole('link', { name: 'Standard visit Link' }).click()\n\n    const dump = await shouldBeDumpPage(page, 'get')\n\n    await expect(dump.method).toBe('get')\n    await expect(dump.query).toEqual({})\n    await expect(dump.form).toEqual({})\n  })\n\n  test('can use the visit method with a specific \"method\" option to manually set the request method', async ({\n    page,\n  }) => {\n    await page.getByRole('link', { name: 'Specific visit Link' }).click()\n\n    const dump = await shouldBeDumpPage(page, 'patch')\n\n    await expect(dump.method).toBe('patch')\n    await expect(dump.query).toEqual({})\n    await expect(dump.form).toEqual({})\n  })\n\n  const data = [\n    { method: 'get', label: 'GET' },\n    { method: 'post', label: 'POST' },\n    { method: 'put', label: 'PUT' },\n    { method: 'patch', label: 'PATCH' },\n    { method: 'delete', label: 'DELETE' },\n  ] as const\n\n  data.forEach(({ method, label }) => {\n    test(`can use the ${label} method`, async ({ page }) => {\n      await page.getByRole('link', { name: `${label} Link` }).click()\n\n      const dump = await shouldBeDumpPage(page, method)\n\n      await expect(dump.method).toBe(method)\n      await expect(dump.query).toEqual({})\n      await expect(dump.form).toEqual({})\n    })\n  })\n})\n\ntest.describe('Data', () => {\n  test.describe('plain objects', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/visits/data/object')\n      //   cy.intercept('/dump/**').as('spy')\n    })\n\n    test('passes data as params by default when using the visit method', async ({ page }) => {\n      await page.getByRole('link', { name: 'Visit Link' }).click()\n\n      const dump = await shouldBeDumpPage(page, 'get')\n\n      await expect(page).toHaveURL('/dump/get?foo=visit')\n      await expect(dump.method).toBe('get')\n      await expect(dump.query).toEqual({ foo: 'visit' })\n      await expect(dump.form).toEqual({})\n      await expect(dump.files).toEqual({})\n      await expect(dump.headers['content-type']).not.toBe('application/json')\n    })\n\n    test.describe('GET method', () => {\n      test('passes data as params', async ({ page }) => {\n        await page.getByRole('link', { name: 'GET Link' }).click()\n\n        const dump = await shouldBeDumpPage(page, 'get')\n\n        await expect(dump.method).toBe('get')\n        await expect(dump.query).toEqual({ bar: 'get' })\n        await expect(dump.form).toEqual({})\n        await expect(dump.files).toEqual({})\n        await expect(dump.headers['content-type']).not.toBe('application/json')\n      })\n\n      const data = [\n        { label: 'QSAF Brackets', formatter: 'brackets', expected: '?a[]=b&a[]=c', expectedObject: { a: ['b', 'c'] } },\n        { label: 'QSAF Indices', formatter: 'indices', expected: '?a[0]=b&a[1]=c', expectedObject: { a: ['b', 'c'] } },\n        { label: 'QSAF Default', formatter: 'default', expected: '?a[]=b&a[]=c', expectedObject: { a: ['b', 'c'] } },\n        { label: 'Delete Query Param', formatter: 'delete param', expected: '', expectedObject: {} },\n      ]\n\n      data.forEach(({ label, formatter, expected, expectedObject }) => {\n        test(`can use the ${formatter} query string array formatter`, async ({ page }) => {\n          await page.getByRole('link', { name: label }).click()\n\n          const dump = await shouldBeDumpPage(page, 'get')\n\n          await expect(dump.query).toEqual(expectedObject)\n          await expect(dump.method).toBe('get')\n          await expect(dump.form).toEqual({})\n          await expect(dump.headers['content-type']).not.toBe('application/json')\n        })\n      })\n    })\n\n    const data = [\n      { method: 'post', label: 'POST', form: { baz: 'post' } },\n      { method: 'put', label: 'PUT', form: { foo: 'put' } },\n      { method: 'patch', label: 'PATCH', form: { bar: 'patch' } },\n      { method: 'delete', label: 'DELETE', form: { baz: 'delete' } },\n    ] as const\n\n    data.forEach(({ method, label, form }) => {\n      test(`can pass data using the ${label} method`, async ({ page }) => {\n        await page.getByRole('link', { name: `${label} Link` }).click()\n\n        const dump = await shouldBeDumpPage(page, method)\n\n        await expect(dump.method).toBe(method)\n        await expect(dump.form).toEqual(form)\n        await expect(dump.files).toEqual({})\n        await expect(dump.headers['content-type']).toBe('application/json')\n      })\n    })\n  })\n\n  test.describe('FormData objects', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/visits/data/form-data')\n    })\n\n    const data = [\n      { method: 'post', label: 'Visit', form: { foo: 'visit' } },\n      { method: 'post', label: 'POST', form: { baz: 'post' } },\n      { method: 'put', label: 'PUT', form: { foo: 'put' } },\n      { method: 'patch', label: 'PATCH', form: { bar: 'patch' } },\n      { method: 'delete', label: 'DELETE', form: { baz: 'delete' } },\n    ] as const\n\n    data.forEach(({ method, label, form }) => {\n      test(`can pass data using the ${label} method`, async ({ page }) => {\n        await page.getByRole('link', { name: `${label} Link` }).click()\n\n        const dump = await shouldBeDumpPage(page, method)\n\n        await expect(dump.method).toBe(method)\n        await expect(dump.form).toEqual(form)\n        await expect(dump.files).toEqual([])\n        await expect(dump.headers['content-type']).toContain('multipart/form-data; boundary=')\n      })\n    })\n  })\n\n  test.describe('auto-converted objects (when files are present)', () => {\n    test.beforeEach(async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/visits/data/auto-converted')\n    })\n\n    const data = [\n      { method: 'post', label: 'POST' },\n      { method: 'put', label: 'PUT' },\n      { method: 'patch', label: 'PATCH' },\n      { method: 'delete', label: 'DELETE' },\n    ] as const\n\n    data.forEach(({ method, label }) => {\n      test(`auto-converts objects using the ${label} method`, async ({ page }) => {\n        await page.getByRole('link', { name: `${label} Link` }).click()\n\n        const dump = await shouldBeDumpPage(page, method)\n\n        await expect(dump.method).toBe(method)\n        await expect(dump.form).toEqual({ foo: 'bar' })\n        await expect(dump.files).not.toEqual([])\n        await expect(dump.files[0].originalname).toBe('example.jpg')\n        await expect(dump.headers['content-type']).toContain('multipart/form-data; boundary=')\n      })\n    })\n  })\n})\n\ntest.describe('Headers', () => {\n  test('has the default set of headers', async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/visits/headers')\n\n    await page.getByRole('link', { name: 'Standard visit Link' }).click()\n\n    const dump = await shouldBeDumpPage(page, 'get')\n\n    await expect(dump.headers['x-inertia']).toBe('true')\n    await expect(dump.headers['x-inertia-version']).toBeUndefined()\n    await expect(dump.headers['x-requested-with']).toBe('XMLHttpRequest')\n    await expect(dump.headers['accept']).toBe('text/html, application/xhtml+xml')\n  })\n\n  test('starts using the x-inertia-version header when a version was given from the back-end', async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/visits/headers/version')\n\n    await page.getByRole('link', { name: 'Standard visit Link' }).click()\n\n    const dump = await shouldBeDumpPage(page, 'get')\n\n    await expect(dump.headers['x-inertia-version']).toBe('example-version-header')\n  })\n\n  test('allows to set custom headers using the visit method', async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/visits/headers')\n\n    await page.getByRole('link', { name: 'Specific visit Link' }).click()\n\n    const dump = await shouldBeDumpPage(page, 'get')\n\n    await expect(dump.headers['x-inertia']).toBe('true')\n    await expect(dump.headers['x-requested-with']).toBe('XMLHttpRequest')\n    await expect(dump.headers['accept']).toBe('text/html, application/xhtml+xml')\n    await expect(dump.headers['foo']).toBe('bar')\n  })\n\n  const data = [\n    { method: 'post', label: 'POST', headerKey: 'baz', headerValue: 'foo' },\n    { method: 'put', label: 'PUT', headerKey: 'foo', headerValue: 'bar' },\n    { method: 'patch', label: 'PATCH', headerKey: 'bar', headerValue: 'baz' },\n    { method: 'delete', label: 'DELETE', headerKey: 'baz', headerValue: 'foo' },\n  ] as const\n\n  data.forEach(({ method, label, headerKey, headerValue }) => {\n    test(`allows to set custom headers using the ${label} method`, async ({ page }) => {\n      pageLoads.watch(page)\n      await page.goto('/visits/headers')\n\n      await page.getByRole('link', { exact: true, name: `${label} Link` }).click()\n\n      const dump = await shouldBeDumpPage(page, method)\n\n      await expect(dump.headers['x-inertia']).toBe('true')\n      await expect(dump.headers['x-requested-with']).toBe('XMLHttpRequest')\n      await expect(dump.headers['accept']).toBe('text/html, application/xhtml+xml')\n      await expect(dump.headers[headerKey]).toBe(headerValue)\n    })\n  })\n\n  test('cannot override built-in Inertia headers', async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/visits/headers')\n\n    await page.getByRole('link', { exact: true, name: 'Overriden Link' }).click()\n\n    const dump = await shouldBeDumpPage(page, 'post')\n\n    await expect(dump.headers['x-inertia']).toBe('true')\n    await expect(dump.headers['x-requested-with']).toBe('XMLHttpRequest')\n    await expect(dump.headers['accept']).toBe('text/html, application/xhtml+xml')\n    await expect(dump.headers['bar']).toBe('baz')\n  })\n})\n\ntest.describe('Replace', () => {\n  test.beforeEach(async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/')\n    await page.getByRole('link', { name: \"Manual 'Replace' visits\" }).click()\n    await expect(page).toHaveURL('visits/replace')\n  })\n\n  const data = [{ method: 'visit' }, { method: 'GET' }] as const\n\n  data.forEach(({ method }) => {\n    // TODO: Not working...\n    test(`replaces the current history state (${method} method)`, async ({ page, browserName }) => {\n      // Firefox handles goBack() differently after replaceState - skip this browser-specific test\n      test.skip(browserName === 'firefox', 'Firefox handles history.replaceState differently')\n\n      const responsePromise = page.waitForResponse('/dump/get')\n      await page.getByRole('link', { name: `[State] Replace ${method}: true` }).click()\n      await responsePromise\n      await shouldBeDumpPage(page, 'get')\n\n      await page.goBack()\n      await expect(page).toHaveURL('/')\n\n      await page.goForward()\n      await expect(page).toHaveURL('/dump/get')\n    })\n  })\n\n  data.forEach(({ method }) => {\n    test(`does not replace the current history state when it is set to false (${method} method)`, async ({ page }) => {\n      await page.getByRole('link', { name: `[State] Replace ${method}: false` }).click()\n      await shouldBeDumpPage(page, 'get')\n\n      await page.goBack()\n      await expect(page).toHaveURL('visits/replace')\n\n      await page.goForward()\n      await expect(page).toHaveURL('dump/get')\n    })\n  })\n})\n\ntest.describe('Preserve state', () => {\n  test.beforeEach(async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('visits/preserve-state')\n  })\n\n  const preserveData = [\n    {\n      testLabel: 'visit method',\n      label: '[State] Preserve visit: true',\n      expected: 'bar',\n    },\n    {\n      testLabel: 'GET method',\n      label: '[State] Preserve GET: true',\n      expected: 'get-bar',\n    },\n    {\n      testLabel: 'callback',\n      label: '[State] Preserve Callback: true',\n      expected: 'callback-bar',\n    },\n  ] as const\n\n  preserveData.forEach(({ testLabel, label, expected }) => {\n    test(`preserves the page's local state (${testLabel})`, async ({ page }) => {\n      await expect(page.getByText('Foo is now default')).toBeVisible()\n      await page.getByLabel('Example Field').fill('Example value')\n\n      const componentKey = await page.evaluate(() => (window as any)._inertia_page_key)\n      await expect(componentKey).not.toBeUndefined()\n\n      await page.getByRole('link', { name: label }).click()\n      await expect(page).toHaveURL(`/visits/preserve-state-page-two?foo=${expected}`)\n\n      const newComponentKey = await page.evaluate(() => (window as any)._inertia_page_key)\n      await expect(newComponentKey).not.toBeUndefined()\n\n      await expect(newComponentKey).toBe(componentKey)\n      await expect(page.getByLabel('Example Field')).toHaveValue('Example value')\n      await expect(page.getByText(`Foo is now ${expected}`)).toBeVisible()\n    })\n  })\n\n  const dontPreserveData = [\n    {\n      testLabel: 'visit method',\n      label: '[State] Preserve visit: false',\n      expected: 'baz',\n    },\n    {\n      testLabel: 'GET method',\n      label: '[State] Preserve GET: false',\n      expected: 'get-baz',\n    },\n    {\n      testLabel: 'callback',\n      label: '[State] Preserve Callback: false',\n      expected: 'callback-baz',\n    },\n  ] as const\n\n  dontPreserveData.forEach(({ testLabel, label, expected }) => {\n    test(`does not preserve the page's local state (${testLabel})`, async ({ page }) => {\n      await expect(page.getByText('Foo is now default')).toBeVisible()\n      await page.getByLabel('Example Field').fill('Another Value')\n\n      const componentKey = await page.evaluate(() => (window as any)._inertia_page_key)\n      await expect(componentKey).not.toBeUndefined()\n\n      await page.getByRole('link', { name: label }).click()\n      await expect(page).toHaveURL(`/visits/preserve-state-page-two?foo=${expected}`)\n\n      const newComponentKey = await page.evaluate(() => (window as any)._inertia_page_key)\n      await expect(newComponentKey).not.toBeUndefined()\n\n      await expect(newComponentKey).not.toBe(componentKey)\n      await expect(page.getByLabel('Example Field')).toHaveValue('')\n      await expect(page.getByText(`Foo is now ${expected}`)).toBeVisible()\n    })\n  })\n})\n\ntest.describe('Preserve scroll', () => {\n  test.describe('disabled (default)', () => {\n    test.beforeEach(async ({ page }) => {\n      await page.goto('/visits/preserve-scroll-false')\n      await expect(page.getByText('Foo is now default')).toBeVisible()\n\n      await scrollElementTo(\n        page,\n        page.evaluate(() => window.scrollTo(5, 7)),\n      )\n      await scrollElementTo(\n        page,\n        page.evaluate(() => document.querySelector('#slot')?.scrollTo(10, 15)),\n      )\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n    })\n\n    test('does not reset untracked scroll regions in persistent layouts (visit method)', async ({\n      page,\n      browserName,\n    }) => {\n      test.skip(browserName === 'firefox', 'Firefox on Linux auto-adjusts scroll on content change')\n\n      await page.getByRole('link', { exact: true, name: 'Reset Scroll' }).click()\n      await expect(page).toHaveURL('/visits/preserve-scroll-false-page-two?foo=bar')\n      await expect(page.getByText('Foo is now bar')).toBeVisible()\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 0 & 0')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n    })\n\n    test('does not reset untracked scroll regions in persistent layouts (GET method)', async ({\n      page,\n      browserName,\n    }) => {\n      test.skip(browserName === 'firefox', 'Firefox on Linux auto-adjusts scroll on content change')\n\n      await page.getByRole('link', { exact: true, name: 'Reset Scroll (GET)' }).click()\n      await expect(page).toHaveURL('/visits/preserve-scroll-false-page-two?foo=baz')\n      await expect(page.getByText('Foo is now baz')).toBeVisible()\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 0 & 0')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n    })\n\n    test('does not reset untracked scroll regions in persistent layouts when returning false from a preserveScroll callback', async ({\n      page,\n    }) => {\n      consoleMessages.listen(page)\n\n      await page\n        .getByRole('link', { exact: true, name: 'Reset Scroll (Callback)' })\n        .click({ position: { x: 50, y: 5 } })\n      await expect(page).toHaveURL('/visits/preserve-scroll-false-page-two?foo=foo')\n      await expect(page.getByText('Foo is now foo')).toBeVisible()\n\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 0 & 0')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n\n      await expect(consoleMessages.messages).toHaveLength(1)\n\n      const message = JSON.parse(consoleMessages.messages[0])\n\n      await expect(message.component).not.toBeUndefined()\n      await expect(message.props).not.toBeUndefined()\n      await expect(message.url).not.toBeUndefined()\n      await expect(message.version).not.toBeUndefined()\n    })\n\n    test('does not restore untracked scroll regions when pressing the back button (visit method)', async ({ page }) => {\n      await page.getByRole('link', { exact: true, name: 'Reset Scroll' }).click()\n\n      await expect(page).toHaveURL('/visits/preserve-scroll-false-page-two?foo=bar')\n      await expect(page.getByText('Foo is now bar')).toBeVisible()\n\n      await scrollElementTo(\n        page,\n        page.evaluate(() => document.querySelector('#slot')?.scrollTo(0, 0)),\n      )\n      await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n\n      await page.waitForTimeout(100)\n      await page.goBack()\n\n      await expect(page).toHaveURL('/visits/preserve-scroll-false')\n      await expect(page.getByText('Foo is now default')).toBeVisible()\n\n      await page.waitForFunction(\n        () => document.documentElement.scrollTop === 7 && document.documentElement.scrollLeft === 5,\n      )\n\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n    })\n\n    test('does not restore untracked scroll regions when pressing the back button (GET method)', async ({ page }) => {\n      await page.getByRole('link', { exact: true, name: 'Reset Scroll (GET)' }).click()\n\n      await expect(page).toHaveURL('/visits/preserve-scroll-false-page-two?foo=baz')\n      await expect(page.getByText('Foo is now baz')).toBeVisible()\n\n      await scrollElementTo(\n        page,\n        page.evaluate(() => document.querySelector('#slot')?.scrollTo(0, 0)),\n      )\n      await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n\n      await page.waitForTimeout(100)\n      await page.goBack()\n\n      await expect(page).toHaveURL('/visits/preserve-scroll-false')\n      await expect(page.getByText('Foo is now default')).toBeVisible()\n\n      await page.waitForFunction(\n        () => document.documentElement.scrollTop === 7 && document.documentElement.scrollLeft === 5,\n      )\n\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n    })\n\n    test('does not restore untracked scroll regions when returning true from a preserveScroll callback', async ({\n      page,\n    }) => {\n      consoleMessages.listen(page)\n\n      await page.getByRole('link', { name: 'Preserve Scroll (Callback)' }).click()\n\n      await expect(page).toHaveURL('/visits/preserve-scroll-false-page-two?foo=baz')\n      await expect(page.getByText('Foo is now baz')).toBeVisible()\n\n      await scrollElementTo(\n        page,\n        page.evaluate(() => document.querySelector('#slot')?.scrollTo(0, 0)),\n      )\n      await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n\n      const message = JSON.parse(consoleMessages.messages[0])\n\n      await expect(message.component).not.toBeUndefined()\n      await expect(message.props).not.toBeUndefined()\n      await expect(message.url).not.toBeUndefined()\n      await expect(message.version).not.toBeUndefined()\n\n      await page.waitForTimeout(100)\n      await page.goBack()\n      await page.waitForTimeout(100)\n\n      await expect(page).toHaveURL('/visits/preserve-scroll-false')\n      await expect(page.getByText('Foo is now default')).toBeVisible()\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n    })\n\n    test('does not restore untracked scroll regions when pressing the back button from another website', async ({\n      page,\n    }) => {\n      await page.getByRole('link', { name: 'Off-site link' }).click()\n\n      await expect(page).toHaveURL('non-inertia')\n\n      await page.waitForTimeout(100)\n      await page.goBack()\n\n      await expect(page).toHaveURL('/visits/preserve-scroll-false')\n      await expect(page.getByText('Foo is now default')).toBeVisible()\n\n      await page.waitForFunction(\n        () => document.documentElement.scrollTop === 7 && document.documentElement.scrollLeft === 5,\n      )\n\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n    })\n  })\n\n  test.describe('enabled', () => {\n    test.beforeEach(async ({ page }) => {\n      await page.goto('/visits/preserve-scroll')\n      await expect(page.getByText('Foo is now default')).toBeVisible()\n\n      await scrollElementTo(\n        page,\n        page.evaluate(() => window.scrollTo(5, 7)),\n      )\n      await scrollElementTo(\n        page,\n        page.evaluate(() => document.querySelector('#slot')?.scrollTo(10, 15)),\n      )\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n    })\n\n    test('resets scroll regions to the top when doing a regular visit (visit method)', async ({ page }) => {\n      await page.getByRole('link', { exact: true, name: 'Reset Scroll' }).click()\n      await expect(page).toHaveURL('/visits/preserve-scroll-page-two?foo=bar')\n      await expect(page.getByText('Foo is now bar')).toBeVisible()\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 0 & 0')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n    })\n\n    test('resets scroll regions to the top when doing a regular visit (GET method)', async ({ page }) => {\n      await page.getByRole('link', { exact: true, name: 'Reset Scroll (GET)' }).click()\n      await expect(page).toHaveURL('/visits/preserve-scroll-page-two?foo=baz')\n      await expect(page.getByText('Foo is now baz')).toBeVisible()\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 0 & 0')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n    })\n\n    test('resets scroll regions to the top when returning false from a preserveScroll callback', async ({ page }) => {\n      consoleMessages.listen(page)\n      await page.getByRole('link', { exact: true, name: 'Reset Scroll (Callback)' }).click()\n\n      await expect(page).toHaveURL('/visits/preserve-scroll-page-two?foo=foo')\n      await expect(page.getByText('Foo is now foo')).toBeVisible()\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 0 & 0')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n\n      await expect(consoleMessages.messages).toHaveLength(1)\n      const message = JSON.parse(consoleMessages.messages[0])\n\n      await expect(message.component).not.toBeUndefined()\n      await expect(message.props).not.toBeUndefined()\n      await expect(message.url).not.toBeUndefined()\n      await expect(message.version).not.toBeUndefined()\n    })\n\n    test('preserves scroll regions when using the \"preserve-scroll\" feature (visit method)', async ({ page }) => {\n      await page.getByRole('link', { exact: true, name: 'Preserve Scroll' }).click()\n\n      await expect(page).toHaveURL('/visits/preserve-scroll-page-two?foo=foo')\n      await expect(page.getByText('Foo is now foo')).toBeVisible()\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n    })\n\n    test('preserves scroll regions when using the \"preserve-scroll\" feature (GET method)', async ({ page }) => {\n      await page.getByRole('link', { exact: true, name: 'Preserve Scroll (GET)' }).click()\n\n      await expect(page).toHaveURL('/visits/preserve-scroll-page-two?foo=bar')\n      await expect(page.getByText('Foo is now bar')).toBeVisible()\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n    })\n\n    test('preserves scroll regions when using the \"preserve-scroll\" feature from a callback', async ({ page }) => {\n      consoleMessages.listen(page)\n      await page\n        .getByRole('link', { exact: true, name: 'Preserve Scroll (Callback)' })\n        .click({ position: { x: 50, y: 5 } })\n\n      await expect(page).toHaveURL('/visits/preserve-scroll-page-two?foo=baz')\n      await expect(page.getByText('Foo is now baz')).toBeVisible()\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n\n      const message = JSON.parse(consoleMessages.messages[0])\n\n      await expect(message.component).not.toBeUndefined()\n      await expect(message.props).not.toBeUndefined()\n      await expect(message.url).not.toBeUndefined()\n      await expect(message.version).not.toBeUndefined()\n    })\n\n    test('restores all tracked scroll regions when pressing the back button (visit method)', async ({ page }) => {\n      await page.getByRole('link', { exact: true, name: 'Preserve Scroll' }).click()\n      await expect(page).toHaveURL('/visits/preserve-scroll-page-two?foo=foo')\n      await page.waitForTimeout(100)\n\n      await scrollElementTo(\n        page,\n        page.evaluate(() => document.querySelector('#slot')?.scrollTo(0, 0)),\n      )\n\n      await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n\n      await page.goBack()\n\n      await expect(page).toHaveURL('/visits/preserve-scroll')\n      await expect(page.getByText('Foo is now default')).toBeVisible()\n\n      await page.waitForFunction(\n        () => document.documentElement.scrollTop === 7 && document.documentElement.scrollLeft === 5,\n      )\n\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n    })\n\n    test('restores all tracked scroll regions when pressing the back button (GET method)', async ({ page }) => {\n      await page.getByRole('link', { exact: true, name: 'Preserve Scroll (GET)' }).click()\n      await expect(page).toHaveURL('/visits/preserve-scroll-page-two?foo=bar')\n      await page.waitForTimeout(100)\n\n      await scrollElementTo(\n        page,\n        page.evaluate(() => document.querySelector('#slot')?.scrollTo(0, 0)),\n      )\n\n      await expect(page.getByText('Slot scroll position is 0 & 0')).toBeVisible()\n\n      await page.goBack()\n\n      await expect(page).toHaveURL('/visits/preserve-scroll')\n      await expect(page.getByText('Foo is now default')).toBeVisible()\n\n      await page.waitForFunction(\n        () => document.documentElement.scrollTop === 7 && document.documentElement.scrollLeft === 5,\n      )\n\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n    })\n\n    test('restores all tracked scroll regions when pressing the back button from another website', async ({ page }) => {\n      await page.getByRole('link', { name: 'Off-site link' }).click()\n\n      await expect(page).toHaveURL('non-inertia')\n\n      await page.goBack()\n\n      await expect(page).toHaveURL('/visits/preserve-scroll')\n      await expect(page.getByText('Foo is now default')).toBeVisible()\n\n      await page.waitForFunction(\n        () => document.documentElement.scrollTop === 7 && document.documentElement.scrollLeft === 5,\n      )\n\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 5 & 7')).toBeVisible()\n      await expect(page.getByText('Slot scroll position is 10 & 15')).toBeVisible()\n    })\n  })\n})\n\ntest.describe('URL fragment navigation (& automatic scrolling)', () => {\n  /** @see https://github.com/inertiajs/inertia/pull/257 */\n\n  test.beforeEach(async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/visits/url-fragments')\n    await expect(page.getByText('Document scroll position is 0 & 0')).toBeVisible()\n  })\n\n  const data = [{ label: 'visit' }, { label: 'GET visit' }]\n\n  data.forEach(({ label }) => {\n    test(`Scrolls to the fragment element when making a ${label} to a different page`, async ({ page }) => {\n      await page.getByRole('link', { name: `Basic ${label}` }).click()\n      await expect(page).toHaveURL('/visits/url-fragments#target')\n      await waitForFragmentScroll(page)\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 0 & 0')).not.toBeVisible()\n    })\n\n    test(`Scrolls to the fragment element when making a ${label} to the same page`, async ({ page }) => {\n      await page.getByRole('link', { exact: true, name: `Fragment ${label}` }).click()\n      await expect(page).toHaveURL('/visits/url-fragments#target')\n      await waitForFragmentScroll(page)\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 0 & 0')).not.toBeVisible()\n    })\n\n    test(`Does not scroll to the fragment element when it does not exist on the page (${label})`, async ({ page }) => {\n      await page.getByRole('link', { exact: true, name: `Non-existent fragment ${label}` }).click()\n      await expect(page).toHaveURL('/visits/url-fragments#non-existent-fragment')\n      await page.getByRole('button', { exact: true, name: 'Update scroll positions' }).click()\n      await expect(page.getByText('Document scroll position is 0 & 0')).toBeVisible()\n    })\n  })\n})\n\ntest.describe('Partial Reloads', () => {\n  test.beforeEach(async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/visits/partial-reloads')\n    await expect(page.getByText('Foo is now 1')).toBeVisible()\n    await expect(page.getByText('Bar is now 2')).toBeVisible()\n    await expect(page.getByText('Baz is now 3')).toBeVisible()\n  })\n\n  const data = [{ label: 'visit' }, { label: 'GET' }]\n\n  data.forEach(({ label }) => {\n    test(`does not have headers specific to partial reloads when the feature is not being used ${label}`, async ({\n      page,\n    }) => {\n      test.setTimeout(10_000)\n      requests.listen(page)\n\n      await page.getByRole('link', { name: `Update All (${label})` }).click()\n      await expect(page).toHaveURL('/visits/partial-reloads?foo=1')\n\n      await expect(requests.requests).toHaveLength(1)\n\n      const request = requests.requests[0]\n\n      await expect(request.headers()['x-inertia-partial-component']).toBeUndefined()\n      await expect(request.headers()['x-inertia-partial-data']).toBeUndefined()\n    })\n\n    test(`has headers specific to \"only\" partial reloads (${label})`, async ({ page }) => {\n      requests.listen(page)\n\n      await page.getByRole('link', { name: `'Only' foo + bar (${label})` }).click()\n      await expect(page).toHaveURL('/visits/partial-reloads?foo=1')\n\n      await expect(requests.requests).toHaveLength(1)\n\n      const request = requests.requests[0]\n\n      await expect(request.headers()['x-inertia-partial-component']).toBe('Visits/PartialReloads')\n      await expect(request.headers()['x-inertia-partial-data']).toBe('headers,foo,bar')\n      await expect(request.headers()['accept']).toBe('text/html, application/xhtml+xml')\n      await expect(request.headers()['x-requested-with']).toBe('XMLHttpRequest')\n      await expect(request.headers()['x-inertia']).toBe('true')\n    })\n\n    test(`has headers specific to \"except\" partial reloads (${label})`, async ({ page }) => {\n      requests.listen(page)\n\n      await page.getByRole('link', { name: `'Except' foo + bar (${label})` }).click()\n      await expect(page).toHaveURL('/visits/partial-reloads?foo=1')\n\n      await expect(requests.requests).toHaveLength(1)\n\n      const request = requests.requests[0]\n\n      await expect(request.headers()['x-inertia-partial-component']).toBe('Visits/PartialReloads')\n      await expect(request.headers()['x-inertia-partial-except']).toBe('foo,bar')\n      await expect(request.headers()['accept']).toBe('text/html, application/xhtml+xml')\n      await expect(request.headers()['x-requested-with']).toBe('XMLHttpRequest')\n      await expect(request.headers()['x-inertia']).toBe('true')\n    })\n\n    test(`it updates all props when the feature is not being used (${label})`, async ({ page }) => {\n      await page.getByRole('link', { name: `Update All (${label})` }).click()\n      await expect(page).toHaveURL('/visits/partial-reloads?foo=1')\n\n      await expect(page.getByText('Foo is now 2')).toBeVisible()\n      await expect(page.getByText('Bar is now 3')).toBeVisible()\n      await expect(page.getByText('Baz is now 4')).toBeVisible()\n    })\n\n    test(`it only updates props that are passed through \"only\" (${label})`, async ({ page }) => {\n      await page.getByRole('link', { name: `'Only' foo + bar (${label})` }).click()\n\n      await expect(page).toHaveURL('/visits/partial-reloads?foo=1')\n\n      await expect(page.getByText('Foo is now 2')).toBeVisible()\n      await expect(page.getByText('Bar is now 3')).toBeVisible()\n      await expect(page.getByText('Baz is now 3')).toBeVisible()\n\n      await page.getByRole('link', { name: `'Only' baz (${label})` }).click()\n      await expect(page).toHaveURL('/visits/partial-reloads?foo=2')\n\n      await expect(page.getByText('Foo is now 2')).toBeVisible()\n      await expect(page.getByText('Bar is now 3')).toBeVisible()\n      await expect(page.getByText('Baz is now 5')).toBeVisible()\n\n      await page.getByRole('link', { name: `Update All (${label})` }).click()\n      await expect(page).toHaveURL('/visits/partial-reloads?foo=2')\n\n      await expect(page.getByText('Foo is now 3')).toBeVisible()\n      await expect(page.getByText('Bar is now 4')).toBeVisible()\n      await expect(page.getByText('Baz is now 5')).toBeVisible()\n    })\n\n    test(`it only updates props that are not passed through \"except\" (${label})`, async ({ page }) => {\n      await page.getByRole('link', { name: `'Except' foo + bar (${label})` }).click()\n      await expect(page).toHaveURL('/visits/partial-reloads?foo=1')\n\n      await expect(page.getByText('Foo is now 1')).toBeVisible()\n      await expect(page.getByText('Bar is now 2')).toBeVisible()\n      await expect(page.getByText('Baz is now 4')).toBeVisible()\n\n      await page.getByRole('link', { name: `'Except' baz (${label})` }).click()\n      await expect(page).toHaveURL('/visits/partial-reloads?foo=1')\n\n      await expect(page.getByText('Foo is now 2')).toBeVisible()\n      await expect(page.getByText('Bar is now 3')).toBeVisible()\n      await expect(page.getByText('Baz is now 4')).toBeVisible()\n    })\n  })\n})\n\ntest('can reload on mount', async ({ page }) => {\n  await page.goto('/visits/reload-on-mount')\n  await expect(page.getByText('Name is mounted!')).toBeVisible()\n})\n\ntest.describe('Concurrent Reloads', () => {\n  test('does not cancel the first request when a second reload is fired', async ({ page }) => {\n    await page.goto('/reload/concurrent')\n\n    await expect(page.locator('#foo')).toHaveText('Foo: initial foo')\n    await expect(page.locator('#bar')).toHaveText('Bar: initial bar')\n\n    requests.listen(page)\n\n    await page.getByRole('button', { name: 'Reload both props' }).click()\n\n    await page.waitForResponse(\n      (response) => response.request().headers()['x-inertia-partial-data'] === 'foo' && response.status() === 200,\n    )\n\n    await page.waitForResponse(\n      (response) => response.request().headers()['x-inertia-partial-data'] === 'bar' && response.status() === 200,\n    )\n\n    await expect(page.locator('#foo')).toContainText('foo reloaded at')\n    await expect(page.locator('#bar')).toContainText('bar reloaded at')\n\n    const reloadRequests = requests.requests.filter(\n      (r) => r.headers()['x-inertia-partial-data'] && r.url().includes('/reload/concurrent'),\n    )\n    expect(reloadRequests).toHaveLength(2)\n  })\n\n  test('does not cancel the first request when a second reload with data is fired', async ({ page }) => {\n    await page.goto('/reload/concurrent-with-data')\n\n    await expect(page.locator('#foo')).toHaveText('Foo: initial foo')\n    await expect(page.locator('#bar')).toHaveText('Bar: initial bar')\n\n    requests.listen(page)\n\n    await page.getByRole('button', { name: 'Reload both props with data' }).click()\n\n    await page.waitForResponse(\n      (response) => response.request().headers()['x-inertia-partial-data'] === 'foo' && response.status() === 200,\n    )\n\n    await page.waitForResponse(\n      (response) => response.request().headers()['x-inertia-partial-data'] === 'bar' && response.status() === 200,\n    )\n\n    await expect(page.locator('#foo')).toContainText('foo reloaded (week) at')\n    await expect(page.locator('#bar')).toContainText('bar reloaded (week) at')\n\n    const reloadRequests = requests.requests.filter(\n      (r) => r.headers()['x-inertia-partial-data'] && r.url().includes('/reload/concurrent-with-data'),\n    )\n    expect(reloadRequests).toHaveLength(2)\n  })\n})\n\ntest.describe('Error bags', () => {\n  test.beforeEach(async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/visits/error-bags')\n  })\n\n  test('does not use error bags by default', async ({ page }) => {\n    await page.getByRole('link', { name: 'Default visit' }).click()\n\n    const dump = await shouldBeDumpPage(page, 'post')\n\n    await expect(dump.method).toBe('post')\n    await expect(dump.headers).not.toHaveProperty('x-inertia-error-bag')\n  })\n\n  test('uses error bags using the visit method', async ({ page }) => {\n    await page.getByRole('link', { name: 'Basic visit' }).click()\n\n    const dump = await shouldBeDumpPage(page, 'post')\n\n    await expect(dump.method).toBe('post')\n    await expect(dump.headers['x-inertia-error-bag']).toContain('visitErrorBag')\n    await expect(dump.form.foo).toBe('bar')\n  })\n\n  test('uses error bags using the POST method', async ({ page }) => {\n    await page.getByRole('link', { name: 'POST visit' }).click()\n\n    const dump = await shouldBeDumpPage(page, 'post')\n\n    await expect(dump.method).toBe('post')\n    await expect(dump.headers['x-inertia-error-bag']).toContain('postErrorBag')\n    await expect(dump.form.foo).toBe('baz')\n  })\n})\n\ntest.describe('Wayfinder object', () => {\n  test.beforeEach(async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/visits/wayfinder')\n  })\n\n  test('can use UrlMethodPair object with visit method', async ({ page }) => {\n    await page.getByRole('link', { name: 'Wayfinder object visit' }).click()\n\n    const dump = await shouldBeDumpPage(page, 'post')\n\n    await expect(dump.method).toBe('post')\n    await expect(dump.query).toEqual({})\n    await expect(dump.form).toEqual({})\n  })\n\n  test('can override UrlMethodPair method with options parameter', async ({ page }) => {\n    await page.getByRole('link', { name: 'Wayfinder object method override' }).click()\n\n    const dump = await shouldBeDumpPage(page, 'patch')\n\n    await expect(dump.method).toBe('patch')\n    await expect(dump.query).toEqual({})\n    await expect(dump.form).toEqual({})\n  })\n})\n\ntest.describe('Redirects', () => {\n  test('follows 303 redirects', async ({ page }) => {\n    pageLoads.watch(page)\n    await page.goto('/')\n\n    await page.getByRole('link', { name: 'Manual Redirect visit' }).click()\n    await shouldBeDumpPage(page, 'get')\n  })\n\n  test('follows external redirects', async ({ page }) => {\n    pageLoads.watch(page, 2)\n    await page.goto('/')\n\n    await page.getByRole('link', { name: 'Manual External Redirect visit' }).click()\n    await expect(page).toHaveURL('/non-inertia')\n    await expect(pageLoads.count).toBe(2)\n  })\n})\n\ntest('can do a subsequent visit after the previous visit has thrown an error in onSuccess', async ({ page }) => {\n  pageLoads.watch(page)\n\n  consoleMessages.listen(page)\n\n  await page.goto('/visits/after-error/1')\n  await expect(page.getByRole('link', { name: 'Throw error on success' })).toBeVisible()\n\n  await expect(consoleMessages.messages).toHaveLength(0)\n  await expect(consoleMessages.errors).toHaveLength(0)\n\n  const response = page.waitForResponse('/visits/after-error/2')\n\n  await page.getByRole('link', { name: 'Throw error on success' }).click()\n  await response\n\n  // Wait for any error to propagate (some browsers may not fire pageerror for framework-caught errors)\n  await page.waitForTimeout(500)\n\n  await expect(consoleMessages.messages).toHaveLength(0)\n\n  // Verify an error was caught if the browser propagated it\n  if (consoleMessages.errors.length > 0) {\n    await expect(consoleMessages.errors[0]).toContain('Error after visit')\n  }\n\n  // The main test: we can still do a subsequent visit after the error\n  await page.getByRole('link', { name: 'Visit dump page' }).click()\n\n  const dump = await shouldBeDumpPage(page, 'get')\n\n  await expect(dump.method).toBe('get')\n  await expect(dump.form).toEqual({})\n})\n\ntest('vue proxies synced back to the core adapter are not stored in history state', async ({ page }) => {\n  test.skip(process.env.PACKAGE !== 'vue3', 'Vue 3 specific test')\n  test.setTimeout(10_000)\n\n  pageLoads.watch(page)\n  await page.goto('/visits/proxy')\n  await expect(page.getByText('Site ID: 1')).toBeVisible()\n  await expect(page.getByRole('button', { name: 'Update First Site Ref' })).toBeVisible()\n\n  const fooText = await page.locator('#foo').innerText()\n  const statusText = await page.locator('#status-1').innerText()\n  await expect(statusText).toBe('Statuses: running')\n\n  await page.getByRole('button', { name: 'Update First Site Ref' }).click()\n\n  const newStatusText = await page.locator('#status-1').innerText()\n  await expect(newStatusText).not.toBe(statusText)\n  await expect(newStatusText.startsWith('Statuses: frontend-')).toBeTruthy()\n\n  await page.getByRole('button', { name: 'Reload' }).click()\n  await expect(page.locator('#foo')).not.toHaveText(fooText)\n  await expect(await page.locator('#status-1').innerText()).toBe(newStatusText)\n\n  const newFooText = await page.locator('#foo').innerText()\n\n  // Navigate away...\n  await page.getByRole('link', { name: 'Go Home' }).click()\n  await expect(page).toHaveURL('/')\n\n  // Go back...\n  await page.goBack()\n  await expect(page).toHaveURL('/visits/proxy')\n\n  // Ensure state is preserved...\n  await expect(page.locator('#foo')).toHaveText(newFooText)\n  await expect(await page.locator('#status-1').innerText()).toBe(newStatusText)\n\n  // Update ref again...\n  await page.getByRole('button', { name: 'Update First Site Ref' }).click()\n\n  const updatedStatusText = await page.locator('#status-1').innerText()\n  await expect(updatedStatusText).not.toBe(newStatusText)\n  await expect(updatedStatusText.startsWith('Statuses: frontend-')).toBeTruthy()\n\n  // Reload again...\n  await page.getByRole('button', { name: 'Reload' }).click()\n  await expect(page.locator('#foo')).not.toHaveText(newFooText)\n\n  // Ensure updated status is still there\n  await expect(await page.locator('#status-1').innerText()).toBe(updatedStatusText)\n})\n"
  },
  {
    "path": "tests/match-props-on-key.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\n\ntest('can match props by a key', async ({ page }) => {\n  await page.goto('/match-props-on-key')\n\n  await expect(page.getByText('bar count is 5')).toBeVisible()\n  await expect(page.getByText('baz count is 5')).toBeVisible()\n  await expect(page.getByText('foo.data count is 5')).toBeVisible()\n  await expect(page.getByText('first foo.data name is User 1')).toBeVisible()\n  await expect(page.getByText('last foo.data name is User 5')).toBeVisible()\n  await expect(page.getByText('foo.companies count is 5')).toBeVisible()\n  await expect(page.getByText('first foo.companies name is Company 1')).toBeVisible()\n  await expect(page.getByText('last foo.companies name is Company 5')).toBeVisible()\n  await expect(page.getByText('foo.teams count is 5')).toBeVisible()\n  await expect(page.getByText('first foo.teams name is Team 1')).toBeVisible()\n  await expect(page.getByText('last foo.teams name is Team 5')).toBeVisible()\n  await expect(page.getByText('foo.page is 0')).toBeVisible()\n  await expect(page.getByText('foo.per_page is 5')).toBeVisible()\n  await expect(page.getByText('foo.meta.label is first')).toBeVisible()\n\n  await page.getByRole('button', { name: 'Reload' }).click()\n\n  await expect(page.getByText('bar count is 5')).toBeVisible()\n  await expect(page.getByText('baz count is 10')).toBeVisible()\n  await expect(page.getByText('foo.data count is 5')).toBeVisible()\n  await expect(page.getByText('first foo.data name is User 1')).toBeVisible()\n  await expect(page.getByText('last foo.data name is User 5')).toBeVisible()\n  await expect(page.getByText('foo.companies count is 5')).toBeVisible()\n  await expect(page.getByText('first foo.companies name is Company 1')).toBeVisible()\n  await expect(page.getByText('last foo.companies name is Company 5')).toBeVisible()\n  await expect(page.getByText('foo.teams count is 10')).toBeVisible()\n  await expect(page.getByText('first foo.teams name is Team 1')).toBeVisible()\n  await expect(page.getByText('last foo.teams name is Team 10')).toBeVisible()\n  await expect(page.getByText('foo.page is 1')).toBeVisible()\n  await expect(page.getByText('foo.per_page is 5')).toBeVisible()\n  await expect(page.getByText('foo.meta.label is second')).toBeVisible()\n\n  await page.getByRole('button', { name: 'Reload' }).click()\n\n  await expect(page.getByText('bar count is 5')).toBeVisible()\n  await expect(page.getByText('baz count is 15')).toBeVisible()\n  await expect(page.getByText('foo.data count is 5')).toBeVisible()\n  await expect(page.getByText('first foo.data name is User 1')).toBeVisible()\n  await expect(page.getByText('last foo.data name is User 5')).toBeVisible()\n  await expect(page.getByText('foo.companies count is 5')).toBeVisible()\n  await expect(page.getByText('first foo.companies name is Company 1')).toBeVisible()\n  await expect(page.getByText('last foo.companies name is Company 5')).toBeVisible()\n  await expect(page.getByText('foo.teams count is 15')).toBeVisible()\n  await expect(page.getByText('first foo.teams name is Team 1')).toBeVisible()\n  await expect(page.getByText('last foo.teams name is Team 15')).toBeVisible()\n  await expect(page.getByText('foo.page is 2')).toBeVisible()\n  await expect(page.getByText('foo.per_page is 5')).toBeVisible()\n  await expect(page.getByText('foo.meta.label is third')).toBeVisible()\n\n  await page.getByRole('button', { name: 'Get Fresh' }).click()\n\n  await expect(page.getByText('bar count is 5')).toBeVisible()\n  await expect(page.getByText('baz count is 5')).toBeVisible()\n  await expect(page.getByText('foo.data count is 5')).toBeVisible()\n  await expect(page.getByText('first foo.data name is User 1')).toBeVisible()\n  await expect(page.getByText('last foo.data name is User 5')).toBeVisible()\n  await expect(page.getByText('foo.companies count is 5')).toBeVisible()\n  await expect(page.getByText('first foo.companies name is Company 1')).toBeVisible()\n  await expect(page.getByText('last foo.companies name is Company 5')).toBeVisible()\n  await expect(page.getByText('foo.teams count is 5')).toBeVisible()\n  await expect(page.getByText('first foo.teams name is Team 1')).toBeVisible()\n  await expect(page.getByText('last foo.teams name is Team 5')).toBeVisible()\n  await expect(page.getByText('foo.page is 0')).toBeVisible()\n  await expect(page.getByText('foo.per_page is 5')).toBeVisible()\n  await expect(page.getByText('foo.meta.label is first')).toBeVisible()\n\n  await page.getByRole('button', { name: 'Reload' }).click()\n\n  await expect(page.getByText('bar count is 5')).toBeVisible()\n  await expect(page.getByText('baz count is 10')).toBeVisible()\n  await expect(page.getByText('foo.data count is 5')).toBeVisible()\n  await expect(page.getByText('first foo.data name is User 1')).toBeVisible()\n  await expect(page.getByText('last foo.data name is User 5')).toBeVisible()\n  await expect(page.getByText('foo.companies count is 5')).toBeVisible()\n  await expect(page.getByText('first foo.companies name is Company 1')).toBeVisible()\n  await expect(page.getByText('last foo.companies name is Company 5')).toBeVisible()\n  await expect(page.getByText('foo.teams count is 10')).toBeVisible()\n  await expect(page.getByText('first foo.teams name is Team 1')).toBeVisible()\n  await expect(page.getByText('last foo.teams name is Team 10')).toBeVisible()\n  await expect(page.getByText('foo.page is 1')).toBeVisible()\n  await expect(page.getByText('foo.per_page is 5')).toBeVisible()\n  await expect(page.getByText('foo.meta.label is second')).toBeVisible()\n})\n"
  },
  {
    "path": "tests/merge-props.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport { clickAndWaitForResponse } from './support'\n\ntest('can merge props', async ({ page }) => {\n  await page.goto('/merge-props')\n\n  await expect(page.getByText('bar count is 5')).toBeVisible()\n  await expect(page.getByText('foo count is 5')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Reload', null, 'button')\n\n  await expect(page.getByText('bar count is 5')).toBeVisible()\n  await expect(page.getByText('foo count is 10')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Reload', null, 'button')\n\n  await expect(page.getByText('bar count is 5')).toBeVisible()\n  await expect(page.getByText('foo count is 15')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Get Fresh', null, 'button')\n\n  await expect(page.getByText('bar count is 5')).toBeVisible()\n  await expect(page.getByText('foo count is 5')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Reload', null, 'button')\n\n  await expect(page.getByText('bar count is 5')).toBeVisible()\n  await expect(page.getByText('foo count is 10')).toBeVisible()\n})\n\ntest('can append to nested props', async ({ page }) => {\n  await page.goto('/merge-nested-props/append')\n\n  await expect(page.getByText('User 1, User 2, User 3')).toBeVisible()\n  await expect(page.getByText('Page: 1, Per Page: 3')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Load More', '/merge-nested-props/append?page=2', 'button')\n\n  await expect(page.getByText('User 1, User 2, User 3, User 4, User 5, User 6')).toBeVisible()\n  await expect(page.getByText('Page: 2, Per Page: 3')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Load More', '/merge-nested-props/append?page=3', 'button')\n\n  await expect(page.getByText('User 1, User 2, User 3, User 4, User 5, User 6, User 7, User 8, User 9')).toBeVisible()\n  await expect(page.getByText('Page: 3, Per Page: 3')).toBeVisible()\n})\n\ntest('can prepend to nested props', async ({ page }) => {\n  await page.goto('/merge-nested-props/prepend')\n\n  await expect(page.getByText('User 3, User 2, User 1')).toBeVisible()\n  await expect(page.getByText('Page: 1, Per Page: 3')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Load More', '/merge-nested-props/prepend?page=2', 'button')\n\n  await expect(page.getByText('User 6, User 5, User 4, User 3, User 2, User 1')).toBeVisible()\n  await expect(page.getByText('Page: 2, Per Page: 3')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Load More', '/merge-nested-props/prepend?page=3', 'button')\n\n  await expect(page.getByText('User 9, User 8, User 7, User 6, User 5, User 4, User 3, User 2, User 1')).toBeVisible()\n  await expect(page.getByText('Page: 3, Per Page: 3')).toBeVisible()\n})\n\ntest('can append to nested props with matchOn', async ({ page }) => {\n  await page.goto('/merge-nested-props-with-match/append')\n\n  await expect(\n    page.getByText('User 1 - initial, User 2 - initial, User 3 - initial, User 4 - initial, User 5 - initial'),\n  ).toBeVisible()\n  await expect(page.getByText('Page: 1, Per Page: 5')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Load More', page.url() + '?page=2', 'button')\n\n  await expect(\n    page.getByText(\n      'User 1 - initial, User 2 - initial, User 3 - initial, User 4 - subsequent, User 5 - subsequent, User 6 - subsequent, User 7 - subsequent, User 8 - subsequent',\n    ),\n  ).toBeVisible()\n  await expect(page.getByText('Page: 2, Per Page: 5')).toBeVisible()\n})\n\ntest('can prepend to nested props with matchOn', async ({ page }) => {\n  await page.goto('/merge-nested-props-with-match/prepend')\n\n  await expect(\n    page.getByText('User 4 - initial, User 5 - initial, User 6 - initial, User 7 - initial, User 8 - initial'),\n  ).toBeVisible()\n  await expect(page.getByText('Page: 1, Per Page: 5')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Load More', page.url() + '?page=2', 'button')\n\n  await expect(\n    page.getByText(\n      'User 1 - subsequent, User 2 - subsequent, User 3 - subsequent, User 4 - subsequent, User 5 - subsequent, User 6 - initial, User 7 - initial, User 8 - initial',\n    ),\n  ).toBeVisible()\n  await expect(page.getByText('Page: 2, Per Page: 5')).toBeVisible()\n})\n\ntest('can selectively merge nested props in complex object', async ({ page }) => {\n  await page.goto('/complex-merge-selective')\n\n  await expect(page.getByText('name is John')).toBeVisible()\n  await expect(page.getByText('users: a, b, c')).toBeVisible()\n  await expect(page.getByText('chat.data: 1, 2, 3')).toBeVisible()\n  await expect(page.getByText('post.id: 1')).toBeVisible()\n  await expect(page.getByText('post.comments.allowed: true')).toBeVisible()\n  await expect(page.getByText('post.comments.data: A, B, C')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Reload', null, 'button')\n\n  await expect(page.getByText('name is Jane')).toBeVisible()\n  await expect(page.getByText('users: d, e, f')).toBeVisible()\n  await expect(page.getByText('chat.data: 1, 2, 3, 4, 5, 6')).toBeVisible()\n  await expect(page.getByText('post.id: 1')).toBeVisible()\n  await expect(page.getByText('post.comments.allowed: false')).toBeVisible()\n  await expect(page.getByText('post.comments.data: A, B, C, D, E, F')).toBeVisible()\n})\n"
  },
  {
    "path": "tests/network-error.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\n\ntest.describe('network error', () => {\n  test('it cleans up request stream after network failure', async ({ page }) => {\n    await page.goto('/network-error')\n\n    await page.route('**/network-error', async (route) => {\n      if (route.request().headers()['x-inertia']) {\n        await route.abort('failed')\n      } else {\n        await route.continue()\n      }\n    })\n\n    await page.locator('#make-request').click()\n    await expect(page.locator('#network-error')).toBeVisible()\n\n    await page.waitForFunction(() => (window.testing.Inertia as any).syncRequestStream.requests.length === 0)\n  })\n})\n"
  },
  {
    "path": "tests/once-props.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport { clickAndWaitForResponse, gotoPageAndWaitForContent } from './support'\n\ntest.beforeEach(async ({ page }) => {\n  await page.goto('/once-props/page-a')\n})\n\ntest('loads the prop on initial page load and then preserves it after navigation', async ({ page }) => {\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n  await expect(page.getByText('Bar: bar-a')).toBeVisible()\n\n  await page.getByRole('link', { name: 'Go to Page B' }).click()\n\n  await expect(page).toHaveURL('/once-props/page-b')\n  await expect(page.getByText('Bar: bar-b')).toBeVisible()\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n\n  await page.reload()\n\n  await expect(page).toHaveURL('/once-props/page-b')\n  await expect(page.getByText('Foo: foo-b')).toBeVisible()\n  await expect(page.getByText('Bar: bar-b')).toBeVisible()\n})\n\ntest('navigating back and forward preserves the prop', async ({ page }) => {\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n  await expect(page.getByText('Bar: bar-a')).toBeVisible()\n\n  await page.getByRole('link', { name: 'Go to Page B' }).click()\n\n  await expect(page).toHaveURL('/once-props/page-b')\n  await expect(page.getByText('Bar: bar-b')).toBeVisible()\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n\n  await page.goBack()\n\n  await expect(page).toHaveURL('/once-props/page-a')\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n  await expect(page.getByText('Bar: bar-a')).toBeVisible()\n\n  await page.goForward()\n\n  await expect(page).toHaveURL('/once-props/page-b')\n  await expect(page.getByText('Bar: bar-b')).toBeVisible()\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n})\n\ntest('partial reload preserves the prop', async ({ page }) => {\n  const fooText = await page.locator('#foo').innerText()\n\n  await page.getByRole('button', { name: 'Reload (only foo)' }).click()\n  await expect(page.getByText(fooText)).not.toBeVisible()\n\n  const newFooText = await page.locator('#foo').innerText()\n\n  expect(newFooText.startsWith('Foo: foo-a')).toBe(true)\n  expect(newFooText).not.toBe(fooText)\n\n  await page.getByRole('link', { name: 'Go to Page B' }).click()\n\n  await expect(page).toHaveURL('/once-props/page-b')\n  await expect(page.getByText(newFooText)).toBeVisible()\n})\n\ntest('partial reload of one once prop preserves all once props on navigation', async ({ page }) => {\n  await page.goto('/once-props/partial-reload/a')\n\n  const fooText = await page.locator('#foo').innerText()\n  const barText = await page.locator('#bar').innerText()\n\n  expect(fooText.startsWith('Foo: foo-a')).toBe(true)\n  expect(barText.startsWith('Bar: bar-a')).toBe(true)\n\n  await page.getByRole('button', { name: 'Reload (only foo)' }).click()\n  await expect(page.getByText(fooText)).not.toBeVisible()\n\n  const newFooText = await page.locator('#foo').innerText()\n  expect(newFooText.startsWith('Foo: foo-a')).toBe(true)\n  expect(newFooText).not.toBe(fooText)\n\n  await expect(page.getByText(barText)).toBeVisible()\n\n  await page.getByRole('link', { name: 'Go to Partial Reload B' }).click()\n  await expect(page).toHaveURL('/once-props/partial-reload/b')\n  await expect(page.getByText(newFooText)).toBeVisible()\n  await expect(page.getByText(barText)).toBeVisible()\n})\n\ntest('navigating through an intermediary page without the once prop', async ({ page }) => {\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n  await expect(page.getByText('Bar: bar-a')).toBeVisible()\n\n  await page.getByRole('link', { name: 'Go to Page C' }).click()\n\n  await expect(page).toHaveURL('/once-props/page-c')\n\n  await page.getByRole('link', { name: 'Go to Page B' }).click()\n\n  await expect(page).toHaveURL('/once-props/page-b')\n  await expect(page.getByText('Bar: bar-b')).toBeVisible()\n  await expect(page.getByText('Foo: foo-b')).toBeVisible()\n})\n\ntest('deferred once prop is loaded via defer and then remembered on navigation', async ({ page }) => {\n  await gotoPageAndWaitForContent(page, '/once-props/deferred/a')\n\n  await expect(page.getByText('Loading foo...')).toBeVisible()\n  await expect(page.getByText('Bar: bar-a')).toBeVisible()\n\n  await page.waitForResponse(\n    (response) =>\n      response.url().includes('/once-props/deferred/a') &&\n      response.request().headers()['x-inertia-partial-data'] === 'foo',\n  )\n\n  await expect(page.getByText('Loading foo...')).not.toBeVisible()\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n\n  const fooText = await page.locator('#foo').innerText()\n\n  await clickAndWaitForResponse(page, 'Go to Deferred Page B', '/once-props/deferred/b')\n\n  await expect(page).toHaveURL('/once-props/deferred/b')\n  await expect(page.getByText('Bar: bar-b')).toBeVisible()\n  await expect(page.getByText('Loading foo...')).not.toBeVisible()\n  await expect(page.getByText(fooText)).toBeVisible()\n})\n\ntest('navigating before deferred+once prop loads preserves other once props and loads deferred+once prop on new page', async ({\n  page,\n}) => {\n  await gotoPageAndWaitForContent(page, '/once-props/slow-deferred/a')\n\n  await expect(page.locator('#bar')).toContainText('Bar: bar-a')\n  await expect(page.locator('#foo-loading')).toBeVisible()\n\n  const barText = await page.locator('#bar').innerText()\n\n  await page.getByRole('link', { name: 'Go to Page B' }).click()\n  await expect(page).toHaveURL('/once-props/slow-deferred/b')\n\n  // bar should be preserved from page A (it was a once prop that was already loaded)\n  await expect(page.locator('#bar')).toContainText(barText)\n\n  // foo should be loaded via defer on page B since we didn't have it on page A\n  await expect(page.locator('#foo-loading')).toBeVisible()\n  await expect(page.locator('#foo')).toContainText('Foo: foo-b')\n\n  const fooText = await page.locator('#foo').innerText()\n\n  // Navigate back to page A\n  await page.getByRole('link', { name: 'Go to Page A' }).click()\n  await expect(page).toHaveURL('/once-props/slow-deferred/a')\n\n  // bar should still be preserved, as well as foo now since it was loaded on page B\n  await expect(page.locator('#foo')).toContainText(fooText)\n  await expect(page.locator('#bar')).toContainText(barText)\n})\n\ntest('once prop with TTL is remembered within TTL window and reloaded after expiry', async ({ page }) => {\n  await page.goto('/once-props/ttl/a')\n\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n  await expect(page.getByText('Bar: bar-a')).toBeVisible()\n\n  const initialFooText = await page.locator('#foo').innerText()\n\n  await page.getByRole('link', { name: 'Go to TTL Page B' }).click()\n\n  await expect(page).toHaveURL('/once-props/ttl/b')\n  await expect(page.getByText('Bar: bar-b')).toBeVisible()\n  await expect(page.getByText(initialFooText)).toBeVisible()\n\n  await page.getByRole('link', { name: 'Go to TTL Page A' }).click()\n\n  await expect(page).toHaveURL('/once-props/ttl/a')\n  await expect(page.getByText(initialFooText)).toBeVisible()\n\n  await page.waitForTimeout(2500)\n\n  await page.getByRole('link', { name: 'Go to TTL Page B' }).click()\n\n  await expect(page).toHaveURL('/once-props/ttl/b')\n  await expect(page.getByText('Bar: bar-b')).toBeVisible()\n\n  const newFooText = await page.locator('#foo').innerText()\n  expect(newFooText).not.toBe(initialFooText)\n  expect(newFooText.startsWith('Foo: foo-b')).toBe(true)\n})\n\ntest('once prop with TTL has its expiry reset after reload', async ({ page }) => {\n  await page.goto('/once-props/ttl/a')\n\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n  const initialFooText = await page.locator('#foo').innerText()\n\n  await page.waitForTimeout(2500)\n\n  await page.getByRole('button', { name: 'Reload foo' }).click()\n  await expect(page.getByText(initialFooText)).not.toBeVisible()\n\n  const reloadedFooText = await page.locator('#foo').innerText()\n  expect(reloadedFooText).not.toBe(initialFooText)\n  expect(reloadedFooText.startsWith('Foo: foo-a')).toBe(true)\n\n  await page.getByRole('link', { name: 'Go to TTL Page B' }).click()\n\n  await expect(page).toHaveURL('/once-props/ttl/b')\n  await expect(page.getByText('Bar: bar-b')).toBeVisible()\n  await expect(page.getByText(reloadedFooText)).toBeVisible()\n})\n\ntest('once prop TTL is preserved across navigation and expires correctly', async ({ page }) => {\n  await page.goto('/once-props/ttl/a')\n\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n  const initialFooText = await page.locator('#foo').innerText()\n\n  await page.waitForTimeout(1000)\n\n  await page.getByRole('link', { name: 'Go to TTL Page B' }).click()\n  await expect(page).toHaveURL('/once-props/ttl/b')\n  await expect(page.getByText(initialFooText)).toBeVisible()\n\n  await page.waitForTimeout(1500)\n\n  await page.getByRole('link', { name: 'Go to TTL Page A' }).click()\n  await expect(page).toHaveURL('/once-props/ttl/a')\n\n  const newFooText = await page.locator('#foo').innerText()\n  expect(newFooText).not.toBe(initialFooText)\n  expect(newFooText.startsWith('Foo: foo-a')).toBe(true)\n})\n\ntest('optional once prop is not loaded initially, fetched via reload, then cached on navigation', async ({ page }) => {\n  await page.goto('/once-props/optional/a')\n\n  await expect(page.getByText('Foo: not loaded')).toBeVisible()\n  await expect(page.getByText('Bar: bar-a')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Load foo', '/once-props/optional/a', 'button')\n\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n\n  const fooText = await page.locator('#foo').innerText()\n  expect(fooText.startsWith('Foo: foo-a')).toBe(true)\n\n  await clickAndWaitForResponse(page, 'Go to Optional Page B', '/once-props/optional/b')\n\n  await expect(page).toHaveURL('/once-props/optional/b')\n  await expect(page.getByText('Bar: bar-b')).toBeVisible()\n  await expect(page.getByText(fooText)).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Go to Optional Page A', '/once-props/optional/a')\n\n  await expect(page).toHaveURL('/once-props/optional/a')\n  await expect(page.getByText(fooText)).toBeVisible()\n})\n\ntest('merge once prop merges on reload and preserves merged data on navigation', async ({ page }) => {\n  await page.goto('/once-props/merge/a')\n\n  await expect(page.getByText('Items count: 3')).toBeVisible()\n  await expect(page.getByText('Bar: bar-a')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Load more items', '/once-props/merge/a', 'button')\n\n  await expect(page.getByText('Items count: 6')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Go to Merge Page B', '/once-props/merge/b')\n\n  await expect(page).toHaveURL('/once-props/merge/b')\n  await expect(page.getByText('Bar: bar-b')).toBeVisible()\n  await expect(page.getByText('Items count: 6')).toBeVisible()\n\n  await clickAndWaitForResponse(page, 'Go to Merge Page A', '/once-props/merge/a')\n\n  await expect(page).toHaveURL('/once-props/merge/a')\n  await expect(page.getByText('Items count: 6')).toBeVisible()\n})\n\ntest('once prop with custom key shares data across pages with different prop names', async ({ page }) => {\n  await page.goto('/once-props/custom-key/a')\n\n  await expect(page.getByText('Permissions: perms-a')).toBeVisible()\n  await expect(page.getByText('Bar: bar-a')).toBeVisible()\n\n  const permissionsText = await page.locator('#permissions').innerText()\n\n  await page.getByRole('link', { name: 'Go to Custom Key Page B' }).click()\n\n  await expect(page).toHaveURL('/once-props/custom-key/b')\n  await expect(page.getByText('Bar: bar-b')).toBeVisible()\n  await expect(page.getByText(permissionsText)).toBeVisible()\n\n  await page.getByRole('link', { name: 'Go to Custom Key Page A' }).click()\n\n  await expect(page).toHaveURL('/once-props/custom-key/a')\n  await expect(page.getByText(permissionsText)).toBeVisible()\n})\n\ntest('prefetched once prop is preserved after navigating through intermediary page', async ({ page }) => {\n  const prefetchPromise = page.waitForResponse((response) => response.url().includes('/once-props/page-d'))\n\n  await page.goto('/once-props/page-a')\n\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n  await expect(page.getByText('Bar: bar-a')).toBeVisible()\n\n  const fooText = await page.locator('#foo').innerText()\n\n  await prefetchPromise\n\n  await page.getByRole('link', { name: 'Go to Page C' }).click()\n  await expect(page).toHaveURL('/once-props/page-c')\n\n  await page.getByRole('link', { name: 'Go to Page D' }).click()\n  await expect(page).toHaveURL('/once-props/page-d')\n\n  await expect(page.getByText(fooText)).toBeVisible()\n})\n\ntest('prefetched once prop is updated when re-prefetched before use', async ({ page }) => {\n  const prefetchPromise = page.waitForResponse((response) => response.url().includes('/once-props/page-d'))\n\n  await page.goto('/once-props/page-a')\n\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n  await expect(page.getByText('Bar: bar-a')).toBeVisible()\n\n  const fooText = await page.locator('#foo').innerText()\n\n  await prefetchPromise\n\n  await page.getByRole('button', { name: 'Reload (only foo)' }).click()\n  await expect(page.getByText(fooText)).not.toBeVisible()\n\n  const newFooText = await page.locator('#foo').innerText()\n\n  expect(newFooText.startsWith('Foo: foo-a')).toBe(true)\n  expect(newFooText).not.toBe(fooText)\n\n  await page.getByRole('link', { name: 'Go to Page D' }).click()\n  await expect(page).toHaveURL('/once-props/page-d')\n\n  await expect(page.getByText(newFooText)).toBeVisible()\n})\n\ntest('prefetch cache TTL is extended when once prop is reloaded before expiry', async ({ page }) => {\n  const prefetchPromise = page.waitForResponse((response) => response.url().includes('/once-props/ttl/c'))\n\n  await page.goto('/once-props/ttl/a')\n\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n  const initialFooText = await page.locator('#foo').innerText()\n\n  await prefetchPromise\n\n  await page.getByRole('button', { name: 'Reload foo' }).click()\n  await expect(page.getByText(initialFooText)).not.toBeVisible()\n\n  const reloadedFooText = await page.locator('#foo').innerText()\n\n  await page.waitForTimeout(1500)\n\n  let requestMade = false\n  page.on('request', (request) => {\n    if (request.url().includes('/once-props/ttl/c')) {\n      requestMade = true\n    }\n  })\n\n  await page.getByRole('link', { name: 'Go to TTL Page C' }).click()\n  await expect(page).toHaveURL('/once-props/ttl/c')\n\n  expect(requestMade).toBe(false)\n  await expect(page.getByText(reloadedFooText)).toBeVisible()\n})\n\ntest('prefetch cache is invalidated when extended TTL expires', async ({ page }) => {\n  test.setTimeout(10000)\n  const prefetchPromise = page.waitForResponse((response) => response.url().includes('/once-props/ttl/c'))\n\n  await page.goto('/once-props/ttl/a')\n\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n  const initialFooText = await page.locator('#foo').innerText()\n\n  await prefetchPromise\n\n  await page.getByRole('button', { name: 'Reload foo' }).click()\n  await expect(page.getByText(initialFooText)).not.toBeVisible()\n\n  const reloadedFooText = await page.locator('#foo').innerText()\n\n  await page.waitForTimeout(2500)\n\n  await page.getByRole('link', { name: 'Go to TTL Page C' }).click()\n  await expect(page).toHaveURL('/once-props/ttl/c')\n\n  const newFooText = await page.locator('#foo').innerText()\n  expect(newFooText).not.toBe(reloadedFooText)\n  expect(newFooText.startsWith('Foo: foo-c')).toBe(true)\n})\n\ntest('prefetched once prop with TTL is refreshed after expiry', async ({ page }) => {\n  const prefetchPromise = page.waitForResponse((response) => response.url().includes('/once-props/ttl/c'))\n\n  await page.goto('/once-props/ttl/a')\n\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n  const initialFooText = await page.locator('#foo').innerText()\n\n  await prefetchPromise\n  await page.waitForTimeout(2500)\n\n  await page.getByRole('link', { name: 'Go to TTL Page C' }).click()\n  await expect(page).toHaveURL('/once-props/ttl/c')\n\n  const newFooText = await page.locator('#foo').innerText()\n  expect(newFooText).not.toBe(initialFooText)\n  expect(newFooText.startsWith('Foo: foo-c')).toBe(true)\n})\n\ntest('prefetch cache is updated when deferred once prop finishes loading', async ({ page }) => {\n  const prefetchPromise = page.waitForResponse(\n    (response) =>\n      response.url().includes('/once-props/deferred/c') && !response.request().headers()['x-inertia-partial-data'],\n  )\n\n  await gotoPageAndWaitForContent(page, '/once-props/deferred/a')\n\n  await expect(page.getByText('Loading foo...')).toBeVisible()\n\n  await prefetchPromise\n\n  await page.waitForResponse(\n    (response) =>\n      response.url().includes('/once-props/deferred/a') &&\n      response.request().headers()['x-inertia-partial-data'] === 'foo',\n  )\n\n  await expect(page.getByText('Loading foo...')).not.toBeVisible()\n  const fooText = await page.locator('#foo').innerText()\n  expect(fooText.startsWith('Foo: foo-a')).toBe(true)\n\n  await page.getByRole('link', { name: 'Go to Deferred Page C' }).click()\n  await expect(page).toHaveURL('/once-props/deferred/c')\n\n  await expect(page.getByText(fooText)).toBeVisible()\n})\n\ntest('prefetch cache is updated when replaceProp is called', async ({ page }) => {\n  const prefetchPromise = page.waitForResponse((response) => response.url().includes('/once-props/page-d'))\n\n  await page.goto('/once-props/page-a')\n\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n\n  await prefetchPromise\n\n  await page.getByRole('button', { name: 'Replace foo' }).click()\n\n  await expect(page.getByText('Foo: replaced-foo')).toBeVisible()\n\n  await page.getByRole('link', { name: 'Go to Page D' }).click()\n  await expect(page).toHaveURL('/once-props/page-d')\n\n  await expect(page.getByText('Foo: replaced-foo')).toBeVisible()\n})\n\ntest('prefetch cache expires based on cacheFor even when once prop has no TTL', async ({ page }) => {\n  const prefetchPromise = page.waitForResponse((response) => response.url().includes('/once-props/page-e'))\n\n  await page.goto('/once-props/page-a')\n\n  await expect(page.getByText('Foo: foo-a')).toBeVisible()\n  const fooText = await page.locator('#foo').innerText()\n\n  await prefetchPromise\n\n  await page.waitForTimeout(1500)\n\n  let requestMade = false\n  page.on('request', (request) => {\n    if (request.url().includes('/once-props/page-e')) {\n      requestMade = true\n    }\n  })\n\n  await page.getByRole('link', { name: 'Go to Page E (short cache)' }).click()\n  await expect(page).toHaveURL('/once-props/page-e')\n\n  expect(requestMade).toBe(true)\n  await expect(page.getByText('Bar: bar-e')).toBeVisible()\n  await expect(page.getByText(fooText)).toBeVisible()\n})\n\ntest('it provides once props as second argument in client-side visit props callback', async ({ page }) => {\n  await page.goto('/once-props/client-side-visit')\n\n  await expect(page.getByText('Foo: foo-initial')).toBeVisible()\n  await expect(page.getByText('Bar: bar-initial')).toBeVisible()\n\n  // Without spreading onceProps, once prop becomes undefined\n  await page.getByRole('button', { name: 'Push without preserving' }).click()\n  await expect(page.locator('#foo')).toContainText('Foo:')\n  await expect(page.locator('#foo')).not.toContainText('foo-initial')\n  await expect(page.getByText('Bar: bar-updated')).toBeVisible()\n\n  await page.goto('/once-props/client-side-visit')\n\n  // Spreading onceProps preserves once props\n  await page.getByRole('button', { name: 'Push with once props' }).click()\n  await expect(page.getByText('Foo: foo-initial')).toBeVisible()\n  await expect(page.getByText('Bar: bar-updated')).toBeVisible()\n})\n"
  },
  {
    "path": "tests/pages.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\n\ntest('receives data from the controllers as props', async ({ page }) => {\n  await page.goto('/')\n  const inertiaProps = await page.evaluate(() => (window as any)._inertia_props)\n\n  await expect(inertiaProps.example).toEqual('FooBar')\n})\n\ntest('it can opt-in to preserve equal props from the previous page', async ({ page }) => {\n  await page.goto('/preserve-equal-props')\n\n  await expect(page.locator('#count-a')).toHaveText('Count A: 1')\n  await expect(page.locator('#effect-a')).toHaveText('Effect A Count: 1')\n  await expect(page.locator('#effect-b')).toHaveText('Effect B Count: 1')\n\n  await page.getByRole('button', { name: 'Submit and redirect back' }).click()\n\n  await expect(page.locator('#effect-b')).toHaveText('Effect B Count: 2')\n  await expect(page.locator('#effect-a')).toHaveText('Effect A Count: 2')\n\n  await page.getByRole('button', { name: 'Enable' }).click()\n  await page.getByRole('button', { name: 'Submit and redirect back' }).click()\n\n  await expect(page.locator('#effect-b')).toHaveText('Effect B Count: 3') // updated\n  await expect(page.locator('#effect-a')).toHaveText('Effect A Count: 2') // preserved\n})\n\ntest.describe('persistent layouts', () => {\n  const layoutData = [{ method: 'render-function' }, { method: 'shorthand' }] as const\n\n  layoutData.forEach(({ method }) => {\n    test(`can have a persistent layout (${method})`, async ({ page }) => {\n      await page.goto(`/persistent-layouts/${method}/simple/page-a`)\n\n      const layoutAId = await page.evaluate(() => (window as any)._inertia_layout_id)\n      await expect(layoutAId).not.toBeNull()\n\n      await expect(page.getByText('Simple Persistent Layout - Page A')).toBeVisible()\n      await page.getByRole('link', { name: 'Page B' }).click()\n\n      await expect(page).toHaveURL(`/persistent-layouts/${method}/simple/page-b`)\n      await expect(page.getByText('Simple Persistent Layout - Page B')).toBeVisible()\n\n      const layoutBId = await page.evaluate(() => (window as any)._inertia_layout_id)\n      await expect(layoutBId).toEqual(layoutAId)\n    })\n  })\n\n  layoutData.forEach(({ method }) => {\n    test(`can create more complex layout arrangements using nested layouts (${method})`, async ({ page }) => {\n      await page.goto(`/persistent-layouts/${method}/nested/page-a`)\n\n      const layoutAId = await page.evaluate(() => (window as any)._inertia_layout_id)\n      const nestedLayoutAId = await page.evaluate(() => (window as any)._inertia_nested_layout_id)\n      await expect(layoutAId).not.toBeNull()\n      await expect(nestedLayoutAId).not.toBeNull()\n\n      await expect(page.getByText('Nested Persistent Layout - Page A')).toBeVisible()\n      await page.getByRole('link', { name: 'Page B' }).click()\n\n      await expect(page).toHaveURL(`/persistent-layouts/${method}/nested/page-b`)\n      await expect(page.getByText('Nested Persistent Layout - Page B')).toBeVisible()\n\n      const layoutBId = await page.evaluate(() => (window as any)._inertia_layout_id)\n      const nestedLayoutBId = await page.evaluate(() => (window as any)._inertia_nested_layout_id)\n      await expect(layoutBId).toEqual(layoutAId)\n      await expect(nestedLayoutBId).toEqual(nestedLayoutAId)\n    })\n  })\n\n  test('has the page props available within the persistent layout', async ({ page }) => {\n    await page.goto('/persistent-layouts/shorthand/simple/page-a')\n\n    const pageProps = await page.evaluate(() => (window as any)._inertia_page_props)\n    const layoutProps = await page.evaluate(() => (window as any)._inertia_site_layout_props)\n\n    await expect(pageProps.foo).toBeDefined()\n    await expect(pageProps.baz).toBeDefined()\n    await expect(layoutProps.foo).toBeDefined()\n    await expect(layoutProps.baz).toBeDefined()\n  })\n\n  test('has the page props available within all nested persistent layouts', async ({ page }) => {\n    await page.goto('/persistent-layouts/shorthand/nested/page-a')\n\n    const pageProps = await page.evaluate(() => (window as any)._inertia_page_props)\n    const layoutProps = await page.evaluate(() => (window as any)._inertia_site_layout_props)\n    const nestedLayoutProps = await page.evaluate(() => (window as any)._inertia_nested_layout_props)\n\n    await expect(pageProps.foo).toBeDefined()\n    await expect(pageProps.baz).toBeDefined()\n    await expect(layoutProps.foo).toBeDefined()\n    await expect(layoutProps.baz).toBeDefined()\n    await expect(nestedLayoutProps.foo).toBeDefined()\n    await expect(nestedLayoutProps.baz).toBeDefined()\n  })\n})\n"
  },
  {
    "path": "tests/plugin.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\n\ntest.describe('plugin', () => {\n  test.skip(process.env.PACKAGE !== 'vue3')\n\n  test.describe('$page helper', () => {\n    test('has the helper injected into the Vue component', async ({ page }) => {\n      await page.goto('/')\n\n      const initialPage = await page.evaluate(() => (window as any).initialPage)\n      const $page = await page.evaluate(() => (window as any)._plugin_global_props.$page)\n      await expect(initialPage).not.toBeNull()\n      await expect($page).toMatchObject(initialPage)\n    })\n\n    test('misses the helper when not registered', async ({ page }) => {\n      await page.goto('/plugin/without')\n\n      const $page = await page.evaluate(() => (window as any)._plugin_global_props.$page)\n      await expect($page).toBeUndefined()\n    })\n  })\n\n  test.describe('$inertia helper', () => {\n    test('has the helper injected into the Vue component', async ({ page }) => {\n      await page.goto('/')\n\n      const $inertia = await page.evaluate(() => (window as any)._plugin_global_props.$inertia)\n      const Inertia = await page.evaluate(() => (window as any).testing.Inertia)\n      await expect($inertia).not.toBeNull()\n      await expect($inertia).toEqual(Inertia)\n    })\n\n    test('misses the helper when not registered', async ({ page }) => {\n      await page.goto('/plugin/without')\n\n      const $inertia = await page.evaluate(() => (window as any)._plugin_global_props.$inertia)\n      await expect($inertia).toBeUndefined()\n    })\n  })\n})\n"
  },
  {
    "path": "tests/poll.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport { consoleMessages, requests } from './support'\n\ntest('will start polling when the component mounts with usePoll', async ({ page }) => {\n  await page.goto('/poll/hook')\n\n  consoleMessages.listen(page)\n\n  const start = Date.now()\n\n  const response = await page.waitForResponse(page.url())\n  const firstRequestTime = Date.now() - start\n  await expect(firstRequestTime).toBeGreaterThanOrEqual(400)\n  await expect(firstRequestTime).toBeLessThanOrEqual(700)\n\n  const response2 = await page.waitForResponse(page.url())\n  const secondRequestTime = Date.now() - start - firstRequestTime\n  await expect(secondRequestTime).toBeGreaterThanOrEqual(400)\n  await expect(secondRequestTime).toBeLessThanOrEqual(700)\n\n  const only = await response.request().headerValue('X-Inertia-Partial-Data')\n  await expect(only).toBe('custom_prop')\n\n  const only2 = await response2.request().headerValue('X-Inertia-Partial-Data')\n  await expect(only2).toBe('custom_prop')\n\n  // Wait for console messages to be captured (may be delayed in Firefox)\n  await expect.poll(() => consoleMessages.messages.length, { timeout: 2000 }).toBeGreaterThanOrEqual(2)\n  await expect(consoleMessages.messages[0]).toContain('hook poll finished')\n  await expect(consoleMessages.messages[1]).toContain('hook poll finished')\n\n  await page.getByRole('link', { name: 'Home' }).click()\n  await page.waitForURL('/')\n\n  requests.listen(page)\n\n  await page.waitForTimeout(700)\n\n  await expect(requests.requests).toHaveLength(0)\n})\n\nconst manualData = [\n  { method: 'hook', url: '/poll/hook/manual' },\n  { method: 'router.poll', url: '/poll/router/manual' },\n]\n\nmanualData.forEach(({ method, url }) => {\n  test(`you can manually start and stop (${method})`, async ({ page }) => {\n    consoleMessages.listen(page)\n\n    await page.goto(url)\n\n    requests.listen(page)\n    await page.waitForTimeout(700)\n    await expect(requests.requests).toHaveLength(0)\n\n    await page.getByRole('button', { name: 'Start' }).click()\n\n    const start = Date.now()\n\n    const response = await page.waitForResponse(page.url())\n    const firstRequestTime = Date.now() - start\n    await expect(firstRequestTime).toBeGreaterThanOrEqual(400)\n    await expect(firstRequestTime).toBeLessThanOrEqual(700)\n\n    const response2 = await page.waitForResponse(page.url())\n    const secondRequestTime = Date.now() - start - firstRequestTime\n    await expect(secondRequestTime).toBeGreaterThanOrEqual(400)\n    await expect(secondRequestTime).toBeLessThanOrEqual(700)\n\n    await page.getByRole('button', { name: 'Stop' }).click()\n\n    const only = await response.request().headerValue('X-Inertia-Partial-Data')\n    await expect(only).toBe('custom_prop')\n\n    const only2 = await response2.request().headerValue('X-Inertia-Partial-Data')\n    await expect(only2).toBe('custom_prop')\n\n    await expect(consoleMessages.messages[0]).toContain('hook poll finished')\n    await expect(consoleMessages.messages[1]).toContain('hook poll finished')\n\n    requests.listen(page)\n\n    await page.waitForTimeout(700)\n    await expect(requests.requests).toHaveLength(0)\n  })\n})\n\ntest.skip('it will throttle polling when in the background', async ({ page }) => {})\ntest.skip('it is able to keep alive when in the background', async ({ page }) => {})\n\nObject.entries({\n  unencrypted: '/poll/unchanged-data',\n  encrypted: '/poll/unchanged-data/encrypted',\n}).forEach(([scenario, url]) => {\n  test(`it skips replaceState when polling returns unchanged data (${scenario})`, async ({ page }) => {\n    await page.goto(url)\n\n    await page.waitForResponse(page.url())\n    await page.waitForResponse(page.url())\n\n    const pollsFinished = Number(await page.locator('.pollsFinished').textContent())\n    await expect(pollsFinished).toBeGreaterThanOrEqual(2)\n\n    // Only 1 replaceState from initial page load, none from polling\n    await expect(page.locator('.replaceStateCalls')).toHaveText('1')\n  })\n})\n"
  },
  {
    "path": "tests/precognition.spec.ts",
    "content": "import test, { expect } from '@playwright/test'\nimport { requests, shouldBeDumpPage } from './support'\n\nconst integrations = ['form-component', 'form-helper']\n\nintegrations.forEach((integration) => {\n  test.describe('Precognition', () => {\n    test.beforeEach(async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/default')\n    })\n\n    const prefix = integration === 'form-helper' ? 'Form Helper - ' : 'Form Component - '\n\n    test(prefix + 'does not validate when field is untouched', async ({ page }) => {\n      await page.locator('input[name=\"name\"]').focus()\n      await page.waitForTimeout(100)\n      await page.locator('input[name=\"name\"]').blur()\n\n      for (let i = 0; i < 5; i++) {\n        await expect(page.getByText('Validating...')).not.toBeVisible()\n        await page.waitForTimeout(50)\n      }\n\n      await expect(page.getByText('The name field is required.')).not.toBeVisible()\n    })\n\n    test(prefix + 'shows validation error when field is invalid', async ({ page }) => {\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n    })\n\n    test(prefix + 'clears validation error when field becomes valid', async ({ page }) => {\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n\n      await page.fill('input[name=\"name\"]', 'John Doe')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('The name must be at least 3 characters.')).not.toBeVisible()\n    })\n\n    test(prefix + 'validates only the specified field', async ({ page }) => {\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n      await expect(page.getByText('The email field is required.')).not.toBeVisible()\n    })\n\n    test(prefix + 'validates multiple fields independently', async ({ page }) => {\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n      await expect(page.getByText('The email must be a valid email address.')).not.toBeVisible()\n\n      await page.fill('input[name=\"email\"]', 'x')\n      await page.locator('input[name=\"email\"]').blur()\n\n      await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n      await expect(page.getByText('The email must be a valid email address.')).toBeVisible()\n    })\n\n    test(prefix + 'does not clear unrelated field errors', async ({ page }) => {\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n\n      await page.fill('input[name=\"email\"]', 'x')\n      await page.locator('input[name=\"email\"]').blur()\n\n      await expect(page.getByText('The email must be a valid email address.')).toBeVisible()\n\n      await page.fill('input[name=\"email\"]', 'test@example.com')\n      await page.locator('input[name=\"email\"]').blur()\n\n      await expect(page.getByText('The email must be a valid email address.')).not.toBeVisible()\n      await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n    })\n\n    test(prefix + 'field is valid when validated and no errors exist', async ({ page }) => {\n      await expect(page.getByText('Name is valid!')).not.toBeVisible()\n\n      await page.fill('input[name=\"name\"]', 'John Doe')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('Name is valid!')).toBeVisible()\n    })\n\n    test(prefix + 'field is not valid before validation', async ({ page }) => {\n      await expect(page.getByText('Name is valid!')).not.toBeVisible()\n\n      await page.fill('input[name=\"name\"]', 'John Doe')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('Name is valid!')).toBeVisible()\n      await expect(page.getByText('The name must be at least 3 characters.')).not.toBeVisible()\n    })\n\n    test(prefix + 'field is not valid after failed validation', async ({ page }) => {\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n      await expect(page.getByText('Name is valid!')).not.toBeVisible()\n    })\n\n    test(prefix + 'valid field persists after successful validation', async ({ page }) => {\n      await page.fill('input[name=\"name\"]', 'John Doe')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('Name is valid!')).toBeVisible()\n\n      await page.fill('input[name=\"name\"]', 'Jane Doe')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('Name is valid!')).toBeVisible()\n    })\n\n    test(prefix + 'valid field becomes invalid when field is revalidated with errors', async ({ page }) => {\n      await page.fill('input[name=\"name\"]', 'John Doe')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('Name is valid!')).toBeVisible()\n\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n      await expect(page.getByText('Name is valid!')).not.toBeVisible()\n    })\n\n    test(prefix + 'maps the full array errors to the first one by default', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/without-all-errors')\n\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      // Should show only the first error from the array, not the second\n      await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n      await expect(page.getByText('The name contains invalid characters.')).not.toBeVisible()\n    })\n\n    test(prefix + 'shows all errors using array errors', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/with-all-errors')\n\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      // Should show all errors from the array\n      await expect(page.locator('#name-error-0')).toHaveText('The name must be at least 3 characters.')\n      await expect(page.locator('#name-error-1')).toHaveText('The name contains invalid characters.')\n    })\n\n    test(prefix + 'shows all errors using global config', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/with-all-errors-config')\n\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      // Should show all errors from the array\n      await expect(page.locator('#name-error-0')).toHaveText('The name must be at least 3 characters.')\n      await expect(page.locator('#name-error-1')).toHaveText('The name contains invalid characters.')\n    })\n\n    test(prefix + 'validates all touched fields when calling validate() without arguments', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/methods')\n\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await page.fill('input[name=\"email\"]', 'x')\n      await page.locator('input[name=\"email\"]').blur()\n\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n      await expect(page.getByText('The name must be at least 3 characters.')).not.toBeVisible()\n      await expect(page.getByText('The email must be a valid email address.')).not.toBeVisible()\n\n      await page.getByRole('button', { name: 'Validate All Touched' }).click()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n      await expect(page.getByText('The email must be a valid email address.')).toBeVisible()\n    })\n\n    test(prefix + 'reset all fields clears all touched fields', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/methods')\n\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await page.fill('input[name=\"email\"]', 'x')\n      await page.locator('input[name=\"email\"]').blur()\n\n      await page.getByRole('button', { name: 'Reset All' }).click()\n\n      await expect(page.locator('input[name=\"name\"]')).toHaveValue('')\n      await expect(page.locator('input[name=\"email\"]')).toHaveValue('')\n\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await page.getByRole('button', { name: 'Validate All Touched' }).click()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n      await expect(page.getByText('The email field is required.')).not.toBeVisible()\n    })\n\n    test(prefix + 'reset specific fields removes only those fields from touched', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/methods')\n\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await page.fill('input[name=\"email\"]', 'x')\n      await page.locator('input[name=\"email\"]').blur()\n\n      await expect(page.locator('input[name=\"name\"]')).toHaveValue('ab')\n      await expect(page.locator('input[name=\"email\"]')).toHaveValue('x')\n\n      await page.getByRole('button', { name: 'Reset Name', exact: true }).click()\n\n      await expect(page.locator('input[name=\"name\"]')).toHaveValue('')\n      await expect(page.locator('input[name=\"email\"]')).toHaveValue('x')\n\n      await page.fill('input[name=\"email\"]', 'y')\n\n      await page.getByRole('button', { name: 'Validate All Touched' }).click()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('The name field is required.')).not.toBeVisible()\n      await expect(page.getByText('The email must be a valid email address.')).toBeVisible()\n    })\n\n    test(prefix + 'touch with array marks multiple fields as touched', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/methods')\n\n      await page.getByRole('button', { name: 'Touch Name and Email' }).click()\n      await page.getByRole('button', { name: 'Validate All Touched' }).click()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('The name field is required.')).toBeVisible()\n      await expect(page.getByText('The email field is required.')).toBeVisible()\n    })\n\n    test(prefix + 'touch deduplicates fields when called multiple times', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/methods')\n\n      await page.fill('input[name=\"name\"]', 'ab')\n\n      await page.getByRole('button', { name: 'Touch Name Twice' }).click()\n      await page.getByRole('button', { name: 'Validate All Touched' }).click()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n      await expect(page.getByText('The email must be a valid email address.')).not.toBeVisible()\n    })\n\n    test(prefix + 'touched() returns false when no fields are touched', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/methods')\n\n      await expect(page.locator('#any-touched')).toHaveText('Form has no touched fields')\n      await expect(page.locator('#name-touched')).toHaveText('Name is not touched')\n      await expect(page.locator('#email-touched')).toHaveText('Email is not touched')\n    })\n\n    test(prefix + 'touched(field) returns true when specific field is touched', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/methods')\n\n      await page.locator('input[name=\"name\"]').focus()\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.locator('#name-touched')).toHaveText('Name is touched')\n      await expect(page.locator('#email-touched')).toHaveText('Email is not touched')\n      await expect(page.locator('#any-touched')).toHaveText('Form has touched fields')\n    })\n\n    test(prefix + 'touched() returns true when any field is touched', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/methods')\n\n      await page.locator('input[name=\"email\"]').focus()\n      await page.locator('input[name=\"email\"]').blur()\n\n      await expect(page.locator('#any-touched')).toHaveText('Form has touched fields')\n      await expect(page.locator('#email-touched')).toHaveText('Email is touched')\n      await expect(page.locator('#name-touched')).toHaveText('Name is not touched')\n    })\n\n    test(prefix + 'touched() updates when multiple fields are touched', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/methods')\n\n      await page.locator('input[name=\"name\"]').focus()\n      await page.locator('input[name=\"name\"]').blur()\n      await page.locator('input[name=\"email\"]').focus()\n      await page.locator('input[name=\"email\"]').blur()\n\n      await expect(page.locator('#name-touched')).toHaveText('Name is touched')\n      await expect(page.locator('#email-touched')).toHaveText('Email is touched')\n      await expect(page.locator('#any-touched')).toHaveText('Form has touched fields')\n    })\n\n    test(prefix + 'validating a specific field also validates previously touched inputs', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/methods')\n\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.fill('input[name=\"email\"]', 'x')\n\n      await page.getByRole('button', { name: 'Validate Name', exact: true }).click()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n      await expect(page.getByText('The email must be a valid email address.')).toBeVisible()\n    })\n\n    test(prefix + 'validate with array of fields validates multiple fields', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/methods')\n\n      await page.getByRole('button', { name: 'Validate Name and Email' }).click()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('The name field is required.')).toBeVisible()\n      await expect(page.getByText('The email field is required.')).toBeVisible()\n    })\n\n    test(prefix + 'reset with array removes multiple fields from touched', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/methods')\n\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await page.fill('input[name=\"email\"]', 'x')\n      await page.locator('input[name=\"email\"]').blur()\n\n      await page.getByRole('button', { name: 'Validate All Touched' }).click()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n      await expect(page.getByText('The email must be a valid email address.')).toBeVisible()\n\n      await page.getByRole('button', { name: 'Reset Name and Email' }).click()\n\n      await expect(page.locator('input[name=\"name\"]')).toHaveValue('')\n      await expect(page.locator('input[name=\"email\"]')).toHaveValue('')\n\n      await expect(page.getByText('Name is not touched')).toBeVisible()\n      await expect(page.getByText('Email is not touched')).toBeVisible()\n      await expect(page.getByText('Form has no touched fields')).toBeVisible()\n\n      await page.fill('input[name=\"name\"]', 'abc')\n      await page.fill('input[name=\"email\"]', 'test@example.com')\n\n      await page.getByRole('button', { name: 'Validate All Touched' }).click()\n\n      await page.waitForTimeout(500)\n\n      await expect(page.getByText('The name must be at least 3 characters.')).not.toBeVisible()\n      await expect(page.getByText('The email must be a valid email address.')).not.toBeVisible()\n    })\n\n    test(prefix + 'does not submit files by default', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/files')\n\n      await page.setInputFiles('#avatar', {\n        name: 'avatar.jpg',\n        mimeType: 'image/jpeg',\n        buffer: Buffer.from('fake image data'),\n      })\n\n      await page.getByRole('button', { name: 'Validate Both' }).click()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('The name field is required.')).toBeVisible()\n      await expect(page.getByText('The avatar field is required.')).toBeVisible()\n    })\n\n    test(prefix + 'validates files when validate-files prop is true', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/files')\n      await page.getByRole('button', { name: /Toggle Validate Files/ }).click()\n      await expect(page.getByText('Toggle Validate Files (enabled)')).toBeVisible()\n\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.setInputFiles('#avatar', {\n        name: 'avatar.jpg',\n        mimeType: 'image/jpeg',\n        buffer: Buffer.from('fake image data'),\n      })\n\n      await page.getByRole('button', { name: 'Validate Both' }).click()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n      await expect(page.getByText('The avatar field is required.')).not.toBeVisible()\n    })\n\n    test(prefix + 'transforms data for validation requests', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/transform')\n\n      await page.fill('input[name=\"name\"]', 'a')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n\n      await page.fill('input[name=\"name\"]', 'aa')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('The name must be at least 3 characters.')).not.toBeVisible()\n      await expect(page.getByText('Name is valid!')).toBeVisible()\n    })\n\n    test(prefix + 'validates correctly when transform changes data keys', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/transform-keys')\n\n      // Invalid email triggers validation error\n      await page.fill('#email-input', 'invalid-email')\n      await page.locator('#email-input').blur()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('The email must be a valid email address.')).toBeVisible()\n\n      // Valid email clears the error\n      await page.fill('#email-input', 'valid@email.com')\n      await page.locator('#email-input').blur()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('The email must be a valid email address.')).not.toBeVisible()\n      await expect(page.getByText('Email is valid!')).toBeVisible()\n    })\n\n    test(prefix + 'calls onPrecognitionSuccess and onFinish callbacks when validation succeeds', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/callbacks')\n\n      await page.fill('input[name=\"name\"]', 'John Doe')\n      await page.click('button:has-text(\"Validate\")')\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('onPrecognitionSuccess called!')).toBeVisible()\n      await expect(page.getByText('onValidationError called!')).not.toBeVisible()\n      await expect(page.getByText('onFinish called!')).toBeVisible()\n    })\n\n    test(prefix + 'calls onValidationError and onFinish callbacks when validation fails', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/callbacks')\n\n      await page.fill('input[name=\"name\"]', 'ab')\n      await page.click('button:has-text(\"Validate\")')\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      await expect(page.getByText('onPrecognitionSuccess called!')).not.toBeVisible()\n      await expect(page.getByText('onValidationError called!')).toBeVisible()\n      await expect(page.getByText('onFinish called!')).toBeVisible()\n    })\n\n    test(prefix + 'onBefore can block validation', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/before-validation')\n\n      await page.fill('input[name=\"name\"]', 'block')\n      await page.locator('input[name=\"name\"]').blur()\n\n      for (let i = 0; i < 5; i++) {\n        await expect(page.getByText('Validating...')).not.toBeVisible()\n        await page.waitForTimeout(50)\n      }\n    })\n\n    test(prefix + 'sends custom headers with validation requests', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/headers')\n\n      // Fill in a valid name to trigger validation\n      await page.fill('input[name=\"name\"]', 'John Doe')\n      await page.locator('input[name=\"name\"]').blur()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n\n      // Should show error confirming custom header was received\n      await expect(page.getByText('Custom header received: custom-value')).toBeVisible()\n    })\n\n    test(\n      prefix + 'automatically cancels previous validation when new validation starts',\n      async ({ page, browserName }) => {\n        await page.goto('/' + integration + '/precognition/cancel')\n\n        requests.listenForFailed(page)\n        requests.listenForResponses(page)\n\n        await page.fill('#auto-cancel-name-input', 'ab')\n        await page.locator('#auto-cancel-name-input').blur()\n        await expect(page.getByText('Validating...')).toBeVisible()\n\n        // Immediately change value and trigger new validation - should cancel the first one\n        await page.fill('#auto-cancel-name-input', 'xy')\n        await page.locator('#auto-cancel-name-input').blur()\n        await expect(page.getByText('Validating...')).not.toBeVisible()\n        await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n\n        // One cancelled, one 422 response\n        expect(requests.failed).toHaveLength(1)\n        expect(requests.responses).toHaveLength(1)\n\n        const cancelledRequestError = await requests.failed[0].failure()?.errorText\n        const expectedError =\n          browserName === 'webkit' ? 'cancelled' : browserName === 'firefox' ? 'NS_BINDING_ABORTED' : 'net::ERR_ABORTED'\n        expect(cancelledRequestError).toBe(expectedError)\n      },\n    )\n\n    test(prefix + 'validates dynamic array inputs after first validation', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/dynamic-array-inputs')\n\n      // Add two items\n      await page.click('#add-item')\n      await page.click('#add-item')\n\n      // Validate first item\n      await page.fill('input[name=\"items.0.name\"]', 'ab')\n      await page.locator('input[name=\"items.0.name\"]').blur()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n      await expect(page.locator('#items\\\\.0\\\\.name-error')).toBeVisible()\n\n      // Validate second item - this should also trigger validation\n      await page.fill('input[name=\"items.1.name\"]', 'x')\n      await page.locator('input[name=\"items.1.name\"]').blur()\n\n      await expect(page.getByText('Validating...')).toBeVisible()\n      await expect(page.getByText('Validating...')).not.toBeVisible()\n      await expect(page.locator('#items\\\\.1\\\\.name-error')).toBeVisible()\n    })\n\n    test(prefix + 'clears submission errors on subsequent precognition success', async ({ page }) => {\n      await page.goto('/' + integration + '/precognition/error-sync')\n\n      // Submit with empty fields to trigger validation errors\n      await page.click('#submit-btn')\n      await expect(page.locator('#name-error')).toBeVisible()\n      await expect(page.locator('#email-error')).toBeVisible()\n      await expect(page.locator('#name-error')).toHaveText('The name field is required.')\n      await expect(page.locator('#email-error')).toHaveText('The email field is required.')\n\n      // Fill valid name and trigger precognition validation\n      await page.fill('input[name=\"name\"]', 'John Doe')\n      await page.locator('input[name=\"name\"]').blur()\n      await expect(page.locator('#validating')).toBeVisible()\n      await expect(page.locator('#validating')).not.toBeVisible()\n\n      // Name error should be cleared, email error should remain\n      await expect(page.locator('#name-error')).not.toBeVisible()\n      await expect(page.locator('#email-error')).toBeVisible()\n    })\n  })\n})\n\ntest.describe('Form Helper', () => {\n  Object.entries({\n    default: 'withPrecognition() with strings',\n    dynamic: 'withPrecognition() with callbacks',\n    wayfinder: 'withPrecognition() with Wayfinder',\n    dynamicWayfinder: 'withPrecognition() with a Wayfinder callback',\n    legacy: 'legacy useForm() from Precognition package with strings',\n    legacyDynamic: 'legacy useForm() from Precognition package with callbacks',\n    legacyWayfinder: 'legacy useForm() from Precognition package with Wayfinder',\n    legacyDynamicWayfinder: 'legacy useForm() from Precognition package with a Wayfinder callback',\n  }).forEach(([key, description]) => {\n    test.describe('instantiate using ' + description, () => {\n      test.beforeEach(async ({ page }) => {\n        await page.goto('/form-helper/precognition/instantiate')\n      })\n\n      test('validates form data using the precognition endpoint', async ({ page }) => {\n        await page.selectOption('select', key)\n        await page.getByRole('button', { name: 'Validate' }).click()\n        await expect(page.getByText('Validating...')).toBeVisible()\n        await expect(page.getByText('Validating...')).not.toBeVisible()\n        await expect(page.getByText('The name must be at least 3 characters.')).toBeVisible()\n      })\n\n      test('submits to the precognition endpoint when no arguments are given', async ({ page }) => {\n        await page.selectOption('select', key)\n        await page.getByRole('button', { name: 'Submit without args' }).click()\n\n        await expect(page).toHaveURL('/precognition/default')\n\n        // @ts-ignore\n        const dump = await page.evaluate(() => window._inertia_request_dump)\n        await expect(dump).not.toBeNull()\n\n        await expect(dump.method).toEqual('post')\n        await expect(dump.headers['precognition']).toBeUndefined()\n        await expect(dump.form).toEqual({\n          name: 'a',\n        })\n      })\n\n      test('submits to another endpoint using method + url arguments', async ({ page }) => {\n        await page.selectOption('select', key)\n        await page.getByRole('button', { name: 'Submit with args' }).click()\n\n        const dump = await shouldBeDumpPage(page, 'patch')\n        await expect(dump.headers['precognition']).toBeUndefined()\n        await expect(dump.form).toEqual({\n          name: 'a',\n        })\n      })\n\n      test('submits to another endpoint using wayfinder-shaped argument', async ({ page }) => {\n        await page.selectOption('select', key)\n        await page.getByRole('button', { name: 'Submit with Wayfinder' }).click()\n\n        const dump = await shouldBeDumpPage(page, 'post')\n        await expect(dump.headers['precognition']).toBeUndefined()\n        await expect(dump.form).toEqual({\n          name: 'a',\n        })\n      })\n\n      test('submits to another endpoint using the form.[method](url) syntax', async ({ page }) => {\n        await page.selectOption('select', key)\n        await page.getByRole('button', { name: 'Submit with method' }).click()\n\n        const dump = await shouldBeDumpPage(page, 'put')\n        await expect(dump.headers['precognition']).toBeUndefined()\n        await expect(dump.form).toEqual({\n          name: 'a',\n        })\n      })\n    })\n  })\n\n  test.describe('Backward compatibility', () => {\n    test.beforeEach(async ({ page }) => {\n      await page.goto('/form-helper/precognition/compatibility')\n    })\n\n    test('setErrors() alias sets multiple errors correctly', async ({ page }) => {\n      await page.click('#test-setErrors')\n\n      await expect(page.locator('#name-error')).toHaveText('setErrors test')\n      await expect(page.locator('#email-error')).toHaveText('setErrors email test')\n      await expect(page.locator('#company-error')).toHaveText('setErrors company test')\n    })\n\n    test('forgetError() alias clears single error correctly', async ({ page }) => {\n      await page.click('#test-setErrors')\n      await expect(page.locator('#name-error')).toHaveText('setErrors test')\n      await expect(page.locator('#email-error')).toHaveText('setErrors email test')\n      await expect(page.locator('#company-error')).toHaveText('setErrors company test')\n\n      await page.click('#test-forgetError')\n\n      await expect(page.locator('#name-error')).not.toBeVisible()\n      await expect(page.locator('#email-error')).toHaveText('setErrors email test')\n      await expect(page.locator('#company-error')).toHaveText('setErrors company test')\n    })\n\n    test('touch() accepts array parameters (original API)', async ({ page }) => {\n      await expect(page.locator('#touched-name')).toHaveText('Name touched: no')\n      await expect(page.locator('#touched-email')).toHaveText('Email touched: no')\n      await expect(page.locator('#touched-company')).toHaveText('Company touched: no')\n      await expect(page.locator('#touched-any')).toHaveText('Any touched: no')\n\n      await page.click('#test-touch-array')\n\n      // Name + email fields should now be touched\n      await expect(page.locator('#touched-name')).toHaveText('Name touched: yes')\n      await expect(page.locator('#touched-email')).toHaveText('Email touched: yes')\n      await expect(page.locator('#touched-company')).toHaveText('Company touched: no')\n      await expect(page.locator('#touched-any')).toHaveText('Any touched: yes')\n    })\n\n    test('touch() accepts spread parameters (new API)', async ({ page }) => {\n      await expect(page.locator('#touched-name')).toHaveText('Name touched: no')\n      await expect(page.locator('#touched-email')).toHaveText('Email touched: no')\n      await expect(page.locator('#touched-company')).toHaveText('Company touched: no')\n      await expect(page.locator('#touched-any')).toHaveText('Any touched: no')\n\n      await page.click('#test-touch-spread')\n\n      await expect(page.locator('#touched-name')).toHaveText('Name touched: yes')\n      await expect(page.locator('#touched-email')).toHaveText('Email touched: yes')\n      await expect(page.locator('#touched-company')).toHaveText('Company touched: no')\n      await expect(page.locator('#touched-any')).toHaveText('Any touched: yes')\n    })\n\n    test('forgetError() and touch() accept a NamedInputEvent', async ({ page }) => {\n      await page.click('#test-setErrors')\n      await expect(page.locator('#company-error')).toHaveText('setErrors company test')\n      await expect(page.locator('#touched-company')).toHaveText('Company touched: no')\n\n      await page.focus('input[name=\"company\"]')\n\n      await expect(page.locator('#company-error')).not.toBeVisible()\n      await expect(page.locator('#touched-company')).toHaveText('Company touched: yes')\n    })\n  })\n})\n"
  },
  {
    "path": "tests/prefetch.spec.ts",
    "content": "import { expect, Page, test } from '@playwright/test'\nimport { requests } from './support'\n\nconst isPrefetchPage = async (page: Page, id: number) => {\n  await page.waitForURL(`prefetch/${id}`)\n  await expect(page.getByText(`This is page ${id}`)).toBeVisible()\n}\n\nconst isPrefetchSwrPage = async (page: Page, id: number) => {\n  await page.waitForURL(`prefetch/swr/${id}`)\n  await expect(page.getByText(`This is page ${id}`)).toBeVisible()\n}\n\nconst hoverAndClick = async (page: Page, buttonText: string, id: number) => {\n  const prefetchPromise = page.waitForResponse(`prefetch/swr/${id}`)\n  await page.getByRole('link', { name: buttonText, exact: true }).hover()\n  await prefetchPromise\n  await page.getByRole('link', { name: buttonText, exact: true }).click()\n  await isPrefetchSwrPage(page, id)\n}\n\ntest('will not prefetch current page', async ({ page }) => {\n  // These two prefetch requests should be made on mount\n  const prefetch2 = page.waitForResponse('prefetch/2')\n  const prefetch4 = page.waitForResponse('prefetch/4')\n\n  await page.goto('prefetch/1')\n\n  // These two prefetch requests should be made on mount\n  const request2 = await prefetch2\n  const request4 = await prefetch4\n\n  expect(request2.request().headers().purpose).toBe('prefetch')\n  expect(request4.request().headers().purpose).toBe('prefetch')\n\n  requests.listen(page)\n  await page.getByRole('link', { name: 'On Hover (Default)' }).hover()\n  await page.waitForTimeout(100)\n  // This is the page we're already on, so it shouldn't make a request\n  await expect(requests.requests.length).toBe(0)\n})\n\ntest('removes single-use prefetch from cache when cacheFor is 0', async ({ page }) => {\n  const prefetch5 = page.waitForResponse('prefetch/5')\n\n  await page.goto('prefetch/1')\n  await prefetch5\n\n  requests.listen(page)\n  await page.getByRole('link', { name: 'On Mount (Once)' }).click()\n  await isPrefetchPage(page, 5)\n  await expect(requests.requests.length).toBe(0)\n\n  // Now that we've used it, it should be removed from the cache\n  await page.getByRole('link', { name: 'On Mount (Once)' }).click()\n  await expect(requests.requests.length).toBe(1)\n})\n\ntest('can prefetch using link props', async ({ page }) => {\n  // These two prefetch requests should be made on mount\n  const prefetch2 = page.waitForResponse('prefetch/2')\n  const prefetch4 = page.waitForResponse('prefetch/4')\n\n  await page.goto('prefetch/1')\n\n  // These two prefetch requests should be made on mount\n  await prefetch2\n  await prefetch4\n\n  requests.listen(page)\n\n  await page.getByRole('link', { name: 'On Mount', exact: true }).click()\n  await isPrefetchPage(page, 2)\n  await expect(requests.requests.length).toBe(0)\n\n  await page.getByRole('link', { name: 'On Hover + Mount' }).click()\n  await isPrefetchPage(page, 4)\n  await expect(requests.requests.length).toBe(0)\n\n  await page.getByRole('link', { name: 'On Click' }).hover()\n  const prefetch3 = page.waitForResponse('prefetch/3')\n  await page.mouse.down()\n  await prefetch3\n  await expect(page).toHaveURL('prefetch/4')\n  requests.listen(page)\n  await page.mouse.up()\n  await isPrefetchPage(page, 3)\n  await expect(requests.requests.length).toBe(0)\n\n  // Wait for mount-based prefetches to settle before testing hover behavior\n  await page.waitForLoadState('networkidle')\n\n  requests.listen(page)\n  await page.getByRole('link', { name: 'On Hover (Default)' }).hover()\n  await page.getByRole('link', { name: 'On Click' }).hover()\n  // If they just do a quick hover, it shouldn't make the request\n  await expect(requests.requests.length).toBe(0)\n\n  const prefetch1 = page.waitForResponse('prefetch/1')\n  await page.getByRole('link', { name: 'On Hover (Default)' }).hover()\n  await prefetch1\n  await expect(page).toHaveURL('prefetch/3')\n\n  requests.listen(page)\n  await page.getByRole('link', { name: 'On Hover (Default)' }).click()\n  await isPrefetchPage(page, 1)\n  await expect(requests.requests.length).toBe(0)\n\n  // Wait for the cache to timeout on the combo link\n  await page.waitForTimeout(1200)\n\n  const prefetch4b = page.waitForResponse('prefetch/4')\n  await page.getByRole('link', { name: 'On Hover + Mount' }).hover()\n  await prefetch4b\n  await expect(page).toHaveURL('prefetch/1')\n\n  requests.listen(page)\n  await page.getByRole('link', { name: 'On Hover + Mount' }).click()\n  await isPrefetchPage(page, 4)\n  await expect(requests.requests.length).toBe(0)\n})\n\ntest('can prefetch using link props with keyboard events', async ({ page }) => {\n  // These two prefetch requests should be made on mount\n  const prefetch2 = page.waitForResponse('prefetch/2')\n  const prefetch4 = page.waitForResponse('prefetch/4')\n\n  await page.goto('prefetch/1')\n\n  // These two prefetch requests should be made on mount\n  await prefetch2\n  await prefetch4\n\n  // Keyboard activation with Enter\n  await page.getByRole('link', { name: 'On Enter' }).focus()\n  const prefetch6 = page.waitForResponse('prefetch/6')\n  await page.keyboard.down('Enter')\n  await prefetch6\n  await expect(page).toHaveURL('prefetch/1')\n  requests.listen(page)\n  await page.keyboard.up('Enter')\n  await isPrefetchPage(page, 6)\n  await expect(requests.requests.length).toBe(0)\n\n  // Keyboard activation with Spacebar on link (nothing happens)\n  await page.getByRole('link', { name: 'On Click' }).focus()\n  await page.keyboard.down(' ')\n  await expect(page).toHaveURL('prefetch/6')\n  requests.listen(page)\n  await page.keyboard.up(' ')\n  await expect(requests.requests.length).toBe(0)\n\n  // Keyboard activation with Spacebar on button\n  await page.getByRole('button', { name: 'On Spacebar' }).focus()\n  const prefetch7 = page.waitForResponse('prefetch/7')\n  await page.keyboard.down(' ')\n  await prefetch7\n  await expect(page).toHaveURL('prefetch/6')\n  requests.listen(page)\n  await page.keyboard.up(' ')\n  await isPrefetchPage(page, 7)\n  await expect(requests.requests.length).toBe(0)\n\n  // Keyboard activation with Enter on button\n  await page.goto('prefetch/1')\n  await page.getByRole('button', { name: 'On Spacebar' }).focus()\n  const prefetch7b = page.waitForResponse('prefetch/7')\n  await page.keyboard.down('Enter')\n  await prefetch7b\n  await expect(page).toHaveURL('prefetch/1')\n  requests.listen(page)\n  await page.keyboard.up('Enter')\n  await isPrefetchPage(page, 7)\n  await expect(requests.requests.length).toBe(0)\n})\n\ntest('does not navigate or prefetch on secondary button click when using prefetch=\"click\"', async ({\n  page,\n  browserName,\n}) => {\n  // Skip on WebKit\n  if (browserName === 'webkit') {\n    return test.skip('Bug in Playwright + WebKit causing the context menu to stick around')\n  }\n\n  // These two prefetch requests should be made on mount\n  const prefetch2 = page.waitForResponse('prefetch/2')\n  const prefetch4 = page.waitForResponse('prefetch/4')\n\n  await page.goto('prefetch/1')\n\n  await prefetch2\n  await prefetch4\n\n  const link = page.getByRole('link', { name: 'On Click', exact: true })\n  await expect(link).toBeVisible()\n\n  requests.listen(page)\n\n  // Right-click (secondary button) should not trigger navigation or prefetch\n  await link.click({ button: 'right' })\n  await page.waitForTimeout(100)\n  await expect(requests.requests.length).toBe(0)\n  await expect(page).toHaveURL('prefetch/1')\n\n  // Middle-click should also not trigger navigation or prefetch\n  await link.click({ button: 'middle' })\n  await page.waitForTimeout(100)\n  await expect(requests.requests.length).toBe(0)\n  await expect(page).toHaveURL('prefetch/1')\n\n  // Left-click should work normally (mousedown prefetches, mouseup navigates)\n  await link.hover()\n  const prefetch3b = page.waitForResponse('prefetch/3')\n  await page.mouse.down()\n  await prefetch3b\n  await expect(page).toHaveURL('prefetch/1')\n  requests.listen(page)\n  await page.mouse.up()\n  await isPrefetchPage(page, 3)\n  await expect(requests.requests.length).toBe(0)\n})\n\ntest('can cache links with single cache value', async ({ page }) => {\n  await page.goto('prefetch/swr/1')\n\n  requests.listen(page)\n\n  // Click back and forth a couple of times to ensure no requests go out\n  await hoverAndClick(page, '1s Expired (Number)', 3)\n  await expect(requests.requests.length).toBe(1)\n  const lastLoaded1 = await page.locator('#last-loaded').textContent()\n\n  await hoverAndClick(page, '1s Expired', 2)\n  await isPrefetchSwrPage(page, 2)\n  await expect(requests.requests.length).toBe(2)\n  const lastLoaded2 = await page.locator('#last-loaded').textContent()\n\n  requests.listen(page)\n\n  await page.getByRole('link', { exact: true, name: '1s Expired (Number)' }).click()\n  await isPrefetchSwrPage(page, 3)\n  await expect(requests.requests.length).toBe(0)\n  const lastLoaded1New = await page.locator('#last-loaded').textContent()\n  await expect(lastLoaded1).toBe(lastLoaded1New)\n\n  await page.getByRole('link', { exact: true, name: '1s Expired' }).click()\n  await isPrefetchSwrPage(page, 2)\n  await expect(requests.requests.length).toBe(0)\n  const lastLoaded2New = await page.locator('#last-loaded').textContent()\n  await expect(lastLoaded2).toBe(lastLoaded2New)\n\n  // Wait for cache to expire\n  await page.waitForTimeout(1200)\n\n  requests.listenForFinished(page)\n\n  await hoverAndClick(page, '1s Expired (Number)', 3)\n  await expect(requests.finished.length).toBe(1)\n  const lastLoaded1Fresh = await page.locator('#last-loaded').textContent()\n  await expect(lastLoaded1).not.toBe(lastLoaded1Fresh)\n\n  await hoverAndClick(page, '1s Expired', 2)\n  await expect(requests.finished.length).toBe(2)\n  const lastLoaded2Fresh = await page.locator('#last-loaded').textContent()\n  await expect(lastLoaded2).not.toBe(lastLoaded2Fresh)\n})\n\ntest.describe('UrlMethodPair prefetch support', () => {\n  test.beforeEach(async ({ page }) => {\n    // Clear any existing cache before each test\n    await page.goto('prefetch/wayfinder')\n    await page.locator('#flush-all').click()\n    await page.waitForTimeout(100)\n\n    // Verify the cache is actually cleared\n    await expect(page.locator('#is-prefetched')).toHaveText('false')\n    await expect(page.locator('#is-prefetching')).toHaveText('false')\n  })\n\n  test('can prefetch with UrlMethodPair', async ({ page }) => {\n    await expect(page.locator('#is-prefetched')).toHaveText('false')\n    await expect(page.locator('#is-prefetching')).toHaveText('false')\n\n    const prefetchPromise = page.waitForResponse((response) => response.url().includes('prefetch/swr/4'))\n    await page.locator('#test-prefetch').click()\n\n    await expect(page.locator('#is-prefetching')).toHaveText('true')\n    await expect(page.locator('#is-prefetched')).toHaveText('false')\n\n    await prefetchPromise\n\n    await expect(page.locator('#is-prefetched')).toHaveText('true')\n    await expect(page.locator('#is-prefetching')).toHaveText('false')\n  })\n\n  test('can use flush with UrlMethodPair', async ({ page }) => {\n    const swrResponse = page.waitForResponse((response) => response.url().includes('prefetch/swr/4'))\n    await page.locator('#test-prefetch').click()\n    await swrResponse\n\n    await expect(page.locator('#is-prefetched')).toHaveText('true')\n\n    await page.locator('#test-flush').click()\n    await expect(page.locator('#is-prefetched')).toHaveText('false')\n  })\n})\n\ntest('can visit the page when prefetching has failed due to network error', async ({ page, browser }) => {\n  await page.goto('prefetch/after-error')\n\n  page.context().setOffline(true)\n  await page.getByRole('button', { name: 'Prefetch Page' }).click()\n\n  page.context().setOffline(false)\n\n  requests.listen(page)\n  await page.getByRole('button', { name: 'Visit Page' }).click()\n\n  await isPrefetchSwrPage(page, 1)\n})\n\ntest('displays the error modal correctly when prefetching a non-Inertia response', async ({ page }) => {\n  await page.goto('prefetch/after-error')\n\n  const prefetchPromise = page.waitForResponse('/non-inertia')\n  await page.getByRole('button', { name: 'Prefetch Non-Inertia' }).click()\n  await prefetchPromise\n\n  await page.getByRole('button', { name: 'Visit Non-Inertia' }).click()\n\n  await expect(page.frameLocator('iframe').getByText('This is a page that does not')).toBeVisible()\n  await expect(page.frameLocator('iframe').locator('body')).toContainText(\n    'This is a page that does not have the Inertia app loaded.',\n  )\n})\n\nconst submitButtonTexts = ['Submit to Same URL', 'Submit to Other URL']\n\nsubmitButtonTexts.forEach((buttonText) => {\n  test.describe('prefetch cache is invalidated after form submission redirect', () => {\n    test(buttonText, async ({ page }) => {\n      await page.goto('prefetch/test-page')\n\n      const prefetchPromise = page.waitForResponse('/prefetch/form')\n      await page.getByRole('link', { name: 'Go to Prefetch Form' }).hover()\n      await prefetchPromise\n\n      requests.listen(page)\n      await page.getByRole('link', { name: 'Go to Prefetch Form' }).click()\n      await page.waitForURL('/prefetch/form')\n      await expect(requests.requests.length).toBe(0)\n\n      const firstRandomValue = await page.locator('.random-value').textContent()\n      expect(firstRandomValue).toBeTruthy()\n\n      await page.getByRole('button', { name: buttonText }).click()\n      await page.waitForURL('/prefetch/form')\n\n      await page.waitForTimeout(100)\n      const secondRandomValue = await page.locator('.random-value').textContent()\n      expect(secondRandomValue).not.toBe(firstRandomValue)\n\n      await page.getByRole('link', { name: 'Back to Test Page' }).click()\n      await page.waitForURL('/prefetch/test-page')\n\n      requests.listen(page)\n      await page.getByRole('link', { name: 'Go to Prefetch Form' }).click()\n      await page.waitForURL('/prefetch/form')\n\n      const thirdRandomValue = await page.locator('.random-value').textContent()\n      expect(thirdRandomValue).not.toBe(firstRandomValue)\n    })\n  })\n})\n\ntest.skip('can do SWR when the link cacheFor prop has two values', async ({ page }) => {\n  await page.goto('prefetch/swr/1')\n\n  requests.listen(page)\n\n  await hoverAndClick(page, '1s Stale, 2s Expired (Number)', 5)\n  await expect(requests.requests.length).toBe(1)\n  const lastLoaded1 = await page.locator('#last-loaded').textContent()\n\n  await hoverAndClick(page, '1s Stale, 2s Expired', 4)\n  await expect(requests.requests.length).toBe(2)\n  const lastLoaded2 = await page.locator('#last-loaded').textContent()\n\n  requests.listen(page)\n\n  // Click back and forth a couple of times to ensure no requests go out\n  await page.getByRole('link', { exact: true, name: '1s Stale, 2s Expired (Number)' }).click()\n  await isPrefetchSwrPage(page, 5)\n  await expect(requests.requests.length).toBe(0)\n  const lastLoaded1New = await page.locator('#last-loaded').textContent()\n  await expect(lastLoaded1).toBe(lastLoaded1New)\n\n  await page.getByRole('link', { exact: true, name: '1s Stale, 2s Expired' }).click()\n  await isPrefetchSwrPage(page, 4)\n  await expect(requests.requests.length).toBe(0)\n  const lastLoaded2New = await page.locator('#last-loaded').textContent()\n  await expect(lastLoaded2).toBe(lastLoaded2New)\n\n  // Wait for stale time to pass\n  await page.waitForTimeout(1200)\n\n  requests.listenForFinished(page)\n\n  const promiseFor5 = page.waitForResponse('prefetch/swr/5')\n  await page.getByRole('link', { exact: true, name: '1s Stale, 2s Expired (Number)' }).hover()\n  await page.waitForTimeout(75)\n  await page.getByRole('link', { exact: true, name: '1s Stale, 2s Expired (Number)' }).click()\n  await isPrefetchSwrPage(page, 5)\n  const lastLoaded1Stale = await page.locator('#last-loaded').textContent()\n  await expect(lastLoaded1).toBe(lastLoaded1Stale)\n  await promiseFor5\n\n  //   await expect(requests.finished.length).toBe(1)\n  await page.waitForTimeout(600)\n  const lastLoaded1Fresh = await page.locator('#last-loaded').textContent()\n  await expect(lastLoaded1).not.toBe(lastLoaded1Fresh)\n\n  const promiseFor4 = page.waitForResponse('prefetch/swr/4')\n  await page.getByRole('link', { exact: true, name: '1s Stale, 2s Expired' }).click()\n  await isPrefetchSwrPage(page, 4)\n  const lastLoaded2Stale = await page.locator('#last-loaded').textContent()\n  await expect(lastLoaded2).toBe(lastLoaded2Stale)\n\n  await promiseFor4\n  //   await expect(requests.finished.length).toBe(2)\n  await page.waitForTimeout(100)\n  const lastLoaded2Fresh = await page.locator('#last-loaded').textContent()\n  await expect(lastLoaded2).not.toBe(lastLoaded2Fresh)\n})\n\ntest.describe('tags', () => {\n  const isTagsPage = async (page: Page, id: number) => {\n    await page.waitForURL(`prefetch/tags/${id}`)\n    await expect(page.getByText(`This is tags page ${id}`)).toBeVisible()\n  }\n\n  test('can flush prefetch cache by tags', async ({ page }) => {\n    await page.goto('prefetch/tags/1')\n\n    const prefetch2 = page.waitForResponse('prefetch/tags/2')\n    await page.getByRole('link', { name: 'User Page 2' }).hover()\n    await page.waitForTimeout(75)\n    await prefetch2\n\n    const prefetch3 = page.waitForResponse('prefetch/tags/3')\n    await page.getByRole('link', { name: 'Product Page 3' }).hover()\n    await page.waitForTimeout(75)\n    await prefetch3\n\n    const prefetch6 = page.waitForResponse('prefetch/tags/6')\n    await page.getByRole('link', { name: 'Untagged Page 6' }).hover()\n    await page.waitForTimeout(75)\n    await prefetch6\n\n    requests.listen(page)\n    await page.getByRole('link', { name: 'User Page 2' }).click()\n    await isTagsPage(page, 2)\n    await expect(requests.requests.length).toBe(0)\n\n    requests.listen(page)\n    await page.getByRole('link', { name: 'Product Page 3' }).click()\n    await isTagsPage(page, 3)\n    await expect(requests.requests.length).toBe(0)\n\n    await page.getByRole('button', { name: 'Flush User Tags' }).click()\n\n    requests.listen(page)\n    await page.getByRole('link', { name: 'User Page 2' }).click()\n    await isTagsPage(page, 2)\n    await expect(requests.requests.length).toBeGreaterThanOrEqual(1)\n\n    requests.listen(page)\n    await page.getByRole('link', { name: 'Product Page 3' }).click()\n    await isTagsPage(page, 3)\n    await expect(requests.requests.length).toBe(0)\n\n    requests.listen(page)\n    await page.getByRole('link', { name: 'Untagged Page 6' }).click()\n    await isTagsPage(page, 6)\n    await expect(requests.requests.length).toBe(0)\n  })\n\n  test('can flush multiple tags simultaneously', async ({ page }) => {\n    await page.goto('prefetch/tags/1')\n\n    const prefetch2 = page.waitForResponse('prefetch/tags/2')\n    await page.getByRole('link', { name: 'User Page 2' }).hover()\n    await page.waitForTimeout(75)\n    await prefetch2\n\n    const prefetch3 = page.waitForResponse('prefetch/tags/3')\n    await page.getByRole('link', { name: 'Product Page 3' }).hover()\n    await page.waitForTimeout(75)\n    await prefetch3\n\n    const prefetch5 = page.waitForResponse('prefetch/tags/5')\n    await page.getByRole('link', { name: 'Admin Page 5' }).hover()\n    await page.waitForTimeout(75)\n    await prefetch5\n\n    const prefetch6 = page.waitForResponse('prefetch/tags/6')\n    await page.getByRole('link', { name: 'Untagged Page 6' }).hover()\n    await page.waitForTimeout(75)\n    await prefetch6\n\n    requests.listen(page)\n    await page.getByRole('link', { name: 'User Page 2' }).click()\n    await isTagsPage(page, 2)\n    await expect(requests.requests.length).toBe(0)\n\n    requests.listen(page)\n    await page.getByRole('link', { name: 'Product Page 3' }).click()\n    await isTagsPage(page, 3)\n    await expect(requests.requests.length).toBe(0)\n\n    requests.listen(page)\n    await page.getByRole('link', { name: 'Admin Page 5' }).click()\n    await isTagsPage(page, 5)\n    await expect(requests.requests.length).toBe(0)\n\n    requests.listen(page)\n    await page.getByRole('link', { name: 'Untagged Page 6' }).click()\n    await isTagsPage(page, 6)\n    await expect(requests.requests.length).toBe(0)\n\n    await page.getByRole('button', { name: 'Flush User + Product Tags' }).click()\n\n    requests.listen(page)\n    await page.getByRole('link', { name: 'User Page 2' }).click()\n    await isTagsPage(page, 2)\n    await expect.poll(() => requests.requests.length).toBeGreaterThanOrEqual(1)\n\n    requests.listen(page)\n    await page.getByRole('link', { name: 'Product Page 3' }).click()\n    await isTagsPage(page, 3)\n    await expect.poll(() => requests.requests.length).toBeGreaterThanOrEqual(1)\n\n    requests.listen(page)\n    await page.getByRole('link', { name: 'Admin Page 5' }).click()\n    await isTagsPage(page, 5)\n    await expect(requests.requests.length).toBe(0)\n\n    requests.listen(page)\n    await page.getByRole('link', { name: 'Untagged Page 6' }).click()\n    await isTagsPage(page, 6)\n    await expect(requests.requests.length).toBe(0)\n  })\n\n  const cacheTagPropTypes = ['string', 'array']\n\n  cacheTagPropTypes.forEach((propType) => {\n    test.describe(`(using ${propType})`, () => {\n      test('can use programmatic router.prefetch with tags', async ({ page }) => {\n        await page.goto(`prefetch/tags/1/${propType}`)\n\n        const prefetch2 = page.waitForResponse('/prefetch/tags/2')\n        const prefetch3 = page.waitForResponse('/prefetch/tags/3')\n        const prefetch6 = page.waitForResponse('/prefetch/tags/6')\n\n        await page.getByRole('button', { name: 'Programmatic Prefetch' }).click()\n\n        await prefetch2\n        await prefetch3\n        await prefetch6\n\n        requests.listen(page)\n        await page.getByRole('link', { name: 'User Page 2' }).click()\n        await isTagsPage(page, 2)\n        await expect(requests.requests.length).toBe(0)\n\n        requests.listen(page)\n        await page.getByRole('link', { name: 'Product Page 3' }).click()\n        await isTagsPage(page, 3)\n        await expect(requests.requests.length).toBe(0)\n\n        requests.listen(page)\n        await page.getByRole('link', { name: 'Untagged Page 6' }).click()\n        await isTagsPage(page, 6)\n        await expect(requests.requests.length).toBe(0)\n\n        await page.getByRole('button', { name: 'Flush User Tags' }).click()\n\n        requests.listen(page)\n        await page.getByRole('link', { name: 'User Page 2' }).click()\n        await isTagsPage(page, 2)\n        await expect(requests.requests.length).toBeGreaterThanOrEqual(1)\n\n        requests.listen(page)\n        await page.getByRole('link', { name: 'Product Page 3' }).click()\n        await isTagsPage(page, 3)\n        await expect(requests.requests.length).toBe(0)\n\n        requests.listen(page)\n        await page.getByRole('link', { name: 'Untagged Page 6' }).click()\n        await isTagsPage(page, 6)\n        await expect(requests.requests.length).toBe(0)\n      })\n\n      test('can use useForm with invalidate option', async ({ page }) => {\n        await page.goto(`prefetch/tags/1/${propType}`)\n\n        const prefetchUser = page.waitForResponse('/prefetch/tags/2')\n        await page.getByRole('link', { name: 'User Page 2' }).hover()\n        await page.waitForTimeout(100)\n        await prefetchUser\n\n        const prefetchProduct = page.waitForResponse('/prefetch/tags/3')\n        await page.getByRole('link', { name: 'Product Page 3' }).hover()\n        await page.waitForTimeout(100)\n        await prefetchProduct\n\n        const prefetchUntagged = page.waitForResponse('/prefetch/tags/6')\n        await page.getByRole('link', { name: 'Untagged Page 6' }).hover()\n        await page.waitForTimeout(100)\n        await prefetchUntagged\n\n        await page.fill('#form-name', 'Test User')\n        await page.click('#submit-invalidate-user')\n\n        await page.waitForURL('/dump/post')\n\n        await page.goBack()\n\n        await page.waitForLoadState('networkidle')\n        requests.listen(page)\n        await page.getByRole('link', { name: 'User Page 2' }).click()\n        await isTagsPage(page, 2)\n        await expect.poll(() => requests.requests.length).toBeGreaterThanOrEqual(1)\n\n        await page.goBack()\n\n        await page.waitForLoadState('networkidle')\n        requests.listen(page)\n        await page.getByRole('link', { name: 'Product Page 3' }).click()\n        await isTagsPage(page, 3)\n        expect(requests.requests.length).toBe(0)\n\n        await page.goBack()\n\n        await page.waitForLoadState('networkidle')\n        requests.listen(page)\n        await page.getByRole('link', { name: 'Untagged Page 6' }).click()\n        await isTagsPage(page, 6)\n        expect(requests.requests.length).toBe(0)\n      })\n    })\n  })\n})\n\ntest('can use prefetched requests with preserveState', async ({ page }) => {\n  await page.goto('/prefetch/preserve-state')\n\n  const prefetchResponse = page.waitForResponse('prefetch/preserve-state?page=2')\n  await page.getByRole('button', { name: 'Prefetch Page 2' }).click()\n  await prefetchResponse\n\n  requests.listen(page)\n\n  // Test both preserveState options use cache\n  await page.getByRole('button', { name: 'Load Page 2 (preserveState: false)' }).click()\n  await expect(page.getByText('Current Page: 2')).toBeVisible()\n  await expect(requests.requests.length).toBe(0)\n\n  await page.goto('/prefetch/preserve-state')\n\n  const prefetchResponse2 = page.waitForResponse('prefetch/preserve-state?page=2')\n  await page.getByRole('button', { name: 'Prefetch Page 2' }).click()\n  await prefetchResponse2\n\n  requests.listen(page)\n\n  await page.getByRole('button', { name: 'Load Page 2 (preserveState: true)' }).click()\n  await expect(page.getByText('Current Page: 2')).toBeVisible()\n  await expect(requests.requests.length).toBe(0)\n})\n"
  },
  {
    "path": "tests/progress-component.spec.ts",
    "content": "import { expect, Locator, test } from '@playwright/test'\n\nconst getProgressPercent = async (bar: Locator) => {\n  return await bar.evaluate((element) => {\n    // Get the inline style transform value which has the original percentage\n    const inlineTransform = element.style.transform\n\n    if (!inlineTransform || inlineTransform === 'none') {\n      return 0\n    }\n\n    // Extract percentage from translate3d(-75%, 0px, 0px)\n    const match = inlineTransform.match(/translate3d\\((-?\\d+(?:\\.\\d+)?)%/)\n    return match ? parseFloat(match[1]) : 0\n  })\n}\n\ntest.describe('Progress Component', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto('/progress-component')\n  })\n\n  test('start() creates nprogress bar and begins auto-animation', async ({ page }) => {\n    await expect(page.locator('#nprogress .bar')).not.toBeVisible()\n\n    await page.getByRole('button', { name: 'Start', exact: true }).click()\n\n    const bar = page.locator('#nprogress .bar')\n    const peg = page.locator('#nprogress .peg')\n\n    await expect(bar).toBeVisible()\n    await expect(peg).toBeVisible()\n\n    const initialTransform = await getProgressPercent(bar)\n    await expect(initialTransform).toBeLessThan(-70)\n\n    await page.waitForTimeout(300)\n    const afterTrickle = await getProgressPercent(bar)\n\n    await expect(afterTrickle).toBeGreaterThan(initialTransform)\n  })\n\n  test('set() without start() directly updates bar position', async ({ page }) => {\n    await page.getByRole('button', { name: 'Set 25%' }).click()\n\n    const bar = page.locator('#nprogress .bar')\n    await expect(bar).toBeVisible()\n\n    const transform25 = await getProgressPercent(bar)\n    await expect(transform25).toBeCloseTo(-75, 1)\n\n    await page.getByRole('button', { name: 'Set 50%' }).click()\n    const transform50 = await getProgressPercent(bar)\n    await expect(transform50).toBeCloseTo(-50, 1)\n\n    await page.getByRole('button', { name: 'Set 75%' }).click()\n    const transform75 = await getProgressPercent(bar)\n    await expect(transform75).toBeCloseTo(-25, 1)\n  })\n\n  test('finish() animates to 100% then fades out and removes bar', async ({ page }) => {\n    test.setTimeout(10_000)\n    await page.getByRole('button', { name: 'Set 25%' }).click()\n\n    const bar = page.locator('#nprogress .bar')\n    await expect(bar).toBeVisible()\n\n    const beforeFinish = await getProgressPercent(bar)\n    await expect(beforeFinish).toBeCloseTo(-75, 1)\n\n    await page.getByRole('button', { name: 'Finish' }).click()\n\n    await expect.poll(async () => await getProgressPercent(bar), { timeout: 2000 }).toBeGreaterThan(-75)\n\n    await page.waitForFunction(\n      () => {\n        const bar = document.querySelector('#nprogress .bar') as HTMLElement\n        const transform = bar?.style.transform\n\n        const match = transform?.match(/translate3d\\((-?\\d+(?:\\.\\d+)?)%/)\n\n        return match && Math.abs(parseFloat(match[1])) < 1\n      },\n      {},\n      { timeout: 3000 },\n    )\n\n    const at100 = await getProgressPercent(bar)\n    await expect(at100).toBeCloseTo(0, 1)\n\n    await expect(bar).not.toBeVisible()\n  })\n\n  test('reset() resets status to 0', async ({ page }) => {\n    await page.getByRole('button', { name: 'Set 50%' }).click()\n\n    const bar = page.locator('#nprogress .bar')\n    const transform50 = await getProgressPercent(bar)\n    await expect(transform50).toBeCloseTo(-50, 1)\n\n    await page.getByRole('button', { name: 'Reset' }).click()\n\n    const transform0 = await getProgressPercent(bar)\n    await expect(transform0).toBeLessThan(-70)\n  })\n\n  test('remove() completes and removes nprogress bar', async ({ page }) => {\n    await page.getByRole('button', { name: 'Start', exact: true }).click()\n    await page.getByRole('button', { name: 'Set 75%' }).click()\n\n    await expect(page.locator('#nprogress .bar')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Remove' }).click()\n\n    await page.waitForTimeout(500)\n    await expect(page.locator('#nprogress .bar')).not.toBeVisible()\n  })\n\n  test('hide() and reveal() control nprogress visibility', async ({ page }) => {\n    await page.getByRole('button', { name: 'Start', exact: true }).click()\n\n    await expect(page.locator('#nprogress .bar')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Hide' }).click()\n\n    await expect(page.locator('#nprogress .bar')).not.toBeVisible()\n\n    await page.getByRole('button', { name: 'Reveal' }).click()\n\n    await expect(page.locator('#nprogress .bar')).toBeVisible()\n  })\n\n  test('multiple hide() calls require multiple reveal() calls', async ({ page }) => {\n    await page.getByRole('button', { name: 'Start', exact: true }).click()\n    await expect(page.locator('#nprogress .bar')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Hide' }).click()\n    await page.getByRole('button', { name: 'Hide' }).click()\n    await expect(page.locator('#nprogress .bar')).not.toBeVisible()\n\n    await page.getByRole('button', { name: 'Reveal' }).click()\n    await expect(page.locator('#nprogress .bar')).not.toBeVisible()\n\n    await page.getByRole('button', { name: 'Reveal' }).click()\n    await expect(page.locator('#nprogress .bar')).toBeVisible()\n  })\n\n  test('isStarted() reflects actual DOM state', async ({ page }) => {\n    await page.getByRole('button', { name: 'Is Started' }).click()\n    let tests = await page.evaluate(() => (window as any).progressTests)\n    let isStarted = tests[tests.length - 1]\n    await expect(isStarted).toBe(false)\n    await expect(page.locator('#nprogress .bar')).not.toBeVisible()\n\n    await page.getByRole('button', { name: 'Clear' }).click()\n    await page.getByRole('button', { name: 'Start', exact: true }).click()\n    await page.getByRole('button', { name: 'Is Started' }).click()\n    tests = await page.evaluate(() => (window as any).progressTests)\n    isStarted = tests[tests.length - 1]\n    await expect(isStarted).toBe(true)\n    await expect(page.locator('#nprogress .bar')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Finish' }).click()\n    await page.getByRole('button', { name: 'Is Started' }).click()\n    tests = await page.evaluate(() => (window as any).progressTests)\n    isStarted = tests[tests.length - 1]\n    await expect(isStarted).toBe(false)\n    await page.waitForTimeout(500)\n    await expect(page.locator('#nprogress .bar')).not.toBeVisible()\n  })\n})\n"
  },
  {
    "path": "tests/remember.spec.ts",
    "content": "import test, { expect } from '@playwright/test'\nimport { shouldBeDumpPage } from './support'\n\ntest.describe('Remember (local state caching)', () => {\n  test('does not remember anything as of default', async ({ page }) => {\n    await page.goto('remember/default')\n\n    await page.fill('#name', 'A')\n    await page.check('#remember')\n    await page.fill('#untracked', 'B')\n\n    await page.getByRole('link', { name: 'Navigate away' }).click()\n\n    await shouldBeDumpPage(page, 'get')\n\n    await page.goBack()\n\n    await expect(page).toHaveURL('remember/default')\n\n    await expect(page.locator('#name')).toHaveValue('')\n    await expect(page.locator('#remember')).not.toBeChecked()\n    await expect(page.locator('#untracked')).toHaveValue('')\n  })\n\n  test('remembers tracked fields using the object syntax', async ({ page }) => {\n    await page.goto('remember/object')\n\n    await page.fill('#name', 'A')\n    await page.check('#remember')\n    await page.fill('#untracked', 'B')\n\n    await page.getByRole('link', { name: 'Navigate away' }).click()\n\n    await shouldBeDumpPage(page, 'get')\n\n    await page.goBack()\n\n    await expect(page).toHaveURL('remember/object')\n\n    await expect(page.locator('#name')).toHaveValue('A')\n    await expect(page.locator('#remember')).toBeChecked()\n    await expect(page.locator('#untracked')).toHaveValue('')\n\n    // Try again with updated values\n    await page.fill('#name', 'C')\n    await page.uncheck('#remember')\n    await page.getByRole('link', { name: 'Navigate away' }).click()\n\n    await shouldBeDumpPage(page, 'get')\n\n    await page.goBack()\n\n    await expect(page).toHaveURL('remember/object')\n    await expect(page.locator('#name')).toHaveValue('C')\n    await expect(page.locator('#remember')).not.toBeChecked()\n  })\n\n  test('restores remembered data when pressing the back button', async ({ page }) => {\n    await page.goto('remember/multiple-components')\n\n    await page.fill('#name', 'D')\n    await page.check('#remember')\n    await page.fill('#untracked', 'C')\n\n    await page.fill('.a-name', 'A1')\n    await page.fill('.a-untracked', 'A2')\n\n    await page.fill('.b-name', 'B1')\n    await page.check('.b-remember')\n    await page.fill('.b-untracked', 'B2')\n\n    await page.getByRole('link', { name: 'Navigate away' }).click()\n\n    await shouldBeDumpPage(page, 'get')\n\n    await page.goBack()\n\n    await expect(page).toHaveURL('remember/multiple-components')\n\n    await expect(page.locator('#name')).toHaveValue('D')\n    await expect(page.locator('#remember')).toBeChecked()\n    await expect(page.locator('#untracked')).toHaveValue('')\n    await expect(page.locator('.a-name')).toHaveValue('A1')\n    await expect(page.locator('.a-remember')).not.toBeChecked()\n    await expect(page.locator('.a-untracked')).toHaveValue('')\n    await expect(page.locator('.b-name')).toHaveValue('B1')\n    await expect(page.locator('.b-remember')).toBeChecked()\n    await expect(page.locator('.b-untracked')).toHaveValue('')\n\n    // Try again with updated values\n    await page.fill('#name', 'E')\n    await page.uncheck('#remember')\n\n    await page.getByRole('link', { name: 'Navigate away' }).click()\n\n    await shouldBeDumpPage(page, 'get')\n\n    await page.goBack()\n\n    await expect(page).toHaveURL('remember/multiple-components')\n    await expect(page.locator('#name')).toHaveValue('E')\n    await expect(page.locator('#remember')).not.toBeChecked()\n  })\n\n  test('restores remembered data when pressing the back button from another website', async ({ page }) => {\n    await page.goto('remember/multiple-components')\n\n    await page.fill('#name', 'D')\n    await page.check('#remember')\n    await page.fill('#untracked', 'C')\n\n    await page.fill('.a-name', 'A1')\n    await page.fill('.a-untracked', 'A2')\n\n    await page.fill('.b-name', 'B1')\n    await page.check('.b-remember')\n    await page.fill('.b-untracked', 'B2')\n\n    await page.getByRole('link', { name: 'Navigate off-site' }).click()\n\n    await expect(page).toHaveURL('non-inertia')\n\n    await page.goBack()\n\n    await page.waitForURL('remember/multiple-components')\n\n    await expect(page.locator('#name')).toHaveValue('D')\n    await expect(page.locator('#remember')).toBeChecked()\n    // This is seems to be browser dependent? Sometimes it's empty, sometimes it's the last value\n    // await expect(page.locator('#untracked')).toHaveValue('')\n\n    // Component \"A\" uses a string-style key (key: 'Users/Create')\n    await expect(page.locator('.a-name')).toHaveValue('A1')\n    await expect(page.locator('.a-remember')).not.toBeChecked()\n    // This is seems to be browser dependent? Sometimes it's empty, sometimes it's the last value\n    // await expect(page.locator('.a-untracked')).toHaveValue('')\n\n    // Component \"B\" uses a callback-style key (key: () => `Users/Edit:${this.user.id}`)\n    await expect(page.locator('.b-name')).toHaveValue('B1')\n    await expect(page.locator('.b-remember')).toBeChecked()\n    // This is seems to be browser dependent? Sometimes it's empty, sometimes it's the last value\n    // await expect(page.locator('.b-untracked')).toHaveValue('')\n\n    // Try again with updated values\n    await page.fill('#name', 'E')\n    await page.uncheck('#remember')\n\n    await page.getByRole('link', { name: 'Navigate off-site' }).click()\n\n    await expect(page).toHaveURL('non-inertia')\n\n    await page.goBack()\n\n    await page.waitForURL('remember/multiple-components')\n    await expect(page.locator('#name')).toHaveValue('E')\n    await expect(page.locator('#remember')).not.toBeChecked()\n    // This is seems to be browser dependent? Sometimes it's empty, sometimes it's the last value\n    // await expect(page.locator('#untracked')).toHaveValue('')\n  })\n\n  test('does not restore remembered data after browser refresh', async ({ page }) => {\n    await page.goto('remember/object')\n\n    await page.fill('#name', 'RefreshTest')\n    await page.check('#remember')\n    await page.fill('#untracked', 'ShouldNotRemember')\n\n    await page.getByRole('link', { name: 'Navigate away' }).click()\n    await shouldBeDumpPage(page, 'get')\n\n    await page.goBack()\n    await expect(page).toHaveURL('remember/object')\n    await expect(page.locator('#name')).toHaveValue('RefreshTest')\n    await expect(page.locator('#remember')).toBeChecked()\n    await expect(page.locator('#untracked')).toHaveValue('')\n\n    await page.reload()\n\n    // After refresh, fields should be empty (not restored from remember state)\n    await expect(page.locator('#name')).toHaveValue('')\n    await expect(page.locator('#remember')).not.toBeChecked()\n    await expect(page.locator('#untracked')).toHaveValue('')\n  })\n\n  test.describe('form helper', () => {\n    test('does not remember form data as of default', async ({ page }) => {\n      await page.goto('remember/form-helper/default')\n\n      await page.fill('#name', 'A')\n      await page.fill('#handle', 'B')\n      await page.check('#remember')\n      await page.fill('#untracked', 'C')\n\n      await page.getByRole('link', { name: 'Navigate away' }).click()\n\n      await shouldBeDumpPage(page, 'get')\n\n      await page.goBack()\n\n      await expect(page).toHaveURL('remember/form-helper/default')\n\n      await expect(page.locator('#name')).not.toHaveValue('A')\n      await expect(page.locator('#handle')).not.toHaveValue('B')\n      await expect(page.locator('#remember')).not.toBeChecked()\n      await expect(page.locator('#untracked')).not.toHaveValue('C')\n    })\n\n    test('does not remember form errors as of default', async ({ page }) => {\n      await page.goto('remember/form-helper/default')\n\n      await page.fill('#name', 'A')\n      await page.fill('#handle', 'B')\n      await page.check('#remember')\n      await page.fill('#untracked', 'C')\n\n      await page.waitForSelector('.name_error', { state: 'detached' })\n      await page.waitForSelector('.handle_error', { state: 'detached' })\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n\n      await page.getByRole('button', { name: 'Submit form' }).click()\n\n      await expect(page.getByText('Some name error')).toBeVisible()\n      await expect(page.getByText('The Handle was invalid')).toBeVisible()\n      await expect(page.locator('.remember_error')).not.toBeVisible()\n\n      await page.getByRole('link', { name: 'Navigate away' }).click()\n\n      await shouldBeDumpPage(page, 'get')\n\n      await page.goBack()\n\n      await expect(page).toHaveURL('remember/form-helper/default')\n\n      await expect(page.locator('#name')).not.toHaveValue('A')\n      await expect(page.locator('#handle')).not.toHaveValue('B')\n      await expect(page.locator('#remember')).not.toBeChecked()\n      await expect(page.locator('#untracked')).not.toHaveValue('C')\n      await expect(page.locator('.name_error')).not.toBeVisible()\n      await expect(page.locator('.handle_error')).not.toBeVisible()\n      await expect(page.locator('.remember_error')).not.toBeVisible()\n    })\n\n    test('remembers form data when tracked', async ({ page }) => {\n      await page.goto('remember/form-helper/remember')\n\n      await page.fill('#name', 'A')\n      await page.fill('#handle', 'B')\n      await page.check('#remember')\n      await page.fill('#untracked', 'C')\n\n      await page.getByRole('link', { name: 'Navigate away' }).click()\n\n      await shouldBeDumpPage(page, 'get')\n\n      await page.goBack()\n\n      await expect(page).toHaveURL('remember/form-helper/remember')\n\n      await expect(page.locator('#name')).toHaveValue('A')\n      await expect(page.locator('#handle')).toHaveValue('B')\n      await expect(page.locator('#remember')).toBeChecked()\n      await expect(page.locator('#untracked')).not.toHaveValue('C')\n\n      // Try again with updated values\n      await page.fill('#name', 'D')\n      await page.fill('#handle', 'E')\n      await page.uncheck('#remember')\n      await page.fill('#untracked', 'F')\n\n      await page.getByRole('link', { name: 'Navigate away' }).click()\n\n      await shouldBeDumpPage(page, 'get')\n\n      await page.goBack()\n\n      await expect(page).toHaveURL('remember/form-helper/remember')\n\n      await expect(page.locator('#name')).toHaveValue('D')\n      await expect(page.locator('#handle')).toHaveValue('E')\n      await expect(page.locator('#remember')).not.toBeChecked()\n      await expect(page.locator('#untracked')).not.toHaveValue('F')\n    })\n\n    test('remembers form errors when tracked', async ({ page }) => {\n      await page.goto('remember/form-helper/remember')\n\n      await page.fill('#name', 'A')\n      await page.fill('#handle', 'B')\n      await page.check('#remember')\n      await page.fill('#untracked', 'C')\n      await page.waitForSelector('.name_error', { state: 'detached' })\n      await page.waitForSelector('.handle_error', { state: 'detached' })\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n\n      await page.getByRole('button', { name: 'Submit form' }).click()\n\n      await expect(page.getByText('Some name error')).toBeVisible()\n      await expect(page.getByText('The Handle was invalid')).toBeVisible()\n      await expect(page.locator('.remember_error')).not.toBeVisible()\n\n      await page.getByRole('link', { name: 'Navigate away' }).click()\n\n      await shouldBeDumpPage(page, 'get')\n\n      await page.goBack()\n\n      await expect(page).toHaveURL('remember/form-helper/remember')\n\n      await expect(page.locator('#name')).toHaveValue('A')\n      await expect(page.locator('#handle')).toHaveValue('B')\n      await expect(page.locator('#remember')).toBeChecked()\n      await expect(page.locator('#untracked')).not.toHaveValue('C')\n      await expect(page.locator('.name_error')).toBeVisible()\n      await expect(page.locator('.handle_error')).toBeVisible()\n      await expect(page.locator('.remember_error')).not.toBeVisible()\n\n      // Try again with updated values\n      await page.fill('#name', 'D')\n      await page.fill('#handle', 'E')\n      await page.uncheck('#remember')\n      await page.fill('#untracked', 'F')\n\n      await page.getByRole('link', { name: 'Navigate away' }).click()\n\n      await shouldBeDumpPage(page, 'get')\n\n      await page.goBack()\n\n      await expect(page).toHaveURL('remember/form-helper/remember')\n\n      await expect(page.locator('#name')).toHaveValue('D')\n      await expect(page.locator('#handle')).toHaveValue('E')\n      await expect(page.locator('#remember')).not.toBeChecked()\n      await expect(page.locator('#untracked')).not.toHaveValue('F')\n      await expect(page.locator('.name_error')).toBeVisible()\n      await expect(page.locator('.handle_error')).toBeVisible()\n      await expect(page.locator('.remember_error')).not.toBeVisible()\n    })\n\n    test('remembers the last state of a form when tracked', async ({ page }) => {\n      await page.goto('remember/form-helper/remember')\n\n      await page.fill('#name', 'A')\n      await page.fill('#handle', 'B')\n      await page.check('#remember')\n      await page.fill('#untracked', 'C')\n      await page.waitForSelector('.name_error', { state: 'detached' })\n      await page.waitForSelector('.handle_error', { state: 'detached' })\n      await page.waitForSelector('.remember_error', { state: 'detached' })\n\n      await page.getByRole('button', { name: 'Submit form' }).click()\n\n      await expect(page.locator('#name')).toHaveValue('A')\n      await expect(page.locator('#handle')).toHaveValue('B')\n      await expect(page.locator('#remember')).toBeChecked()\n      await expect(page.locator('#untracked')).toHaveValue('C')\n\n      await expect(page.getByText('Some name error')).toBeVisible()\n      await expect(page.getByText('The Handle was invalid')).toBeVisible()\n      await expect(page.locator('.remember_error')).not.toBeVisible()\n\n      await page.getByRole('button', { name: 'Reset one field & error' }).click()\n\n      await expect(page.locator('#name')).toHaveValue('A')\n      await expect(page.locator('#handle')).toHaveValue('example')\n      await expect(page.locator('#remember')).toBeChecked()\n      await expect(page.locator('#untracked')).toHaveValue('C')\n\n      await expect(page.locator('.name_error')).not.toBeVisible()\n      await expect(page.locator('.handle_error')).toBeVisible()\n      await expect(page.locator('.remember_error')).not.toBeVisible()\n\n      await page.getByRole('link', { name: 'Navigate away' }).click()\n\n      await shouldBeDumpPage(page, 'get')\n\n      await page.goBack()\n\n      await expect(page).toHaveURL('remember/form-helper/remember')\n\n      await expect(page.locator('#name')).toHaveValue('A')\n      await expect(page.locator('#handle')).toHaveValue('example')\n      await expect(page.locator('#remember')).toBeChecked()\n      await expect(page.locator('#untracked')).not.toHaveValue('C') // Untracked, so now reset (page state was lost)\n      await expect(page.locator('.name_error')).not.toBeVisible()\n      await expect(page.locator('.handle_error')).toBeVisible()\n      await expect(page.locator('.remember_error')).not.toBeVisible()\n    })\n\n    test('it excludes fields via dontRemember', async ({ page }) => {\n      await page.goto('remember/form-helper/password')\n\n      await page.fill('#username', 'A')\n      await page.fill('#password', 'B')\n\n      await page.getByRole('link', { name: 'Navigate away' }).click()\n\n      await shouldBeDumpPage(page, 'get')\n\n      await page.goBack()\n\n      await expect(page).toHaveURL('remember/form-helper/password')\n\n      await expect(page.locator('#username')).toHaveValue('A')\n      await expect(page.locator('#password')).toHaveValue('')\n    })\n  })\n\n  test('restore without types', async ({ page }) => {\n    await page.goto('remember/router')\n\n    await expect(page.getByText('Foo: -')).toBeVisible()\n    await expect(page.getByText('Bar: 0')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Remember' }).click()\n    await page.waitForTimeout(100) // Wait for remember to complete\n    await page.getByRole('button', { name: 'Restore', exact: true }).click()\n\n    await expect(page.getByText('Foo: foo')).toBeVisible()\n    await expect(page.getByText('Bar: 42')).toBeVisible()\n  })\n\n  test('restore with types', async ({ page }) => {\n    await page.goto('remember/router')\n\n    await expect(page.getByText('Foo: -')).toBeVisible()\n    await expect(page.getByText('Bar: 0')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Remember' }).click()\n    await page.waitForTimeout(100) // Wait for remember to complete\n    await page.getByRole('button', { name: 'Restore Typed' }).click()\n\n    await expect(page.getByText('Foo: foo')).toBeVisible()\n    await expect(page.getByText('Bar: 42')).toBeVisible()\n  })\n})\n"
  },
  {
    "path": "tests/scroll-smooth.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport { pageLoads } from './support'\n\ntest.describe('scroll-smooth', () => {\n  test.beforeEach(async ({ page }) => {\n    pageLoads.watch(page)\n  })\n\n  test('it resets scroll position when navigating from a long page to a short page with scroll-smooth CSS', async ({\n    page,\n  }) => {\n    // Start on the long page\n    await page.goto('/scroll-smooth/long')\n    await expect(page.getByRole('heading', { name: 'Long Page' })).toBeVisible()\n\n    // Scroll to the bottom of the page (use instant to avoid smooth scroll delay)\n    await page.evaluate(() => window.scrollTo({ top: document.body.scrollHeight, behavior: 'instant' }))\n    await page.waitForTimeout(100)\n\n    // Verify we scrolled down\n    const scrollYBeforeNavigation = await page.evaluate(() => window.scrollY)\n    expect(scrollYBeforeNavigation).toBeGreaterThan(500)\n\n    // Click the link to go to the short page\n    await page.getByRole('link', { name: 'Go to Short Page' }).click()\n    await expect(page.getByRole('heading', { name: 'Short Page' })).toBeVisible()\n\n    // Wait for smooth scroll animation to complete\n    await page.waitForTimeout(500)\n\n    // Verify scroll position was reset to top (allow small tolerance for smooth scroll)\n    const scrollYAfterNavigation = await page.evaluate(() => window.scrollY)\n    expect(scrollYAfterNavigation).toBeLessThan(10)\n  })\n\n  test('it resets scroll position when navigating from a short page to a long page with scroll-smooth CSS', async ({\n    page,\n  }) => {\n    // Start on the short page\n    await page.goto('/scroll-smooth/short')\n    await expect(page.getByRole('heading', { name: 'Short Page' })).toBeVisible()\n\n    // Click the link to go to the long page\n    await page.getByRole('link', { name: 'Go to Long Page' }).click()\n    await expect(page.getByRole('heading', { name: 'Long Page' })).toBeVisible()\n\n    // Wait for smooth scroll animation to complete\n    await page.waitForTimeout(500)\n\n    // Verify scroll position is at top (allow small tolerance for smooth scroll)\n    const scrollYAfterNavigation = await page.evaluate(() => window.scrollY)\n    expect(scrollYAfterNavigation).toBeLessThan(10)\n  })\n})\n"
  },
  {
    "path": "tests/ssr.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport { consoleMessages, pageLoads } from './support'\n\nconst SSR_SERVER_PORT = 13714\n\ntest.describe('SSR', () => {\n  test.describe('initial page load', () => {\n    test('renders HTML with props on the server', async ({ page }) => {\n      const response = await page.request.get('/ssr/page1')\n      const html = await response.text()\n\n      // Verify server-rendered content (using regex to handle React's comment nodes)\n      expect(html).toContain('data-page=')\n      expect(html).toMatch(/Name:.*John Doe/)\n      expect(html).toMatch(/Email:.*john@example\\.com/)\n      expect(html).toContain('Item 1')\n      expect(html).toContain('Item 2')\n      expect(html).toContain('Item 3')\n      expect(html).toMatch(/Count:.*42/)\n    })\n\n    test('hydrates correctly after initial SSR load', async ({ page }) => {\n      consoleMessages.listen(page)\n\n      await page.goto('/ssr/page1')\n\n      await expect(page.getByTestId('ssr-title')).toHaveText('SSR Page 1')\n      await expect(page.getByTestId('user-name')).toHaveText('Name: John Doe')\n      await expect(page.getByTestId('count')).toHaveText('Count: 42')\n\n      expect(consoleMessages.errors).toHaveLength(0)\n    })\n  })\n\n  test('embeds page data in a script element instead of data-page attribute', async ({ page }) => {\n    const response = await page.request.get('/ssr/page-with-script-element')\n    const html = await response.text()\n\n    expect(html).toContain('data-page=\"app\"')\n    expect(html).toContain('<script data-page=\"app\" type=\"application/json\">')\n    expect(html).toContain('Hello from script element! Escape <\\\\/script>.')\n\n    await page.goto('/ssr/page-with-script-element')\n    const scriptContent = await page.locator('script[data-page=\"app\"]').textContent()\n    expect(JSON.parse(scriptContent || '')).toMatchObject({\n      component: 'SSR/PageWithScriptElement',\n      props: {\n        message: 'Hello from script element! Escape </script>.',\n      },\n    })\n  })\n\n  test.describe('client-side navigation', () => {\n    test('navigates without full page reload after SSR', async ({ page }) => {\n      pageLoads.watch(page)\n\n      await page.goto('/ssr/page1')\n      await expect(page.getByTestId('ssr-title')).toHaveText('SSR Page 1')\n\n      await page.getByTestId('navigate-link').click()\n\n      await expect(page.getByTestId('ssr-title')).toHaveText('SSR Page 2')\n      await expect(page.getByTestId('navigated-status')).toHaveText('Navigated: true')\n      expect(pageLoads.count).toBe(1)\n    })\n\n    test('can navigate back and forth after SSR', async ({ page, request }) => {\n      pageLoads.watch(page)\n\n      await page.goto('/ssr/page1')\n      await expect(page.getByTestId('ssr-title')).toHaveText('SSR Page 1')\n\n      await page.getByTestId('navigate-link').click()\n      await expect(page.getByTestId('ssr-title')).toHaveText('SSR Page 2')\n\n      await page.getByTestId('back-link').click()\n      await expect(page.getByTestId('ssr-title')).toHaveText('SSR Page 1')\n\n      expect(pageLoads.count).toBe(1)\n\n      // Verify SSR server is still healthy\n      const response = await request.get(`http://localhost:${SSR_SERVER_PORT}/health`)\n      const health = await response.json()\n      expect(health.status).toBe('OK')\n    })\n  })\n})\n"
  },
  {
    "path": "tests/support.ts",
    "content": "import { expect, Page, Request, Response } from '@playwright/test'\n\nexport const clickAndWaitForResponse = async (\n  page: Page,\n  buttonText: string,\n  url: string | null = null,\n  element: 'link' | 'button' = 'link',\n) => {\n  const responsePromise = page.waitForResponse(url ?? page.url())\n  await page.getByRole(element, { exact: true, name: buttonText }).click()\n  return await responsePromise\n}\n\nexport const pageLoads = {\n  count: 0,\n\n  watch(page: Page, maxLoads = 1) {\n    this.count = 0\n\n    page.on('load', () => {\n      // Ignore load events from about:blank (Firefox fires these, Chromium doesn't)\n      if (page.url() === 'about:blank') {\n        return\n      }\n\n      this.count++\n\n      if (this.count > maxLoads) {\n        throw new Error('The page loaded more than once')\n      }\n    })\n  },\n}\n\nexport const consoleMessages = {\n  errors: [] as string[],\n  messages: [] as string[],\n\n  listen(page: Page) {\n    this.errors = []\n    this.messages = []\n    page.on('console', (msg) => this.messages.push(msg.text()))\n    page.on('pageerror', (error: Error) => this.errors.push(error.message))\n  },\n}\n\nexport const requests = {\n  requests: [] as Request[],\n  finished: [] as Request[],\n  failed: [] as Request[],\n  responses: [] as Response[],\n  _handlers: {} as Record<string, { page: Page; handler: (...args: any[]) => void }>,\n\n  _replaceListener(page: Page, event: string, handler: (...args: any[]) => void) {\n    const existing = this._handlers[event]\n\n    if (existing) {\n      existing.page.off(event, existing.handler)\n    }\n\n    this._handlers[event] = { page, handler }\n    page.on(event, handler)\n  },\n\n  listen(page: Page) {\n    this.requests = []\n    this._replaceListener(page, 'request', (request: Request) => this.requests.push(request))\n  },\n\n  listenForFinished(page: Page) {\n    this.finished = []\n    this._replaceListener(page, 'requestfinished', (request: Request) => this.finished.push(request))\n  },\n\n  listenForFailed(page: Page) {\n    this.failed = []\n    this._replaceListener(page, 'requestfailed', (request: Request) => this.failed.push(request))\n  },\n\n  listenForResponses(page: Page) {\n    this.responses = []\n    this._replaceListener(page, 'response', (data: Response) => this.responses.push(data))\n  },\n}\n\nexport const shouldBeDumpPage = async (page: Page, method: 'get' | 'post' | 'patch' | 'put' | 'delete') => {\n  await expect(page).toHaveURL(new RegExp(`dump/${method}`))\n  // Wait for Vue/React/Svelte to mount and set the dump (Firefox may need this)\n  await page.waitForFunction(() => window._inertia_request_dump !== undefined)\n  // @ts-ignore\n  const dump = await page.evaluate(() => window._inertia_request_dump)\n\n  return dump\n}\n\nexport const scrollElementTo = async (page: Page, promise: Promise<void>) => {\n  await promise\n  // Wait for scroll listener debounce\n  await page.waitForTimeout(100)\n}\n\nexport const gotoPageAndWaitForContent = async (page: Page, url: string) => {\n  await page.goto(url, { waitUntil: 'domcontentloaded' })\n}\n\nexport const reloadAndWaitForContent = async (page: Page) => {\n  await page.reload({ waitUntil: 'domcontentloaded' })\n}\n\n// Wait for scroll to complete after navigating to a fragment\nexport const waitForFragmentScroll = async (page: Page) => {\n  // Give time for the scroll animation to complete\n  await page.waitForTimeout(200)\n}\n"
  },
  {
    "path": "tests/svelte.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport { consoleMessages } from './support'\n\ntest.beforeEach(async ({ page }) => {\n  test.skip(process.env.PACKAGE !== 'svelte', 'Svelte-only test')\n})\n\ntest('props and page store are in sync', async ({ page }) => {\n  consoleMessages.listen(page)\n\n  await page.goto('/svelte/props-and-page-store')\n\n  await expect(page.getByText('foo prop is default')).toBeVisible()\n  await expect(page.getByText('$page.props.foo is default')).toBeVisible()\n  await expect(page.getByText('pageProps.foo is default')).toBeVisible()\n  await expect(page.getByText('$sveltePage.props.foo is default')).toBeVisible()\n  await expect(consoleMessages.messages).toHaveLength(11)\n  await expect(consoleMessages.messages[0]).toBe('[script] foo prop is default')\n  await expect(consoleMessages.messages[1]).toBe('[script] $page.props.foo is default')\n  await expect(consoleMessages.messages[2]).toBe('[script] $sveltePage.props.foo is default')\n  await expect(consoleMessages.messages[3]).toBe('[reactive expression] foo prop is default')\n  await expect(consoleMessages.messages[4]).toBe('[reactive expression] $page.props.foo is default')\n  await expect(consoleMessages.messages[5]).toBe('[reactive expression] $sveltePage.props.foo is default')\n  await expect(consoleMessages.messages[6]).toBe('[onMount] foo prop is default')\n  await expect(consoleMessages.messages[7]).toBe('[onMount] $page.props.foo is default')\n  await expect(consoleMessages.messages[8]).toBe('[onMount] $sveltePage.props.foo is default')\n  await expect(consoleMessages.messages[9]).toBe('[reactive expression] $page.props.foo is default')\n  await expect(consoleMessages.messages[10]).toBe('[reactive expression] $sveltePage.props.foo is default')\n  await expect(await page.locator('#input').inputValue()).toEqual('default')\n\n  consoleMessages.messages = []\n  await page.getByRole('link', { name: 'Bar' }).click()\n\n  await expect(page.getByText('foo prop is bar')).toBeVisible()\n  await expect(page.getByText('$page.props.foo is bar')).toBeVisible()\n  await expect(page.getByText('pageProps.foo is bar')).toBeVisible()\n  await expect(page.getByText('$sveltePage.props.foo is bar')).toBeVisible()\n  await expect(consoleMessages.messages).toHaveLength(11)\n  await expect(consoleMessages.messages[0]).toBe('[reactive expression] $page.props.foo is bar')\n  await expect(consoleMessages.messages[1]).toBe('[reactive expression] $sveltePage.props.foo is bar')\n  await expect(consoleMessages.messages[2]).toBe('[script] foo prop is bar')\n  await expect(consoleMessages.messages[3]).toBe('[script] $page.props.foo is bar')\n  await expect(consoleMessages.messages[4]).toBe('[script] $sveltePage.props.foo is bar')\n  await expect(consoleMessages.messages[5]).toBe('[reactive expression] foo prop is bar')\n  await expect(consoleMessages.messages[6]).toBe('[reactive expression] $page.props.foo is bar')\n  await expect(consoleMessages.messages[7]).toBe('[reactive expression] $sveltePage.props.foo is bar')\n  await expect(consoleMessages.messages[8]).toBe('[onMount] foo prop is bar')\n  await expect(consoleMessages.messages[9]).toBe('[onMount] $page.props.foo is bar')\n  await expect(consoleMessages.messages[10]).toBe('[onMount] $sveltePage.props.foo is bar')\n  await expect(await page.locator('#input').inputValue()).toEqual('bar')\n\n  consoleMessages.messages = []\n  await page.getByRole('link', { name: 'Baz' }).click()\n\n  await expect(page.getByText('foo prop is baz')).toBeVisible()\n  await expect(page.getByText('$page.props.foo is baz')).toBeVisible()\n  await expect(page.getByText('pageProps.foo is baz')).toBeVisible()\n  await expect(page.getByText('$sveltePage.props.foo is baz')).toBeVisible()\n  await expect(consoleMessages.messages).toHaveLength(11)\n  await expect(consoleMessages.messages[0]).toBe('[reactive expression] $page.props.foo is baz')\n  await expect(consoleMessages.messages[1]).toBe('[reactive expression] $sveltePage.props.foo is baz')\n  await expect(consoleMessages.messages[2]).toBe('[script] foo prop is baz')\n  await expect(consoleMessages.messages[3]).toBe('[script] $page.props.foo is baz')\n  await expect(consoleMessages.messages[4]).toBe('[script] $sveltePage.props.foo is baz')\n  await expect(consoleMessages.messages[5]).toBe('[reactive expression] foo prop is baz')\n  await expect(consoleMessages.messages[6]).toBe('[reactive expression] $page.props.foo is baz')\n  await expect(consoleMessages.messages[7]).toBe('[reactive expression] $sveltePage.props.foo is baz')\n  await expect(consoleMessages.messages[8]).toBe('[onMount] foo prop is baz')\n  await expect(consoleMessages.messages[9]).toBe('[onMount] $page.props.foo is baz')\n  await expect(consoleMessages.messages[10]).toBe('[onMount] $sveltePage.props.foo is baz')\n  await expect(await page.locator('#input').inputValue()).toEqual('baz')\n\n  consoleMessages.messages = []\n\n  await page.getByRole('link', { name: 'Home' }).click()\n  await page.waitForURL('/')\n\n  await page.goBack()\n  await page.waitForURL('/svelte/props-and-page-store?foo=baz')\n\n  await expect(page.getByText('foo prop is baz')).toBeVisible()\n  await expect(page.getByText('$page.props.foo is baz')).toBeVisible()\n  await expect(page.getByText('pageProps.foo is baz')).toBeVisible()\n  await expect(page.getByText('$sveltePage.props.foo is baz')).toBeVisible()\n  await expect(consoleMessages.messages).toHaveLength(11)\n  await expect(consoleMessages.messages[0]).toBe('[reactive expression] $page.props.foo is undefined')\n  await expect(consoleMessages.messages[1]).toBe('[reactive expression] $sveltePage.props.foo is undefined')\n  await expect(consoleMessages.messages[2]).toBe('[script] foo prop is baz')\n  await expect(consoleMessages.messages[3]).toBe('[script] $page.props.foo is baz')\n  await expect(consoleMessages.messages[4]).toBe('[script] $sveltePage.props.foo is baz')\n  await expect(consoleMessages.messages[5]).toBe('[reactive expression] foo prop is baz')\n  await expect(consoleMessages.messages[6]).toBe('[reactive expression] $page.props.foo is baz')\n  await expect(consoleMessages.messages[7]).toBe('[reactive expression] $sveltePage.props.foo is baz')\n  await expect(consoleMessages.messages[8]).toBe('[onMount] foo prop is baz')\n  await expect(consoleMessages.messages[9]).toBe('[onMount] $page.props.foo is baz')\n  await expect(consoleMessages.messages[10]).toBe('[onMount] $sveltePage.props.foo is baz')\n})\n"
  },
  {
    "path": "tests/view-transitions.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport { consoleMessages } from './support'\n\ntest.describe('View Transitions', () => {\n  test.skip(({ browserName }) => browserName === 'firefox', 'Firefox does not support View Transitions API in CI')\n\n  test('navigates with boolean view transition', async ({ page }) => {\n    await page.goto('/view-transition/page-a')\n\n    await expect(page.getByText('Page A - View Transition Test')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Transition with boolean' }).click()\n\n    await expect(page).toHaveURL('/view-transition/page-b')\n    await expect(page.getByText('Page B - View Transition Test')).toBeVisible()\n  })\n\n  test('calls viewTransition callbacks when using callback function', async ({ page }) => {\n    consoleMessages.listen(page)\n\n    await page.goto('/view-transition/page-a')\n\n    await expect(page.getByText('Page A - View Transition Test')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Transition with callback' }).click()\n\n    await expect(page).toHaveURL('/view-transition/page-b')\n    await expect(page.getByText('Page B - View Transition Test')).toBeVisible()\n\n    await expect.poll(() => consoleMessages.messages).toEqual(['updateCallbackDone', 'ready', 'finished'])\n  })\n\n  test('calls viewTransition callbacks on Link component with callback function', async ({ page }) => {\n    consoleMessages.listen(page)\n\n    await page.goto('/view-transition/page-a')\n\n    await expect(page.getByText('Page A - View Transition Test')).toBeVisible()\n\n    await page.getByRole('link', { name: 'Link to Page B' }).click()\n\n    await expect(page).toHaveURL('/view-transition/page-b')\n    await expect(page.getByText('Page B - View Transition Test')).toBeVisible()\n\n    await expect.poll(() => consoleMessages.messages).toEqual(['updateCallbackDone', 'ready', 'finished'])\n  })\n\n  test('calls viewTransition callbacks on client-side visit with callback function', async ({ page }) => {\n    consoleMessages.listen(page)\n\n    await page.goto('/view-transition/page-a')\n\n    await expect(page.getByText('Page A - View Transition Test')).toBeVisible()\n\n    await page.getByRole('button', { name: 'Client-side replace' }).click()\n\n    await expect(page).toHaveURL('/view-transition/page-b')\n    await expect(page.getByText('Page B - View Transition Test')).toBeVisible()\n\n    await expect.poll(() => consoleMessages.messages).toEqual(['updateCallbackDone', 'ready', 'finished'])\n  })\n\n  test('does not use view transition when same page returns with validation errors', async ({ page }) => {\n    consoleMessages.listen(page)\n\n    await page.goto('/view-transition/form-errors')\n    await page.getByRole('button', { name: 'Submit with View Transition' }).click()\n    await expect(page.getByText('The name field is required.')).toBeVisible()\n\n    await page.waitForTimeout(500)\n\n    await expect(consoleMessages.messages).toEqual([])\n  })\n\n  test('does not throw InvalidStateError when document visibility is hidden during view transition', async ({\n    page,\n  }) => {\n    consoleMessages.listen(page)\n\n    await page.goto('/view-transition/page-a')\n    await expect(page.getByText('Page A - View Transition Test')).toBeVisible()\n\n    await page.evaluate(() => {\n      Object.defineProperty(document, 'visibilityState', { value: 'hidden', configurable: true })\n    })\n\n    await page.getByRole('button', { name: 'Transition with boolean' }).click()\n\n    await expect(page).toHaveURL('/view-transition/page-b')\n    await expect(page.getByText('Page B - View Transition Test')).toBeVisible()\n    await expect(consoleMessages.errors).toEqual([])\n  })\n})\n"
  },
  {
    "path": "tests/when-visible.spec.ts",
    "content": "import { expect, test } from '@playwright/test'\nimport { pageLoads, requests } from './support'\n\ntest('it will wait to fire the reload until element is visible', async ({ page }) => {\n  await page.goto('/when-visible')\n  requests.listen(page)\n\n  await page.evaluate(() => (window as any).scrollTo(0, 1000))\n  await expect(requests.requests).toHaveLength(0)\n\n  await page.evaluate(() => (window as any).scrollTo(0, 3000))\n  await expect(requests.requests).toHaveLength(0)\n\n  await page.evaluate(() => (window as any).scrollTo(0, 5000))\n  await expect(page.getByText('Loading first one...')).toBeVisible()\n  await expect(page.getByText('First one is visible!')).not.toBeVisible()\n  await page.waitForResponse(page.url())\n  await expect(page.getByText('Loading first one...')).not.toBeVisible()\n  await expect(page.getByText('First one is visible!')).toBeVisible()\n\n  // Scroll back up and then back down, make sure we don't re-request\n  await page.evaluate(() => (window as any).scrollTo(0, 3000))\n  await expect(requests.requests).toHaveLength(1)\n\n  await page.evaluate(() => (window as any).scrollTo(0, 5000))\n  await expect(requests.requests).toHaveLength(1)\n  await expect(page.getByText('First one is visible!')).toBeVisible()\n\n  requests.listen(page)\n\n  await page.evaluate(() => (window as any).scrollTo(0, 6000))\n  await expect(requests.requests).toHaveLength(0)\n\n  // This one has a buffer of 1000\n  await page.evaluate(() => (window as any).scrollTo(0, 9000))\n  await expect(page.getByText('Loading second one...')).toBeVisible()\n  await expect(page.getByText('Second one is visible!')).not.toBeVisible()\n  await page.waitForResponse(page.url())\n  await expect(page.getByText('Loading second one...')).not.toBeVisible()\n  await expect(page.getByText('Second one is visible!')).toBeVisible()\n\n  // This one should trigger every time it's visible\n  await page.evaluate(() => (window as any).scrollTo(0, 15_000))\n  await expect(page.getByText('Loading third one...')).toBeVisible()\n  await expect(page.getByText('Third one is visible!')).not.toBeVisible()\n  await page.waitForResponse(page.url())\n  await expect(page.getByText('Loading third one...')).not.toBeVisible()\n  await expect(page.getByText('Third one is visible!')).toBeVisible()\n\n  // Now scroll up and down to re-trigger it\n  await page.evaluate(() => (window as any).scrollTo(0, 13_000))\n  await page.waitForFunction(() => document.documentElement.scrollTop < 14000, { timeout: 2000 })\n  await page.waitForTimeout(200)\n\n  let responsePromise = page.waitForResponse(page.url())\n  await page.evaluate(() => (window as any).scrollTo(0, 15_000))\n  await expect(page.getByText('Third one is visible!')).toBeVisible()\n  await responsePromise\n\n  await page.evaluate(() => (window as any).scrollTo(0, 13_000))\n  await page.waitForFunction(() => document.documentElement.scrollTop < 14000, { timeout: 2000 })\n  await page.waitForTimeout(200)\n\n  responsePromise = page.waitForResponse(page.url())\n  await page.evaluate(() => (window as any).scrollTo(0, 15_000))\n  await expect(page.getByText('Third one is visible!')).toBeVisible()\n  await responsePromise\n\n  await page.evaluate(() => (window as any).scrollTo(0, 20_000))\n  await expect(page.getByText('Loading fourth one...')).toBeVisible()\n  await page.waitForResponse(page.url())\n  await expect(page.getByText('Loading fourth one...')).not.toBeVisible()\n\n  await page.evaluate(() => (window as any).scrollTo(0, 26_000))\n  await expect(page.getByText('Loading fifth one...')).toBeVisible()\n  await page.waitForResponse('/when-visible?count=0')\n  await expect(page.getByText('Loading fifth one...')).not.toBeVisible()\n  await expect(page.getByText('Count is now 1')).toBeVisible()\n\n  // Now scroll up and down to re-trigger it\n  // Need to scroll far enough that the element is truly out of viewport\n  await page.evaluate(() => (window as any).scrollTo(0, 10_000))\n  await page.waitForFunction(() => document.documentElement.scrollTop < 15000, { timeout: 2000 })\n  // Give IntersectionObserver time to process the visibility change\n  await page.waitForTimeout(200)\n\n  await page.evaluate(() => (window as any).scrollTo(0, 26_000))\n  await expect(page.getByText('Count is now 1')).toBeVisible()\n  await page.waitForResponse('/when-visible?count=1')\n  await expect(page.getByText('Count is now 2')).toBeVisible()\n})\n\ntest('it will reload again when the prop value is set to undefined (e.g. page reload)', async ({ page }) => {\n  await page.goto('/when-visible-reload')\n  requests.listen(page)\n\n  // Initial load - lazyData should be missing\n  await expect(page.getByText('This is lazy loaded data!')).not.toBeVisible()\n\n  // Scroll to trigger the WhenVisible component\n  await page.evaluate(() => (window as any).scrollTo(0, 3000))\n  await expect(page.getByText('Loading lazy data...')).toBeVisible()\n\n  // Wait for lazy data to load\n  await page.waitForResponse(page.url())\n  await expect(page.getByText('Loading lazy data...')).not.toBeVisible()\n  await expect(page.getByText('This is lazy loaded data!')).toBeVisible()\n\n  await page.evaluate(() => (window as any).scrollTo(0, 0))\n\n  // Click the reload button to trigger the issue\n  await page.getByRole('button', { name: 'Reload Page' }).click()\n\n  // Lazily loaded data should be missing again after reload\n  await expect(page.getByText('Loading lazy data...')).toBeVisible()\n  await expect(page.getByText('This is lazy loaded data!')).not.toBeVisible()\n\n  // Scroll to trigger the WhenVisible component again\n  await page.evaluate(() => (window as any).scrollTo(0, 3000))\n\n  // Wait for lazy data to load again\n  await page.waitForResponse(page.url())\n  await expect(page.getByText('Loading lazy data...')).not.toBeVisible()\n  await expect(page.getByText('This is lazy loaded data!')).toBeVisible()\n})\n\ntest('it handles array props correctly with router.reload()', async ({ page }) => {\n  await page.goto('/when-visible-array-reload')\n  requests.listen(page)\n\n  // Initial load - array data should be missing\n  await expect(page.getByText('First lazy data loaded!')).not.toBeVisible()\n  await expect(page.getByText('Second lazy data loaded!')).not.toBeVisible()\n\n  // Scroll to trigger the WhenVisible component\n  await page.evaluate(() => (window as any).scrollTo(0, 3000))\n  await expect(page.getByText('Loading array data...')).toBeVisible()\n\n  // Wait for array data to load\n  await page.waitForResponse(page.url())\n  await expect(page.getByText('Loading array data...')).not.toBeVisible()\n  await expect(page.getByText('First lazy data loaded!')).toBeVisible()\n  await expect(page.getByText('Second lazy data loaded!')).toBeVisible()\n\n  await page.evaluate(() => (window as any).scrollTo(0, 0))\n\n  // Click the reload button to trigger the issue\n  await page.getByRole('button', { name: 'Reload Page' }).click()\n\n  // Array data should be missing again after reload\n  await expect(page.getByText('Loading array data...')).toBeVisible()\n  await expect(page.getByText('First lazy data loaded!')).not.toBeVisible()\n  await expect(page.getByText('Second lazy data loaded!')).not.toBeVisible()\n\n  // Scroll to trigger the WhenVisible component again\n  await page.evaluate(() => (window as any).scrollTo(0, 3000))\n\n  // Wait for array data to load again\n  await page.waitForResponse(page.url())\n  await expect(page.getByText('Loading array data...')).not.toBeVisible()\n  await expect(page.getByText('First lazy data loaded!')).toBeVisible()\n  await expect(page.getByText('Second lazy data loaded!')).toBeVisible()\n})\n\ntest('it shows loaded content immediately when data exists from history (back button)', async ({ page }) => {\n  await page.goto('/when-visible-back-button')\n  pageLoads.watch(page)\n  requests.listen(page)\n\n  await expect(page.getByText('This is lazy loaded data!')).not.toBeVisible()\n\n  await page.evaluate(() => (window as any).scrollTo(0, 2000))\n  await expect(page.getByText('Loading lazy data...')).toBeVisible()\n  await page.waitForResponse(page.url())\n  await expect(page.getByText('Loading lazy data...')).not.toBeVisible()\n  await expect(page.getByText('This is lazy loaded data!', { exact: true })).toBeVisible()\n\n  // Navigate away and back\n  await page.evaluate(() => (window as any).scrollTo(0, 0))\n  await page.getByRole('link', { name: 'Navigate Away' }).click()\n  await page.waitForURL('/links/method')\n  await page.goBack()\n  await page.waitForURL('/when-visible-back-button')\n\n  // Data exists from history, should show immediately without making a request\n  requests.listen(page)\n  await expect(page.getByText('This is lazy loaded data!', { exact: true })).toBeVisible()\n  await expect(page.getByText('Loading lazy data...')).not.toBeVisible()\n  expect(requests.requests).toHaveLength(0)\n})\n\ntest('it re-triggers when always prop is set after back button navigation', async ({ page }) => {\n  await page.goto('/when-visible-back-button')\n  pageLoads.watch(page)\n\n  // Scroll to the always component and load data\n  await page.evaluate(() => (window as any).scrollTo(0, 4000))\n  await expect(page.getByText('Loading always data...')).toBeVisible()\n  await page.waitForResponse(page.url())\n  await expect(page.getByText('Always: This is lazy loaded data!')).toBeVisible()\n\n  // Navigate away and back\n  await page.evaluate(() => (window as any).scrollTo(0, 0))\n  await page.getByRole('link', { name: 'Navigate Away' }).click()\n  await page.waitForURL('/links/method')\n  await page.goBack()\n  await page.waitForURL('/when-visible-back-button')\n  await expect(page.getByText('Always: This is lazy loaded data!')).toBeVisible()\n\n  // Ensure we're scrolled to the top before scrolling down to re-trigger\n  // Firefox may restore scroll position after back navigation, so we need to wait and force scroll\n  await page.waitForTimeout(100)\n  await page.evaluate(() => {\n    window.scrollTo({ top: 0, left: 0, behavior: 'instant' })\n  })\n  await page.waitForTimeout(200)\n\n  // Scroll to trigger the always component again, should re-fetch\n  await page.evaluate(() => (window as any).scrollTo(0, 4000))\n  const response = await page.waitForResponse(\n    (res) =>\n      res.url().includes('/when-visible-back-button') &&\n      res.request().headers()['x-inertia-partial-data'] !== undefined,\n  )\n  expect(response.status()).toBe(200)\n})\n\ntest('it exposes fetching state to the default slot', async ({ page }) => {\n  await page.goto('/when-visible-fetching')\n\n  await page.evaluate(() => (window as any).scrollTo(0, 5000))\n  await expect(page.getByText('Loading lazy data...')).toBeVisible()\n  await expect(page.getByText('Lazy data loaded!')).not.toBeVisible()\n\n  await page.waitForResponse(page.url())\n  await page.evaluate(() => (window as any).scrollTo(0, 0))\n  await page.waitForTimeout(100)\n\n  await expect(page.getByText('Loading lazy data...')).not.toBeVisible()\n  await expect(page.getByText('Lazy data loaded!')).toBeVisible()\n  await expect(page.getByText('Fetching in background...')).not.toBeVisible()\n\n  // Scroll back to trigger re-fetch, content stays visible while fetching\n  await page.evaluate(() => (window as any).scrollTo(0, 5000))\n  await expect(page.getByText('Lazy data loaded!')).toBeVisible()\n  await expect(page.getByText('Fetching in background...')).toBeVisible()\n\n  await page.waitForResponse(page.url())\n  await page.evaluate(() => (window as any).scrollTo(0, 0))\n  await page.waitForTimeout(100)\n  await expect(page.getByText('Lazy data loaded!')).toBeVisible()\n  await expect(page.getByText('Fetching in background...')).not.toBeVisible()\n})\n\ntest('it merges data and params props', async ({ page }) => {\n  await page.goto('/when-visible-merge-params')\n\n  // Using only the data prop works as before\n  await page.evaluate(() => (window as any).scrollTo(0, 3000))\n  await expect(page.getByText('Loading data only...')).toBeVisible()\n  await page.waitForResponse(page.url())\n  await expect(page.getByText('Data only loaded: Data only success!')).toBeVisible()\n\n  // Using both data and params merges them - data sets 'only', params.data becomes query string\n  await page.evaluate(() => (window as any).scrollTo(0, 8000))\n  await expect(page.getByText('Loading merged...')).toBeVisible()\n  await page.waitForResponse((res) => res.url().includes('extra=from-params'))\n  await expect(page.getByText('Merged loaded: Merged success! extra=from-params')).toBeVisible()\n\n  // Other params options like preserveUrl are also passed through\n  await page.evaluate(() => (window as any).scrollTo(0, 13500))\n  await expect(page.getByText('Loading merged with callback...')).toBeVisible()\n  await page.waitForResponse((res) => res.url().includes('page=2'))\n  await expect(page.getByText('Merged with callback loaded: Merged with callback success! page=2')).toBeVisible()\n})\n\ntest('it does not trigger unneeded requests when params change while visible', async ({ page }) => {\n  await page.goto('/when-visible-params-update')\n\n  await page.evaluate(() => (window as any).scrollTo(0, 3000))\n  await expect(page.getByText('Loading lazy data...')).toBeVisible()\n  await page.waitForResponse((res) => res.url().includes('paramValue=initial'))\n  await expect(page.getByText('Data loaded: Loaded with paramValue=initial')).toBeVisible()\n  await page.waitForTimeout(100)\n\n  requests.listen(page)\n\n  await page.getByRole('button', { name: 'Update Param' }).click()\n  await expect(page.getByText('Current param: updated')).toBeVisible()\n  await page.waitForTimeout(100)\n\n  expect(requests.requests).toHaveLength(0)\n})\n"
  }
]