Full Code of connectrpc/connect-query-es for AI

main ef9eb4ec7611 cached
111 files
353.8 KB
122.2k tokens
87 symbols
1 requests
Download .txt
Showing preview only (386K chars total). Download the full file or copy to clipboard to get everything.
Repository: connectrpc/connect-query-es
Branch: main
Commit: ef9eb4ec7611
Files: 111
Total size: 353.8 KB

Directory structure:
gitextract_bg1etjgz/

├── .eslintrc.cjs
├── .gitattributes
├── .github/
│   ├── CODE_OF_CONDUCT.md
│   ├── CONTRIBUTING.md
│   ├── RELEASING.md
│   ├── dependabot.yaml
│   ├── release.yaml
│   └── workflows/
│       ├── add-to-project.yaml
│       ├── ci.yaml
│       ├── pr-title.yaml
│       ├── prepare-release.yml
│       └── publish-release.yml
├── .gitignore
├── .nvmrc
├── .vscode/
│   ├── extensions.json
│   └── settings.json
├── LICENSE
├── MAINTAINERS.md
├── README.md
├── SECURITY.md
├── assets/
│   ├── connect-query.ai
│   └── connect-query_dependency_graph.excalidraw
├── cspell.config.json
├── package.json
├── packages/
│   ├── connect-query/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── call-unary-method.test.ts
│   │   │   ├── index.ts
│   │   │   ├── test/
│   │   │   │   └── test-wrapper.tsx
│   │   │   ├── use-infinite-query.test.ts
│   │   │   ├── use-infinite-query.ts
│   │   │   ├── use-mutation.test.ts
│   │   │   ├── use-mutation.ts
│   │   │   ├── use-query.test.ts
│   │   │   ├── use-query.ts
│   │   │   ├── use-transport.test.tsx
│   │   │   └── use-transport.tsx
│   │   ├── tsconfig.build.json
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── connect-query-core/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── call-unary-method.ts
│   │   │   ├── connect-query-key.test.ts
│   │   │   ├── connect-query-key.ts
│   │   │   ├── create-infinite-query-options.test.ts
│   │   │   ├── create-infinite-query-options.ts
│   │   │   ├── create-query-options.test.ts
│   │   │   ├── create-query-options.ts
│   │   │   ├── index.ts
│   │   │   ├── message-key.test.ts
│   │   │   ├── message-key.ts
│   │   │   ├── page-param-key.ts
│   │   │   ├── structural-sharing.test.ts
│   │   │   ├── structural-sharing.ts
│   │   │   ├── transport-key.test.ts
│   │   │   ├── transport-key.ts
│   │   │   ├── utils.test.ts
│   │   │   └── utils.ts
│   │   ├── tsconfig.build.json
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── examples/
│   │   └── react/
│   │       └── basic/
│   │           ├── .gitignore
│   │           ├── buf.gen.yaml
│   │           ├── eliza.proto
│   │           ├── index.html
│   │           ├── package.json
│   │           ├── src/
│   │           │   ├── css.ts
│   │           │   ├── datum.tsx
│   │           │   ├── example.tsx
│   │           │   ├── gen/
│   │           │   │   ├── eliza-ElizaService_connectquery.ts
│   │           │   │   └── eliza_pb.ts
│   │           │   ├── index.css
│   │           │   ├── indicator.tsx
│   │           │   ├── main.test.tsx
│   │           │   ├── main.tsx
│   │           │   ├── page.tsx
│   │           │   └── vite-env.d.ts
│   │           ├── tsconfig.json
│   │           └── vite.config.ts
│   ├── protoc-gen-connect-query/
│   │   ├── .eslintignore
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── bin/
│   │   │   └── protoc-gen-connect-query
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── generateDts.ts
│   │   │   ├── generateTs.ts
│   │   │   ├── protoc-gen-connect-query-plugin.ts
│   │   │   └── utils.ts
│   │   └── tsconfig.json
│   └── test-utils/
│       ├── buf.gen.yaml
│       ├── package.json
│       ├── proto/
│       │   ├── bigint.proto
│       │   ├── eliza.proto
│       │   ├── list.proto
│       │   ├── proto2.proto
│       │   └── proto3.proto
│       ├── src/
│       │   ├── gen/
│       │   │   ├── bigint_pb.ts
│       │   │   ├── eliza_pb.ts
│       │   │   ├── list_pb.ts
│       │   │   ├── proto2_pb.ts
│       │   │   └── proto3_pb.ts
│       │   └── index.tsx
│       └── tsconfig.json
├── scripts/
│   ├── find-workspace-version.js
│   ├── gh-diffcheck.js
│   ├── release.js
│   ├── set-workspace-version.js
│   └── utils.js
├── tsconfig.base.json
└── turbo.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintrc.cjs
================================================
// Copyright 2021-2023 The Connect Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  root: true,
  ignorePatterns: ["packages/*/dist/**"],
  plugins: ["@typescript-eslint", "n", "import", "vitest"],
  // Rules and settings that do not require a non-default parser
  extends: ["eslint:recommended"],
  rules: {
    "no-console": "error",
    "import/no-cycle": "error",
    "import/no-duplicates": "error",
  },
  overrides: [
    {
      files: ["**/*.{ts,tsx,cts,mts}"],
      parser: "@typescript-eslint/parser",
      parserOptions: {
        project: true,
      },
      settings: {
        "import/resolver": {
          typescript: {
            project: "tsconfig.json",
          },
        },
      },
      extends: [
        "plugin:@typescript-eslint/recommended",
        "plugin:@typescript-eslint/recommended-requiring-type-checking",
        "plugin:import/recommended",
        "plugin:import/typescript",
      ],
      rules: {
        "@typescript-eslint/strict-boolean-expressions": "error",
        "@typescript-eslint/no-unnecessary-condition": "error",
        "@typescript-eslint/array-type": "off", // we use complex typings, where Array is actually more readable than T[]
        "@typescript-eslint/switch-exhaustiveness-check": [
          "error",
          {
            considerDefaultExhaustiveForUnions: true,
          },
        ],
        "@typescript-eslint/prefer-nullish-coalescing": "error",
        "@typescript-eslint/no-unnecessary-boolean-literal-compare": "error",
        "@typescript-eslint/no-invalid-void-type": "error",
        "@typescript-eslint/no-base-to-string": "error",
        "import/no-cycle": "error",
        "import/no-duplicates": "error",
      },
    },
    // For scripts and configurations, use Node.js rules
    {
      files: ["**/*.{js,mjs,cjs}"],
      parserOptions: {
        ecmaVersion: 13, // ES2022 - https://eslint.org/docs/latest/use/configure/language-options#specifying-environments
      },
      extends: ["eslint:recommended", "plugin:n/recommended"],
      rules: {
        "n/hashbang": "off", // this rule reports _any_ hashbang outside of an npm binary as an error
        "n/prefer-global/process": "off",
        "n/no-process-exit": "off",
        "n/exports-style": ["error", "module.exports"],
        "n/file-extension-in-import": ["error", "always"],
        "n/prefer-global/buffer": ["error", "always"],
        "n/prefer-global/console": ["error", "always"],
        "n/prefer-global/url-search-params": ["error", "always"],
        "n/prefer-global/url": ["error", "always"],
        "n/prefer-promises/dns": "error",
        "n/prefer-promises/fs": "error",
        "n/no-unsupported-features/node-builtins": "error",
        "n/no-unsupported-features/es-syntax": "error",
      },
    },
  ],
};


================================================
FILE: .gitattributes
================================================
# This is similar to the git option core.autocrlf but it applies to all
# users of the repository and therefore doesn't depend on a developers
# local configuration.
* text=auto

# Ignore generated files in GitHub diffs by default
**/*_pb.ts linguist-generated=true
**/*_connect.ts linguist-generated=true
**/*_pb.js linguist-generated=true
**/*_pb.d.ts linguist-generated=true


================================================
FILE: .github/CODE_OF_CONDUCT.md
================================================
## Community Code of Conduct

Connect follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).


================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contributing

We'd love your help making `connect-query-es` better!

If you'd like to add new exported APIs, please [open an issue][open-issue]
describing your proposal — discussing API changes ahead of time makes
pull request review much smoother. In your issue, pull request, and any other
communications, please remember to treat your fellow contributors with
respect!

Note that for a contribution to be accepted, you must sign off on all commits
in order to affirm that they comply with the [Developer Certificate of Origin][dco].
Make sure to configure `git` with the same name and E-Mail as your GitHub account,
and run `git commit` with the `-s` flag to sign. If necessary, a bot will remind
you to sign your commits when you open your pull request, and provide helpful tips.

## Setup

[Fork][fork], then clone the repository:

```
git clone git@github.com:your_github_username/connect-query-es.git
cd connect-query-es
git remote add upstream https://github.com/connectrpc/connect-query-es.git
git fetch upstream
```

Install dependencies (you'll need Node.js in the version specified in `.nvmrc`,
and `npm` in the version specified in `package.json`):

```bash
npm ci
```

Make sure that the tests, linters, and other checks pass:

```bash
npm run all
```

We're using `turborepo` to run tasks. If you haven't used it yet, take a look at
[filtering and package scoping](https://turbo.build/repo/docs/crafting-your-repository/running-tasks).

## Making Changes

Start by creating a new branch for your changes:

```
git checkout main
git fetch upstream
git rebase upstream/main
git checkout -b cool_new_feature
```

Make your changes, then ensure that `npm run all` still passes.
When you're satisfied with your changes, push them to your fork.

```
git commit -a
git push origin cool_new_feature
```

Then use the GitHub UI to open a pull request.

At this point, you're waiting on us to review your changes. We _try_ to respond
to issues and pull requests within a few business days, and we may suggest some
improvements or alternatives. Once your changes are approved, one of the
project maintainers will merge them.

We're much more likely to approve your changes if you:

- Add tests for new functionality.
- Write a [good commit message][commit-message].
- Maintain backward compatibility.

[fork]: https://github.com/connectrpc/connect-query-es/fork
[open-issue]: https://github.com/connectrpc/connect-query-es/issues/new
[dco]: https://developercertificate.org
[commit-message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html


================================================
FILE: .github/RELEASING.md
================================================
# Releasing

## Prerequisites

- See the setup and tools required in CONTRIBUTING.md
- A granular access token for npmjs.com with read and write permissions, scoped
  to the `connectrpc` organization.
- Make sure that the repository is in a good state, without PRs close to merge
  that would ideally be part of the release.

## Steps

1. Choose a new version (e.g. 1.2.3), making sure to follow semver. Note that all
   packages in this repository use the same version number.
2. Trigger the prepare-release workflow that will create a release PR.

- Note: If releasing for a hotfix of a major version that is behind the current main branch, make sure to create an appropriate branch (e.g. release/v1.x) before running the workflow with the branch name set as the base_branch.

3. Edit the PR description with release notes. See the section below for details.
4. Make sure CI passed on your PR and ask a maintainer for review.
5. After approval, merge your PR.

## Release notes

- We generate release notes with the GitHub feature, see
  https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes
- Only changes that impact users should be listed. No need to list things like
  doc changes (unless it’s something major), dependency version bumps, or similar.
  Remove them from the generated release notes.
- If the release introduces a major new feature or change, add a section at the
  top that explains it for users. A good example is https://github.com/connectrpc/connect-es/releases/tag/v0.10.0
  It lists a major new feature and a major change with dedicated sections, and
  moves the changelist with PR links to a separate "Enhancement" section below.
- If the release includes a very long list of changes, consider breaking the
  changelist up with the sections "Enhancements", "Bugfixes", "Breaking changes".
  A good example is https://github.com/connectrpc/connect-es/releases/tag/v0.9.0
- If the release includes changes specific to a npm package, group and explain
  the changelist in according separate sections. A good example is https://github.com/connectrpc/connect-es/releases/tag/v0.8.0
  Note that we are not using full package names with scope - a more user-friendly
  name like "Connect for Node.js" or "Connect for Fastify" is preferable.


================================================
FILE: .github/dependabot.yaml
================================================
version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "monthly"
      day: "monday"
      timezone: UTC
      time: "07:00"
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "monthly"
      day: "monday"
      timezone: UTC
      time: "07:00"
    open-pull-requests-limit: 50
    groups:
      connectRelated:
        patterns:
          - "@connectrpc/*"
          - "@bufbuild/*"
      devDependencies:
        patterns:
          - "@arethetypeswrong/*"
          - "@testing-library/*"
          - "@types/*"
          - "@typescript-eslint/*"
          - "@vitejs/*"
          - "cspell"
          - "eslint*"
          - "jest-mock"
          - "jest"
          - "prettier"
          - "react-dom"
          - "react"
          - "ts-jest"
          - "ts-node"
          - "turbo"
          - "typescript"
          - "vite"
          - "vitest"
          - "@vitest/*"
      reactQuery:
        patterns:
          - "@tanstack/react-query"
          - "@tanstack/react-query-devtools"
          - "@tanstack/query-core"


================================================
FILE: .github/release.yaml
================================================
changelog:
  exclude:
    labels:
      - ignore-for-release
    authors:
      - dependabot[bot]


================================================
FILE: .github/workflows/add-to-project.yaml
================================================
name: Add issues and PRs to project

on:
  issues:
    types:
      - opened
      - reopened
      - transferred
  pull_request_target:
    types:
      - opened
      - reopened
  issue_comment:
    types:
      - created

jobs:
  call-workflow-add-to-project:
    name: Call workflow to add issue to project
    uses: connectrpc/base-workflows/.github/workflows/add-to-project.yaml@main
    secrets: inherit


================================================
FILE: .github/workflows/ci.yaml
================================================
name: ci

on:
  push:
    branches: [main, "v*"]
    tags: ["v*"]
  pull_request:
    branches: [main, "v*"]
  workflow_dispatch:

permissions:
  contents: read

env:
  # https://consoledonottrack.com/
  DO_NOT_TRACK: 1

jobs:
  tasks:
    runs-on: ubuntu-22.04
    strategy:
      fail-fast: false
      matrix:
        task:
          - format
          - license-header
          - lint
          - attw
          - build
        include:
          - task: format
            diff-check: true
          - task: license-header
            diff-check: true
    name: ${{ matrix.task }}
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v6
        with:
          node-version-file: .nvmrc
          cache: "npm"
      - uses: actions/cache@v5
        with:
          path: .turbo
          key: ${{ runner.os }}/${{ matrix.task }}/${{ github.sha }}
          restore-keys: ${{ runner.os }}/${{ matrix.task }}
      - run: npm ci
      - run: npx turbo run ${{ matrix.task }}
      - name: Check changed files
        if: ${{ matrix.diff-check }}
        run: node scripts/gh-diffcheck.js
  test:
    runs-on: ubuntu-22.04
    strategy:
      fail-fast: false
      matrix:
        node-version: [24.x, 22.x, 20.x]
    name: "test on Node.js ${{ matrix.node-version }}"
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v6
        with:
          node-version: ${{ matrix.node-version }}
          cache: "npm"
      - uses: actions/cache@v5
        with:
          path: .turbo
          key: ${{ runner.os }}/test/${{ github.sha }}
          restore-keys: ${{ runner.os }}/test
      - run: npm ci
      - run: npx turbo run test


================================================
FILE: .github/workflows/pr-title.yaml
================================================
name: Lint PR Title
# Prevent writing to the repository using the CI token.
# Ref: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#permissions
permissions:
  pull-requests: read
on:
  pull_request:
    # By default, a workflow only runs when a pull_request's activity type is opened,
    # synchronize, or reopened. We explicity override here so that PR titles are
    # re-linted when the PR text content is edited.
    types:
      - opened
      - edited
      - reopened
      - synchronize
jobs:
  lint:
    uses: bufbuild/base-workflows/.github/workflows/pr-title.yaml@main


================================================
FILE: .github/workflows/prepare-release.yml
================================================
name: Prepare Release

on:
  workflow_dispatch:
    inputs:
      version:
        description: "Version to release (e.g. 1.2.3)"
        required: true
        type: string

jobs:
  prepare-release:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v6
        with:
          ref: main
          fetch-depth: 0
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version-file: ".nvmrc"

      - name: Install dependencies
        run: npm ci

      - name: Create release branch
        run: |
          git config --global user.name 'github-actions[bot]'
          git config --global user.email 'github-actions[bot]@users.noreply.github.com'
          git checkout -b "release/prep-release-${{ inputs.version }}"

      - name: Get current workspace version
        id: workspace_version
        run: |
          VERSION=$(npm run getversion --silent)
          echo "version=$VERSION" >> $GITHUB_OUTPUT

      - name: Set version and run build
        run: |
          npm run setversion ${{ inputs.version }}

      - name: Commit version changes
        run: |
          git add .
          git commit -s -m "Release ${{ inputs.version }}"
          git push --set-upstream origin "release/prep-release-${{ inputs.version }}"

      - name: Get release notes
        id: release_notes
        run: |
          RELEASE_NOTES=$(
            gh api \
              --method POST \
              -H "Accept: application/vnd.github+json" \
              -H "X-GitHub-Api-Version: 2022-11-28" \
              /repos/${{ github.repository }}/releases/generate-notes \
              -f 'tag_name=v${{ inputs.version }}' -f 'target_commitish=${{ inputs.base_branch }}' -f 'previous_tag_name=v${{ steps.workspace_version.outputs.version }}' \
              --jq ".body" \
          )
          echo "notes<<EOF" >> $GITHUB_OUTPUT
          echo "$RELEASE_NOTES" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Create pull request
        run: |
          gh pr create \
            --title "Release ${{ inputs.version }}" \
            --body "${{ steps.release_notes.outputs.notes }}" \
            --base "${{ inputs.base_branch }}"
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .github/workflows/publish-release.yml
================================================
name: Publish Release

on:
  pull_request:
    types: [closed]
    branches:
      - main

jobs:
  publish-release:
    runs-on: ubuntu-latest
    # Only run if PR was merged and branch name starts with release/prep-release-
    if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/prep-release-')
    permissions:
      id-token: write # Required for OIDC
      contents: write
      pull-requests: write
      issues: write

    steps:
      - name: Checkout base branch
        uses: actions/checkout@v6
        with:
          ref: ${{ github.event.pull_request.base.ref }}
          fetch-depth: 0
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version-file: ".nvmrc"

      - name: Install dependencies
        run: npm ci

      - name: Get current workspace version
        id: workspace_version
        run: |
          VERSION=$(npm run getversion --silent)
          echo "version=$VERSION" >> $GITHUB_OUTPUT

      - name: Get updated release notes from PR
        id: pr_notes
        run: |
          RELEASE_NOTES=$(gh pr view ${{ github.event.pull_request.number }} --json body | jq -r ".body")
          echo "notes<<EOF" >> $GITHUB_OUTPUT
          echo "$RELEASE_NOTES" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Publish to npm
        run: npm run release

      - name: Publish GitHub release
        run: |
          gh release create v${{ steps.workspace_version.outputs.version }} \
            --title "Release v${{ steps.workspace_version.outputs.version }}" \
            --notes "${{ steps.pr_notes.outputs.notes }}"
        # --discussion-category "Announcements" ## Enable if discussions are enabled
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .gitignore
================================================
.turbo
.wrangler
node_modules
/packages/*/dist
/packages/*/coverage
tsconfig.vitest-temp.json

================================================
FILE: .nvmrc
================================================
v24.5.0


================================================
FILE: .vscode/extensions.json
================================================
{
  "recommendations": ["orta.vscode-twoslash-queries"]
}


================================================
FILE: .vscode/settings.json
================================================
{
  "git.enableCommitSigning": true,
  "git.alwaysSignOff": true,
  "typescript.tsdk": "node_modules/typescript/lib"
}


================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

1.  Definitions.

    "License" shall mean the terms and conditions for use, reproduction,
    and distribution as defined by Sections 1 through 9 of this document.

    "Licensor" shall mean the copyright owner or entity authorized by
    the copyright owner that is granting the License.

    "Legal Entity" shall mean the union of the acting entity and all
    other entities that control, are controlled by, or are under common
    control with that entity. For the purposes of this definition,
    "control" means (i) the power, direct or indirect, to cause the
    direction or management of such entity, whether by contract or
    otherwise, or (ii) ownership of fifty percent (50%) or more of the
    outstanding shares, or (iii) beneficial ownership of such entity.

    "You" (or "Your") shall mean an individual or Legal Entity
    exercising permissions granted by this License.

    "Source" form shall mean the preferred form for making modifications,
    including but not limited to software source code, documentation
    source, and configuration files.

    "Object" form shall mean any form resulting from mechanical
    transformation or translation of a Source form, including but
    not limited to compiled object code, generated documentation,
    and conversions to other media types.

    "Work" shall mean the work of authorship, whether in Source or
    Object form, made available under the License, as indicated by a
    copyright notice that is included in or attached to the work
    (an example is provided in the Appendix below).

    "Derivative Works" shall mean any work, whether in Source or Object
    form, that is based on (or derived from) the Work and for which the
    editorial revisions, annotations, elaborations, or other modifications
    represent, as a whole, an original work of authorship. For the purposes
    of this License, Derivative Works shall not include works that remain
    separable from, or merely link (or bind by name) to the interfaces of,
    the Work and Derivative Works thereof.

    "Contribution" shall mean any work of authorship, including
    the original version of the Work and any modifications or additions
    to that Work or Derivative Works thereof, that is intentionally
    submitted to Licensor for inclusion in the Work by the copyright owner
    or by an individual or Legal Entity authorized to submit on behalf of
    the copyright owner. For the purposes of this definition, "submitted"
    means any form of electronic, verbal, or written communication sent
    to the Licensor or its representatives, including but not limited to
    communication on electronic mailing lists, source code control systems,
    and issue tracking systems that are managed by, or on behalf of, the
    Licensor for the purpose of discussing and improving the Work, but
    excluding communication that is conspicuously marked or otherwise
    designated in writing by the copyright owner as "Not a Contribution."

    "Contributor" shall mean Licensor and any individual or Legal Entity
    on behalf of whom a Contribution has been received by Licensor and
    subsequently incorporated within the Work.

2.  Grant of Copyright License. Subject to the terms and conditions of
    this License, each Contributor hereby grants to You a perpetual,
    worldwide, non-exclusive, no-charge, royalty-free, irrevocable
    copyright license to reproduce, prepare Derivative Works of,
    publicly display, publicly perform, sublicense, and distribute the
    Work and such Derivative Works in Source or Object form.

3.  Grant of Patent License. Subject to the terms and conditions of
    this License, each Contributor hereby grants to You a perpetual,
    worldwide, non-exclusive, no-charge, royalty-free, irrevocable
    (except as stated in this section) patent license to make, have made,
    use, offer to sell, sell, import, and otherwise transfer the Work,
    where such license applies only to those patent claims licensable
    by such Contributor that are necessarily infringed by their
    Contribution(s) alone or by combination of their Contribution(s)
    with the Work to which such Contribution(s) was submitted. If You
    institute patent litigation against any entity (including a
    cross-claim or counterclaim in a lawsuit) alleging that the Work
    or a Contribution incorporated within the Work constitutes direct
    or contributory patent infringement, then any patent licenses
    granted to You under this License for that Work shall terminate
    as of the date such litigation is filed.

4.  Redistribution. You may reproduce and distribute copies of the
    Work or Derivative Works thereof in any medium, with or without
    modifications, and in Source or Object form, provided that You
    meet the following conditions:

    (a) You must give any other recipients of the Work or
    Derivative Works a copy of this License; and

    (b) You must cause any modified files to carry prominent notices
    stating that You changed the files; and

    (c) You must retain, in the Source form of any Derivative Works
    that You distribute, all copyright, patent, trademark, and
    attribution notices from the Source form of the Work,
    excluding those notices that do not pertain to any part of
    the Derivative Works; and

    (d) If the Work includes a "NOTICE" text file as part of its
    distribution, then any Derivative Works that You distribute must
    include a readable copy of the attribution notices contained
    within such NOTICE file, excluding those notices that do not
    pertain to any part of the Derivative Works, in at least one
    of the following places: within a NOTICE text file distributed
    as part of the Derivative Works; within the Source form or
    documentation, if provided along with the Derivative Works; or,
    within a display generated by the Derivative Works, if and
    wherever such third-party notices normally appear. The contents
    of the NOTICE file are for informational purposes only and
    do not modify the License. You may add Your own attribution
    notices within Derivative Works that You distribute, alongside
    or as an addendum to the NOTICE text from the Work, provided
    that such additional attribution notices cannot be construed
    as modifying the License.

    You may add Your own copyright statement to Your modifications and
    may provide additional or different license terms and conditions
    for use, reproduction, or distribution of Your modifications, or
    for any such Derivative Works as a whole, provided Your use,
    reproduction, and distribution of the Work otherwise complies with
    the conditions stated in this License.

5.  Submission of Contributions. Unless You explicitly state otherwise,
    any Contribution intentionally submitted for inclusion in the Work
    by You to the Licensor shall be under the terms and conditions of
    this License, without any additional terms or conditions.
    Notwithstanding the above, nothing herein shall supersede or modify
    the terms of any separate license agreement you may have executed
    with Licensor regarding such Contributions.

6.  Trademarks. This License does not grant permission to use the trade
    names, trademarks, service marks, or product names of the Licensor,
    except as required for reasonable and customary use in describing the
    origin of the Work and reproducing the content of the NOTICE file.

7.  Disclaimer of Warranty. Unless required by applicable law or
    agreed to in writing, Licensor provides the Work (and each
    Contributor provides its Contributions) on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    implied, including, without limitation, any warranties or conditions
    of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
    PARTICULAR PURPOSE. You are solely responsible for determining the
    appropriateness of using or redistributing the Work and assume any
    risks associated with Your exercise of permissions under this License.

8.  Limitation of Liability. In no event and under no legal theory,
    whether in tort (including negligence), contract, or otherwise,
    unless required by applicable law (such as deliberate and grossly
    negligent acts) or agreed to in writing, shall any Contributor be
    liable to You for damages, including any direct, indirect, special,
    incidental, or consequential damages of any character arising as a
    result of this License or out of the use or inability to use the
    Work (including but not limited to damages for loss of goodwill,
    work stoppage, computer failure or malfunction, or any and all
    other commercial damages or losses), even if such Contributor
    has been advised of the possibility of such damages.

9.  Accepting Warranty or Additional Liability. While redistributing
    the Work or Derivative Works thereof, You may choose to offer,
    and charge a fee for, acceptance of support, warranty, indemnity,
    or other liability obligations and/or rights consistent with this
    License. However, in accepting such obligations, You may act only
    on Your own behalf and on Your sole responsibility, not on behalf
    of any other Contributor, and only if You agree to indemnify,
    defend, and hold each Contributor harmless for any liability
    incurred by, or claims asserted against, such Contributor by reason
    of your accepting any such warranty or additional liability.

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

Copyright 2021-2023 The Connect Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


================================================
FILE: MAINTAINERS.md
================================================
# Maintainers

## Current

- [Timo Stamm](https://github.com/timostamm), [Buf](https://buf.build)
- [Steve Ayers](https://github.com/smaye81), [Buf](https://buf.build)
- [Paul Sachs](https://github.com/paul-sachs), [Buf](https://buf.build)

## Former

- [Dimitri Mitropoulos](https://github.com/dimitropoulos)


================================================
FILE: README.md
================================================
<!-- markdownlint-disable-next-line MD041 MD033 -- 033: necessary for setting the width; 041: this is the style of bufbuild READMEs -->

<img src="assets/connect-query@16x.png" width="15%" />

<!-- omit in toc -->

# Connect-Query

[![License](https://img.shields.io/github/license/connectrpc/connect-query-es?color=blue)](./LICENSE) [![Build](https://github.com/connectrpc/connect-query-es/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/connectrpc/connect-query-es/actions/workflows/ci.yaml) [![NPM Version](https://img.shields.io/npm/v/@connectrpc/connect-query/latest?color=green&label=%40connectrpc%2Fconnect-query)](https://www.npmjs.com/package/@connectrpc/connect-query) [![NPM Version](https://img.shields.io/npm/v/@connectrpc/protoc-gen-connect-query/latest?color=green&label=%40connectrpc%2Fprotoc-gen-connect-query)](https://www.npmjs.com/package/@connectrpc/protoc-gen-connect-query)

Connect-Query is an wrapper around [TanStack Query](https://tanstack.com/query) (react-query), written in TypeScript and thoroughly tested. It enables effortless communication with servers that speak the [Connect Protocol](https://connectrpc.com/docs/protocol).

- [Quickstart](#quickstart)
  - [Install](#install)
  - [Usage](#usage)
  - [Generated Code](#generated-code)
- [Connect-Query API](#connect-query-api)
  - [`TransportProvider`](#transportprovider)
  - [`useTransport`](#usetransport)
  - [`useQuery`](#usequery)
  - [`useSuspenseQuery`](#usesuspensequery)
  - [`useInfiniteQuery`](#useinfinitequery)
  - [`useSuspenseInfiniteQuery`](#usesuspenseinfinitequery)
  - [`useMutation`](#usemutation)
  - [`createConnectQueryKey`](#createconnectquerykey)
  - [`callUnaryMethod`](#callunarymethod)
  - [`createProtobufSafeUpdater`](#createprotobufsafeupdater)
  - [`createQueryOptions`](#createqueryoptions)
  - [`createInfiniteQueryOptions`](#createinfinitequeryoptions)
  - [`addStaticKeyToTransport`](#addstatickeytotransport)
  - [`ConnectQueryKey`](#connectquerykey)
  - [`QueryOptions`](#queryoptions)
  - [`QueryOptionsWithSkipToken`](#queryoptionswithskiptoken)
  - [`InfiniteQueryOptions`](#infinitequeryoptions)
  - [`InfiniteQueryOptionsWithSkipToken`](#infinitequeryoptionswithskiptoken)

## Quickstart

### Install

```sh
npm install @connectrpc/connect-query @connectrpc/connect-web
```

> [!TIP]
>
> If you are using something that doesn't automatically install peerDependencies (npm older than v7), you'll want to make sure you also have `@bufbuild/protobuf`, `@connectrpc/connect`, and `@tanstack/react-query` installed. `@connectrpc/connect-web` is required for defining
> the transport to be used by the client.

### Usage

Connect-Query will immediately feel familiar to you if you've used TanStack Query. It provides a similar API, but instead takes a definition for your endpoint and returns a typesafe API for that endpoint.

First, make sure you've configured your provider and query client:

```tsx
import { createConnectTransport } from "@connectrpc/connect-web";
import { TransportProvider } from "@connectrpc/connect-query";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const finalTransport = createConnectTransport({
  baseUrl: "https://demo.connectrpc.com",
});

const queryClient = new QueryClient();

function App() {
  return (
    <TransportProvider transport={finalTransport}>
      <QueryClientProvider client={queryClient}>
        <YourApp />
      </QueryClientProvider>
    </TransportProvider>
  );
}
```

With configuration completed, you can now use the `useQuery` hook to make a request:

```ts
import { useQuery } from '@connectrpc/connect-query';
import { say } from 'your-generated-code/eliza-ElizaService_connectquery';

export const Example: FC = () => {
  const { data } = useQuery(say, { sentence: "Hello" });
  return <div>{data}</div>;
};
```

**_That's it!_**

The code generator does all the work of turning your Protobuf file into something you can easily import. TypeScript types all populate out-of-the-box. Your documentation is also converted to [TSDoc](https://tsdoc.org/).

One of the best features of this library is that once you write your schema in Protobuf form, the TypeScript types are generated and then inferred. You never again need to specify the types of your data since the library does it automatically.

### Generated Code

To make a query, you need a schema for a remote procedure call (RPC). A typed schema can be generated with [`protoc-gen-es`](https://www.npmjs.com/package/@bufbuild/protoc-gen-es). It generates an export for every service:

```ts
/**
 * @generated from service connectrpc.eliza.v1.ElizaService
 */
export declare const ElizaService: GenService<{
  /**
   * Say is a unary RPC. Eliza responds to the prompt with a single sentence.
   *
   * @generated from rpc connectrpc.eliza.v1.ElizaService.Say
   */
  say: {
    methodKind: "unary";
    input: typeof SayRequestSchema;
    output: typeof SayResponseSchema;
  };
}>;
```

[`protoc-gen-connect-query`](https://www.npmjs.com/package/@connectrpc/protoc-gen-connect-query) is an optional additional plugin that exports every RPC individually for convenience:

```ts
import { ElizaService } from "./eliza_pb";

/**
 * Say is a unary RPC. Eliza responds to the prompt with a single sentence.
 *
 * @generated from rpc connectrpc.eliza.v1.ElizaService.Say
 */
export const say: (typeof ElizaService)["method"]["say"];
```

For more information on code generation, see the [documentation for `protoc-gen-connect-query`](https://www.npmjs.com/package/@connectrpc/protoc-gen-connect-query) and the [documentation for `protoc-gen-es`](https://www.npmjs.com/package/@bufbuild/protoc-gen-es).

## Connect-Query API

### `TransportProvider`

```ts
const TransportProvider: FC<
  PropsWithChildren<{
    transport: Transport;
  }>
>;
```

`TransportProvider` is the main mechanism by which Connect-Query keeps track of the `Transport` used by your application.

Broadly speaking, "transport" joins two concepts:

1. The protocol of communication. For this there are two options: the [Connect Protocol](https://connectrpc.com/docs/protocol/), or the [gRPC-Web Protocol](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md).
1. The protocol options. The primary important piece of information here is the `baseUrl`, but there are also other potentially critical options like request credentials, wire serialization options, or protocol-specific options like Connect's support for [HTTP GET](https://connectrpc.com/docs/web/get-requests-and-caching).

With these two pieces of information in hand, the transport provides the critical mechanism by which your app can make network requests.

To learn more about the two modes of transport, take a look at the Connect-Web documentation on [choosing a protocol](https://connectrpc.com/docs/web/choosing-a-protocol/).

To get started with Connect-Query, simply import a transport (either [`createConnectTransport`](https://github.com/connectrpc/connect-es/blob/main/packages/connect-web/src/connect-transport.ts) or [`createGrpcWebTransport`](https://github.com/connectrpc/connect-es/blob/main/packages/connect-web/src/grpc-web-transport.ts) from [`@connectrpc/connect-web`](https://www.npmjs.com/package/@connectrpc/connect-web)) and pass it to the provider.

A common use case for the transport is to add headers to requests (like auth tokens, etc). You can do this with a custom [interceptor](https://connectrpc.com/docs/web/interceptors).

```tsx
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { TransportProvider } from "@connectrpc/connect-query";

const queryClient = new QueryClient();

export const App = () => {
  const transport = createConnectTransport({
    baseUrl: "<your baseUrl here>",
    interceptors: [
      (next) => (request) => {
        request.header.append("some-new-header", "some-value");
        // Add your headers here
        return next(request);
      },
    ],
  });
  return (
    <TransportProvider transport={transport}>
      <QueryClientProvider client={queryClient}>
        <YourApp />
      </QueryClientProvider>
    </TransportProvider>
  );
};
```

For more details about what you can do with the transport, see the [Connect-Web documentation](https://connectrpc.com/docs/web/).

### `useTransport`

```ts
const useTransport: () => Transport;
```

Use this helper to get the default transport that's currently attached to the React context for the calling component.

> [!TIP]
>
> All hooks accept a `transport` in the options. You can use the Transport from the context, or create one dynamically. If you create a Transport dynamically, make sure to memoize it, because it is taken into consideration when building query keys.

### `useQuery`

```ts
function useQuery<
  I extends DescMessage,
  O extends DescMessage,
  SelectOutData = MessageShape<O>,
>(
  schema: DescMethodUnary<I, O>,
  input?: SkipToken | MessageInitShape<I>,
  { transport, ...queryOptions }: UseQueryOptions<I, O, SelectOutData> = {},
): UseQueryResult<SelectOutData, ConnectError>;
```

The `useQuery` hook is the primary way to make a unary request. It's a wrapper around TanStack Query's [`useQuery`](https://tanstack.com/query/v5/docs/react/reference/useQuery) hook, but it's preconfigured with the correct `queryKey` and `queryFn` for the given method.

Any additional `options` you pass to `useQuery` will be merged with the options that Connect-Query provides to @tanstack/react-query. This means that you can pass any additional options that TanStack Query supports.

### `useSuspenseQuery`

Identical to useQuery but mapping to the `useSuspenseQuery` hook from [TanStack Query](https://tanstack.com/query/v5/docs/react/reference/useSuspenseQuery). This includes the benefits of narrowing the resulting data type (data will never be undefined).

### `useInfiniteQuery`

```ts
function useInfiniteQuery<
  I extends DescMessage,
  O extends DescMessage,
  ParamKey extends MessagePageParamKey<MessageInitShape<I>>,
>(
  schema: DescMethodUnary<I, O>,
  input: SkipToken | MessageInitWithPageParam<MessageInitShape<I>, ParamKey>,
  {
    transport,
    pageParamKey,
    getNextPageParam,
    ...queryOptions
  }: UseInfiniteQueryOptions<I, O, ParamKey>,
): UseInfiniteQueryResult<InfiniteData<MessageShape<O>>, ConnectError>;
```

The `useInfiniteQuery` is a wrapper around TanStack Query's [`useInfiniteQuery`](https://tanstack.com/query/v5/docs/react/reference/useInfiniteQuery) hook, but it's preconfigured with the correct `queryKey` and `queryFn` for the given method.

There are some required options for `useInfiniteQuery`, primarily `pageParamKey` and `getNextPageParam`. These are required because Connect-Query doesn't know how to paginate your data. You must provide a mapping from the output of the previous page and getting the next page. `pageParamKey` supports root keys as strings (`"page"`) and nested keys as dot-separated strings (`"query.page"`). All other options passed to `useInfiniteQuery` will be merged with the options that Connect-Query provides to @tanstack/react-query. This means that you can pass any additional options that TanStack Query supports.

### `useSuspenseInfiniteQuery`

Identical to useInfiniteQuery but mapping to the `useSuspenseInfiniteQuery` hook from [TanStack Query](https://tanstack.com/query/v5/docs/react/reference/useSuspenseInfiniteQuery). This includes the benefits of narrowing the resulting data type (data will never be undefined).

### `useMutation`

```ts
function useMutation<I extends DescMessage, O extends DescMessage>(
  schema: DescMethodUnary<I, O>,
  { transport, ...queryOptions }: UseMutationOptions<I, O, Ctx> = {},
): UseMutationResult<MessageShape<O>, ConnectError, PartialMessage<I>>;
```

The `useMutation` is a wrapper around TanStack Query's [`useMutation`](https://tanstack.com/query/v5/docs/react/reference/useMutation) hook, but it's preconfigured with the correct `mutationFn` for the given method.

Any additional `options` you pass to `useMutation` will be merged with the options that Connect-Query provides to @tanstack/react-query. This means that you can pass any additional options that TanStack Query supports.

### `createConnectQueryKey`

This function is used under the hood of `useQuery` and other hooks to compute a [`queryKey`](https://tanstack.com/query/v4/docs/react/guides/query-keys) for TanStack Query. You can use it to create keys yourself to filter queries.

`useQuery` creates a query key with the following parameters:

1. The qualified name of the RPC.
2. The transport being used.
3. The request message.
4. The cardinality of the RPC (either "finite" or "infinite").
5. Adds a DataTag which brands the key with the associated data type of the response.

The DataTag type allows @tanstack/react-query functions to properly infer the type of the data returned by the query. This is useful for things like `QueryClient.setQueryData` and `QueryClient.getQueryData`.

To create the same key manually, you simply provide the same parameters:

```ts
import { createConnectQueryKey, useTransport } from "@connectrpc/connect-query";
import { ElizaService } from "./gen/eliza_pb";

const myTransport = useTransport();
const queryKey = createConnectQueryKey({
  schema: ElizaService.method.say,
  transport: myTransport,
  // You can provide a partial message here.
  input: { sentence: "hello" },
  // This defines what kind of request it is (either for an infinite or finite query).
  cardinality: "finite",
});

// queryKey:
[
  "connect-query",
  {
    transport: "t1",
    serviceName: "connectrpc.eliza.v1.ElizaService",
    methodName: "Say",
    input: { sentence: "hello" },
    cardinality: "finite",
  },
];
```

You can create a partial key that matches all RPCs of a service:

```ts
import { createConnectQueryKey } from "@connectrpc/connect-query";
import { ElizaService } from "./gen/eliza_pb";

const queryKey = createConnectQueryKey({
  schema: ElizaService,
  cardinality: "finite",
});

// queryKey:
[
  "connect-query",
  {
    serviceName: "connectrpc.eliza.v1.ElizaService",
    cardinality: "finite",
  },
];
```

Infinite queries have distinct keys. To create a key for an infinite query, use the parameter `cardinality`:

```ts
import { createConnectQueryKey } from "@connectrpc/connect-query";
import { ListService } from "./gen/list_pb";

// The hook useInfiniteQuery() creates a query key with cardinality: "infinite",
// and passes on the pageParamKey.
const queryKey = createConnectQueryKey({
  schema: ListService.method.list,
  cardinality: "infinite",
  pageParamKey: "page",
  input: { preview: true },
});
```

### `callUnaryMethod`

```ts
function callUnaryMethod<I extends DescMessage, O extends DescMessage>(
  transport: Transport,
  schema: DescMethodUnary<I, O>,
  input: MessageInitShape<I> | undefined,
  options?: {
    signal?: AbortSignal;
  },
): Promise<O>;
```

This API allows you to directly call the method using the provided transport. Use this if you need to manually call a method outside of the context of a React component, or need to call it where you can't use hooks.

### `createProtobufSafeUpdater` (deprecated)

Creates a typesafe updater that can be used to update data in a query cache. Used in combination with a queryClient.

```ts
import { createProtobufSafeUpdater, useTransport } from '@connectrpc/connect-query';
import { useQueryClient } from "@tanstack/react-query";

...

const queryClient = useQueryClient();
const transport = useTransport();
queryClient.setQueryData(
  createConnectQueryKey({
    schema: example,
    transport,
    input: {},
    cardinality: "finite",
  }),
  createProtobufSafeUpdater(example, (prev) => {
    if (prev === undefined) {
      return undefined;
    }
    return {
      ...prev,
      completed: true,
    };
  })
);

```

** Note: This API is deprecated and will be removed in a future version. `ConnectQueryKey` now contains type information to make it safer to use `setQueryData` directly. **

### `createQueryOptions`

```ts
function createQueryOptions<I extends DescMessage, O extends DescMessage>(
  schema: DescMethodUnary<I, O>,
  input: SkipToken | PartialMessage<I> | undefined,
  {
    transport,
  }: {
    transport: Transport;
  },
): {
  queryKey: ConnectQueryKey;
  queryFn: QueryFunction<MessageShape<O>, ConnectQueryKey> | SkipToken;
  structuralSharing: (oldData: unknown, newData: unknown) => unknown;
};
```

A functional version of the options that can be passed to the `useQuery` hook from `@tanstack/react-query`. When called, it will return the appropriate `queryKey`, `queryFn`, and `structuralSharing` flag. This is useful when interacting with `useQueries` API or queryClient methods (like [ensureQueryData](https://tanstack.com/query/latest/docs/reference/QueryClient#queryclientensurequerydata), etc).

An example of how to use this function with `useQueries`:

```ts
import { useQueries } from "@tanstack/react-query";
import { createQueryOptions, useTransport } from "@connectrpc/connect-query";
import { example } from "your-generated-code/example-ExampleService_connectquery";

const MyComponent = () => {
  const transport = useTransport();
  const [query1, query2] = useQueries([
    createQueryOptions(example, { sentence: "First query" }, { transport }),
    createQueryOptions(example, { sentence: "Second query" }, { transport }),
  ]);
  ...
};
```

### `createInfiniteQueryOptions`

```ts
function createInfiniteQueryOptions<
  I extends DescMessage,
  O extends DescMessage,
  ParamKey extends MessagePageParamKey<MessageInitShape<I>>,
>(
  schema: DescMethodUnary<I, O>,
  input: SkipToken | MessageInitWithPageParam<MessageInitShape<I>, ParamKey>,
  {
    transport,
    getNextPageParam,
    pageParamKey,
  }: ConnectInfiniteQueryOptions<I, O, ParamKey>,
): {
  getNextPageParam: ConnectInfiniteQueryOptions<
    I,
    O,
    ParamKey
  >["getNextPageParam"];
  queryKey: ConnectInfiniteQueryKey<I>;
  queryFn:
    | QueryFunction<
        MessageShape<O>,
        ConnectInfiniteQueryKey<I>,
        MessageInitShape<I>[ParamKey]
      >
    | SkipToken;
  structuralSharing: (oldData: unknown, newData: unknown) => unknown;
  initialPageParam: PartialMessage<I>[ParamKey];
};
```

A functional version of the options that can be passed to the `useInfiniteQuery` hook from `@tanstack/react-query`.When called, it will return the appropriate `queryKey`, `queryFn`, and `structuralSharing` flags, as well as a few other parameters required for `useInfiniteQuery`. This is useful when interacting with some queryClient methods (like [ensureQueryData](https://tanstack.com/query/latest/docs/reference/QueryClient#queryclientensurequerydata), etc).

### `addStaticKeyToTransport`

Transports are taken into consideration when building query keys for associated queries. This can cause issues with SSR since the transport on the server is not the same transport that gets executed on the client (cannot be tracked by reference). To bypass this, you can use this method to add an explicit key to the transport that will be used in the query key. For example:

```ts
import { addStaticKeyToTransport } from "@connectrpc/connect-query";
import { createConnectTransport } from "@connectrpc/connect-web";

const transport = addStaticKeyToTransport(
  createConnectTransport({
    baseUrl: "https://demo.connectrpc.com",
  }),
  "demo",
);
```

### `ConnectQueryKey`

```ts
type ConnectQueryKey = [
  /**
   * To distinguish Connect query keys from other query keys, they always start with the string "connect-query".
   */
  "connect-query",
  {
    /**
     * A key for a Transport reference, created with createTransportKey().
     */
    transport?: string;
    /**
     * The name of the service, e.g. connectrpc.eliza.v1.ElizaService
     */
    serviceName: string;
    /**
     * The name of the method, e.g. Say.
     */
    methodName?: string;
    /**
     * A key for the request message, created with createMessageKey(),
     * or "skipped".
     */
    input?: Record<string, unknown> | "skipped";
    /**
     * Whether this is an infinite query, or a regular one.
     */
    cardinality?: "infinite" | "finite";
  },
];
```

TanStack Query manages query caching for you based on query keys. [`QueryKey`s](https://tanstack.com/query/v4/docs/react/guides/query-keys) in TanStack Query are arrays with arbitrary JSON-serializable data - typically handwritten for each endpoint. In Connect-Query, query keys are more structured, since queries are always tied to a service, RPC, input message, and transport. For example, a query key might look like this:

```ts
[
  "connect-query",
  {
    transport: "t1",
    serviceName: "connectrpc.eliza.v1.ElizaService",
    methodName: "Say",
    input: {
      sentence: "hello there",
    },
    cardinality: "finite",
  },
];
```

The factory [`createConnectQueryKey`](#createconnectquerykey) makes it easy to create a `ConnectQueryKey`, including partial keys for query filters.

### `QueryOptions`

Return type of `createQueryOptions` assuming SkipToken was not provided.

```ts
interface QueryOptions<I extends DescMessage, O extends DescMessage> {
  queryKey: ConnectQueryKey<O>;
  queryFn: QueryFunction<MessageShape<O>, ConnectQueryKey<O>, MessageShape<I>>;
  structuralSharing: (oldData: unknown, newData: unknown) => unknown;
}
```

### `QueryOptionsWithSkipToken`

Return type of `createQueryOptions` when SkipToken is provided.

```ts
interface QueryOptionsWithSkipToken<
  I extends DescMessage,
  O extends DescMessage,
> extends Omit<QueryOptions<I, O>, "queryFn"> {
  queryFn: SkipToken;
}
```

### `InfiniteQueryOptions`

Return type of `createInfiniteQueryOptions` assuming SkipToken was not provided.

```ts
interface InfiniteQueryOptions<
  I extends DescMessage,
  O extends DescMessage,
  ParamKey extends keyof MessageInitShape<I>,
> {
  getNextPageParam: ConnectInfiniteQueryOptions<
    I,
    O,
    ParamKey
  >["getNextPageParam"];
  queryKey: ConnectQueryKey<O>;
  queryFn: QueryFunction<
    MessageShape<O>,
    ConnectQueryKey<O>,
    MessageInitShape<I>[ParamKey]
  >;
  structuralSharing: (oldData: unknown, newData: unknown) => unknown;
  initialPageParam: MessageInitShape<I>[ParamKey];
}
```

### `InfiniteQueryOptionsWithSkipToken`

Return type of `createInfiniteQueryOptions` when SkipToken is provided.

```ts
interface InfiniteQueryOptionsWithSkipToken<
  I extends DescMessage,
  O extends DescMessage,
  ParamKey extends keyof MessageInitShape<I>,
> extends Omit<InfiniteQueryOptions<I, O, ParamKey>, "queryFn"> {
  queryFn: SkipToken;
}
```

## Testing

Connect-query (along with all other javascript based connect packages) can be tested with the `createRouterTransport` function from `@connectrpc/connect`. This function allows you to create a transport that can be used to test your application without needing to make any network requests. We also have a dedicated package, [@connectrpc/connect-playwright](https://github.com/connectrpc/connect-playwright-es) for testing within [playwright](https://playwright.dev/).

For playwright, you can see a sample test [here](https://github.com/connectrpc/connect-playwright-es/blob/main/packages/connect-playwright-example/tests/simple.spec.ts).

## Frequently Asked Questions

### How do I pass other TanStack Query options?

Each function that interacts with TanStack Query also provides for options that can be passed through.

```ts
import { useQuery } from '@connectrpc/connect-query';
import { example } from 'your-generated-code/example-ExampleService_connectquery';

export const Example: FC = () => {
  const { data } = useQuery(example, undefined, {
    // These are typesafe options that are passed to underlying TanStack Query.
    refetchInterval: 1000,
  });
  return <div>{data}</div>;
};
```

### What is Connect-Query's relationship to Connect-Web and Protobuf-ES?

Here is a high-level overview of how Connect-Query fits in with Connect-Web and Protobuf-ES:

<details>
<summary>Expand to see a detailed dependency graph</summary>

<!-- markdownlint-disable-next-line MD033 -- 033: necessary for setting the width; -->

<img
  alt="connect-query_dependency_graph"
  src="./assets/connect-query_dependency_graph.png"
  width="75%"
/>

</details>

Your Protobuf files serve as the primary input to the code generators `protoc-gen-connect-query` and `protoc-gen-es`. Both of these code generators also rely on primitives provided by Protobuf-ES. The Buf CLI produces the generated output. The final generated code uses `Transport` from Connect-Web and generates a final Connect-Query API.

### What is `Transport`

`Transport` is a regular JavaScript object with two methods, `unary` and `stream`. See the definition in the Connect-Web codebase [here](https://github.com/connectrpc/connect-es/blob/main/packages/connect/src/transport.ts). `Transport` defines the mechanism by which the browser can call a gRPC-web or Connect backend. Read more about Transport on the [connect docs](https://connectrpc.com/docs/web/choosing-a-protocol).

### What if I already use Connect-Web?

You can use Connect-Web and Connect-Query together if you like!

### What if I use gRPC-web?

Connect-Query also supports gRPC-web! All you need to do is make sure you call `createGrpcWebTransport` instead of `createConnectTransport`.

That said, we encourage you to check out the [Connect protocol](https://connectrpc.com/docs/protocol/), a simple, POST-only protocol that works over HTTP/1.1 or HTTP/2. It supports server-streaming methods just like gRPC-Web, but is easy to debug in the network inspector.

### What if I have a custom `Transport`?

If the `Transport` attached to React Context via the `TransportProvider` isn't working for you, then you can override transport at every level. For example, you can pass a custom transport directly to the lowest-level API like `useQuery` or `callUnaryMethod`.

### Does this only work with React?

Connect-Query does require React, but the core (`createConnectQueryKey` and `callUnaryMethod`) is not React specific so splitting off a `connect-solid-query` is possible.

### How do I do Prefetching?

When you might not have access to React context, you can use `createQueryOptions` and provide a transport directly. For example:

```ts
import { say } from "./gen/eliza-ElizaService_connectquery";

function prefetch() {
  return queryClient.prefetchQuery(
    createQueryOptions(say, { sentence: "Hello" }, { transport: myTransport }),
  );
}
```

> [!TIP]
>
> Transports are taken into consideration when building query keys. If you want to prefetch queries on the server, and hydrate them in the client, make sure to use the same transport key on both sides with [`addStaticKeyToTransport`](#addstatickeytotransport).

### What about Streaming?

Connect-Query currently only supports Unary RPC methods, which use a simple request/response style of communication similar to GET or POST requests in REST. This is because it aligns most closely with TanStack Query's paradigms. However, we understand that there may be use cases for Server Streaming, Client Streaming, and Bidirectional Streaming, and we're eager to hear about them.

At Buf, we strive to build software that solves real-world problems, so we'd love to learn more about your specific use case. If you can provide a small, reproducible example, it will help us shape the development of a future API for streaming with Connect-Query.

To get started, we invite you to open a pull request with an example project in the examples directory of the Connect-Query repository. If you're not quite sure how to implement your idea, don't worry - we want to see how you envision it working. If you already have an isolated example, you may also provide a simple CodeSandbox or Git repository.

If you're not yet at the point of creating an example project, feel free to open an issue in the repository and describe your use case. We'll follow up with questions to better understand your needs.

Your input and ideas are crucial in shaping the future development of Connect-Query. We appreciate your input and look forward to hearing from you.

## Legal

Offered under the [Apache 2 license](/LICENSE).


================================================
FILE: SECURITY.md
================================================
# Security Policy

This project follows the [Connect security policy and reporting
process](https://connectrpc.com/docs/governance/security).


================================================
FILE: assets/connect-query.ai
================================================
%PDF-1.6
%
1 0 obj
<</Metadata 2 0 R/OCProperties<</D<</ON[18 0 R]/Order 19 0 R/RBGroups[]>>/OCGs[18 0 R]>>/Pages 3 0 R/Type/Catalog>>
endobj
2 0 obj
<</Length 31167/Subtype/XML/Type/Metadata>>stream
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 7.2-c000 79.1b65a79, 2022/06/13-17:46:14        ">
   <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
      <rdf:Description rdf:about=""
            xmlns:xmp="http://ns.adobe.com/xap/1.0/"
            xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/"
            xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"
            xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
            xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/"
            xmlns:dc="http://purl.org/dc/elements/1.1/"
            xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
            xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#"
            xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"
            xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/"
            xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
         <xmp:CreatorTool>Adobe Illustrator 26.5 (Windows)</xmp:CreatorTool>
         <xmp:CreateDate>2022-11-15T17:46:08-04:00</xmp:CreateDate>
         <xmp:MetadataDate>2022-11-15T17:46:08-05:00</xmp:MetadataDate>
         <xmp:ModifyDate>2022-11-15T17:46:08-05:00</xmp:ModifyDate>
         <xmp:Thumbnails>
            <rdf:Alt>
               <rdf:li rdf:parseType="Resource">
                  <xmpGImg:width>256</xmpGImg:width>
                  <xmpGImg:height>232</xmpGImg:height>
                  <xmpGImg:format>JPEG</xmpGImg:format>
                  <xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgA6AEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq8&#xA;4/Nv87NB/L+3W1CDUNfnTlb6crcQinYSTsK8V8B1b8cuxYTP3NGbOIe98rebfzm/MfzRK5v9Zmgt&#xA;XJpY2TG2gAP7PGMhnH+uWOZ8MMY9HXzzSlzLCmZnYsxLMxqzHcknuctak60Tzt5w0J1bR9avLEJ0&#xA;jhnkWMgdjHXgw9iMjKETzDOM5DkXrnkv/nLDzTp7R2/mmzj1i16Ndwhbe6Ar1IUek9B24r88x56U&#xA;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</xmpGImg:image>
               </rdf:li>
            </rdf:Alt>
         </xmp:Thumbnails>
         <xmpTPg:NPages>1</xmpTPg:NPages>
         <xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>
         <xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>
         <xmpTPg:MaxPageSize rdf:parseType="Resource">
            <stDim:w>190.000000</stDim:w>
            <stDim:h>190.000000</stDim:h>
            <stDim:unit>Pixels</stDim:unit>
         </xmpTPg:MaxPageSize>
         <xmpTPg:PlateNames>
            <rdf:Seq>
               <rdf:li>Cyan</rdf:li>
               <rdf:li>Magenta</rdf:li>
               <rdf:li>Yellow</rdf:li>
               <rdf:li>Black</rdf:li>
            </rdf:Seq>
         </xmpTPg:PlateNames>
         <xmpTPg:SwatchGroups>
            <rdf:Seq>
               <rdf:li rdf:parseType="Resource">
                  <xmpG:groupName>Default Swatch Group</xmpG:groupName>
                  <xmpG:groupType>0</xmpG:groupType>
               </rdf:li>
            </rdf:Seq>
         </xmpTPg:SwatchGroups>
         <dc:format>application/pdf</dc:format>
         <dc:title>
            <rdf:Alt>
               <rdf:li xml:lang="x-default">connect-query</rdf:li>
            </rdf:Alt>
         </dc:title>
         <xmpMM:DocumentID>xmp.did:ef71b652-b2a1-4a4e-86d6-63c0de777b3d</xmpMM:DocumentID>
         <xmpMM:InstanceID>uuid:fe6fd78e-c88a-4c95-8b8a-014f7e1940d4</xmpMM:InstanceID>
         <xmpMM:OriginalDocumentID>xmp.did:7c4f2302-202b-7840-b399-95443e775df7</xmpMM:OriginalDocumentID>
         <xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>
         <xmpMM:DerivedFrom rdf:parseType="Resource">
            <stRef:instanceID>xmp.iid:41fc62d4-bcde-a748-bf99-2213076a569f</stRef:instanceID>
            <stRef:documentID>xmp.did:9f50c985-9253-b841-ae5b-ac499933c02f</stRef:documentID>
            <stRef:originalDocumentID>xmp.did:7c4f2302-202b-7840-b399-95443e775df7</stRef:originalDocumentID>
         </xmpMM:DerivedFrom>
         <xmpMM:History>
            <rdf:Seq>
               <rdf:li rdf:parseType="Resource">
                  <stEvt:action>saved</stEvt:action>
                  <stEvt:instanceID>xmp.iid:7c4f2302-202b-7840-b399-95443e775df7</stEvt:instanceID>
                  <stEvt:when>2022-11-15T17:39:29-05:00</stEvt:when>
                  <stEvt:softwareAgent>Adobe Illustrator 26.5 (Windows)</stEvt:softwareAgent>
                  <stEvt:changed>/</stEvt:changed>
               </rdf:li>
               <rdf:li rdf:parseType="Resource">
                  <stEvt:action>saved</stEvt:action>
                  <stEvt:instanceID>xmp.iid:ef71b652-b2a1-4a4e-86d6-63c0de777b3d</stEvt:instanceID>
                  <stEvt:when>2022-11-15T17:42:05-05:00</stEvt:when>
                  <stEvt:softwareAgent>Adobe Illustrator 26.5 (Windows)</stEvt:softwareAgent>
                  <stEvt:changed>/</stEvt:changed>
               </rdf:li>
            </rdf:Seq>
         </xmpMM:History>
         <illustrator:Type>Document</illustrator:Type>
         <illustrator:CreatorSubTool>AIRobin</illustrator:CreatorSubTool>
         <pdf:Producer>Adobe PDF library 16.07</pdf:Producer>
      </rdf:Description>
   </rdf:RDF>
</x:xmpmeta>
                                                                                                    
                                                                                                    
                                                                                                    
                                                                                                    
                                                                                                    
                                                                                                    
                                                                                                    
                                                                                                    
                                                                                                    
                                                                                                    
                                                                                                    
                                                                                                    
                                                                                                    
                                                                                                    
                                                                                                    
                                                                                                    
                                                                                                    
                                                                                                    
                                                                                                    
                                                                                                    
                           
<?xpacket end="w"?>
endstream
endobj
3 0 obj
<</Count 1/Kids[5 0 R]/Type/Pages>>
endobj
5 0 obj
<</ArtBox[0.0 10.0 190.0 180.0]/BleedBox[0.0 0.0 190.0 190.0]/Contents 20 0 R/CropBox[0.0 0.0 190.0 190.0]/LastModified(D:20221115174608-04'00')/MediaBox[0.0 0.0 190.0 190.0]/Parent 3 0 R/PieceInfo<</Illustrator 7 0 R>>/Resources<</ExtGState<</GS0 21 0 R>>/Properties<</MC0 18 0 R>>>>/Thumb 22 0 R/TrimBox[0.0 0.0 190.0 190.0]/Type/Page>>
endobj
20 0 obj
<</Filter/FlateDecode/Length 3365>>stream
HdɎ$DyP9/W
AAАC7RyT75:LDfd/O߯ǯtۿ~i-]>~K9\=hۇ>>N^{޳Ma1HwHj^_Oj㞭vͻdon={ar5n[y*{Lf5G˄W΃<YeS,|Q}L<Wwsrm1r8X;[au=wKZ΁{-w#k{N
׺ںל"M|N
YEcZ^1rG,?#p}{sKYĮ҇|ݐ`YKY[78V6+9Nr),BEOC#ֻ{LUh]B[J䲿])U:;S	@$j@9رQn7g!`z"`]~0Œ'}Q1Z`0ϓǵqhWm˂-J]2L7G5%ǫ"	R™ޭ[#rbMd\[JqP[!5.?b?M,F?qzoadN=}:z`jT+-ʐO+e3IV#C9Ÿ@$p3y"o8:1[&BWء2~{('g4}~QxQ&Ղġs[,UL׊5IOV)Xu[D^@"P-ۛ"g_B=5ƩrWD֔eHSGQq	k,Y[XvwFѰ#T%e1JSOhQLv# -Xal"K5p`[l	~5N%Ô}5/!.3
| ̲
|PSIqIn
zq0DH'
k?Dz)?86z@U-ݖۛB+Ɍ+QBM1#G(ty]afV
Jz"fhW"Q{rSF1xwB29f$3m``^㢰k.9d`σVI8]DOT]nQaT5蒣kvW5 }dN9,βZ3\MwVnWyRH[:iT{\4y/OubU9&74RpWxD7 6K,ы߽=Hzkzo(rnqUZ98g;:8P6KEunM"6ywNRMD[a|(ޢH,ՎYMLsHV	
Ēj[IB:nAnNjKm |ggx>2;[YmQ@S;Uʸȫ&{7	|)~H
Uq	*Aƺc2VD:j4E5cz'T81Nėכ9@侸T4Mx~$WSRDWx	{÷/I"~9	ϩcjwXT#'J=5!
m
&O}1B#D\5/G菽J|P4OЊzqceSYmI䥋*$CV躙Na.':R4$!<G.!250zujK
V$JS;nZ"MUBJ0~i)4XmJ:[wUFʨ3>Fa5G<z5+!Z/֚Pi$7}
žh"8bĀt
1G.de"<PehqR'	]PWW-6l;%vn UuG,}IƂjRzitb5C8)&(b9C7p?`j~Rʏְjm*LClR2] cD*3N/loX$YԏxյrևzL-qeDMy[cApxլؿt+YR!mPI:Ȳ['Z}Q^c#"U![<U5Mt##*3 q
ƗMjw;2e&EZ6Ix
Ig(f]M|"Eţ&)6'*GM[hh.U!0dBk\ڶSS
%I&jْhYUS긯jeJZ%q߅N*Pi-Krf
$Xt`Sa\lB_gkɣUwTlQRJ07_iU\^Y⊜B]lsO"pc	g<NTBZV]<OǑ> <W߈ˈ,>mT/,BQS"	8.)]4>#͔k&5\>:S}eM0UmCBjh;PY@ZcHT['	 MTu2~!5JGR^'e65{ʀ"W'5OLBEnjHh}^AcGW
2ǍhSH6{
>~)i5U+!|=vΡ\"W.)-ɒyAcݕj Jf{^G{WZL+evEYXЊ*#E
A/ęuƞ%]XoVd"v
K|:Ա>SlUg:=rxfc1-:yRߏi1E;:!oȕ(U"v`&oQ#+B]j!Vzfz!p`=258a!$j8"o?f9>DEJE(Pg'B8`$tR)\⥽QF6Mr	!B#YAv,׏_kkuk?AfU!qRḘ|㱱5찪JLi>:9s
/v(|=gnOd(.qN$xjmSW)̎5jTKI:<3^v^U!2w7f]}ݰνA~M4쒭NZ{e3>b@Nݳg w)3lu@23Fj!~<e
endstream
endobj
22 0 obj
<</BitsPerComponent 8/ColorSpace 23 0 R/Filter[/ASCII85Decode/FlateDecode]/Height 23/Length 228/Width 23>>stream
8;V_Vd1+#:#_lhU!caSg'i,jiJb5p7\B]X,dIci`%;l(Aq118L01&:,0,cSE[\l?L
jE*gpfUHdLGgQ!=8c'!DB7&!>;TsN(6o9+Oaos7rTuAUD6q\+!>[5tSd9RG7R94@0
Dp*Ss#!u#Oh+h*d,RE*e_klX+RG'@fRT7%'-E0NM?+nIoR.`#)1ZPG)h35SoV!kZl
]M2*;a\S?O`JC@'jKi1ZB)iJ=4'q~>
endstream
endobj
23 0 obj
[/Indexed/DeviceRGB 255 24 0 R]
endobj
24 0 obj
<</Filter[/ASCII85Decode/FlateDecode]/Length 428>>stream
8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0
b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup`
E1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\.?d>Mn
6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1
VNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH<
PO7r\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O(
l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~>
endstream
endobj
18 0 obj
<</Intent 25 0 R/Name(Layer 1)/Type/OCG/Usage 26 0 R>>
endobj
25 0 obj
[/View/Design]
endobj
26 0 obj
<</CreatorInfo<</Creator(Adobe Illustrator 26.5)/Subtype/Artwork>>>>
endobj
21 0 obj
<</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>>
endobj
7 0 obj
<</LastModified(D:20221115174608-04'00')/Private 14 0 R>>
endobj
14 0 obj
<</AIMetaData 15 0 R/AIPrivateData1 16 0 R/ContainerVersion 12/CreatorVersion 26/RoundtripStreamType 2/RoundtripVersion 24>>
endobj
15 0 obj
<</Length 1477>>stream
%!PS-Adobe-3.0 
%%Creator: Adobe Illustrator(R) 24.0
%%AI8_CreatorVersion: 26.5.1
%%For: (KIRKLAND) ()
%%Title: (connect-query.ai)
%%CreationDate: 11/15/2022 5:46 PM
%%Canvassize: 16383
%%BoundingBox: 0 10 191 180
%%HiResBoundingBox: 0.000004398789315 10.0000007744293 190.00000001085 179.99999970249
%%DocumentProcessColors: Cyan Magenta Yellow Black
%AI5_FileFormat 14.0
%AI12_BuildNumber: 228
%AI3_ColorUsage: Color
%AI7_ImageSettings: 0
%%RGBProcessColor: 0 0 0 ([Registration])
%AI3_Cropmarks: 0 0 190 190
%AI3_TemplateBox: 95.5 94.5 95.5 94.5
%AI3_TileBox: -211 -301 401 491
%AI3_DocumentPreview: None
%AI5_ArtSize: 14400 14400
%AI5_RulerUnits: 6
%AI24_LargeCanvasScale: 1
%AI9_ColorModel: 1
%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0
%AI5_TargetResolution: 800
%AI5_NumLayers: 1
%AI17_Begin_Content_if_version_gt:24 4
%AI10_OpenToVie: -184.931677018638 417 1.11805555555556 0 8220.98136645962 8147.60869565217 2117 1873 18 0 0 227 219 0 0 0 1 1 0 1 1 0 1
%AI17_Alternate_Content
%AI9_OpenToView: -184.931677018638 417 1.11805555555556 2117 1873 18 0 0 227 219 0 0 0 1 1 0 1 1 0 1
%AI17_End_Versioned_Content
%AI5_OpenViewLayers: 7
%AI17_Begin_Content_if_version_gt:24 4
%AI17_Alternate_Content
%AI17_End_Versioned_Content
%%PageOrigin:-864 -446
%AI7_GridSettings: 72 8 72 8 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142
%AI9_Flatten: 1
%AI12_CMSettings: 00.MS
%%EndComments

endstream
endobj
16 0 obj
<</Length 38915>>stream
%AI24_ZStandard_Data(/X,=$á(DDc:,@AQFRk<A@	&
-
1䷃poM^X>կ÷W~woYj`C1ʬY-[=m~53T1E><b}m-ávnQ?fk;-uG ~qG woY]la͗8[^zvZ~c
loo|(
؞eaQ')._tݢ:lv܊խQ6Ѧ;-oUG_f/6
ǭPX4k.\{ɭ>k`=k@+[mzin{`=ֿexZ=mzukk7չ
?GbptcƏiE,y]c|౦iVۖa]#k.kn}:vOZ9FktzcXǷ3nf]Ǭ57ytխ/X,ztխ׏k0~G\0d^e3c\r5Z7~mz7~~tokH8Hh6
;b+Ѯ]5I`woB;pYc8F_r;R~kc&4|5,j;]ǽEu7dznAZcZ-eg&~[s5[? ,_?S$k
2w|΢Df38~gڎz.F\vW;ZY-"`pn^2Ubj5Xeƴ
wԻj[<lϟ9Ovޯ,5`"[umfT<ˮ/kA}6v!vPٲx&~ӳ~@ற_f17Xb8R|,3`yZ%Ukd4%rn"Cf55w4N~P>7ӭ
ZkQe`OY5g񧔵ǟn-my`8xg0^?cv_g\~8tP-㷃o]/=)ڑgNh8nugߏ}s{Ueu5lo2ߵ?_s݉ɶMf]XTYa[o{-mxp5L	.Rvít}g,\ƂIo8'=|flw.uZ_ږ?fu~نcלg~Ow)}ÛuwmfYz`k]9[~g]ây.An8Y
ܲp̆wTsr6Cv;ĀoY]ϴ[
v+݂6YMp1l\qo^%*u)usuEi:޻tt|:qj]_8#8X8Ln6Lsqv7X;a2f}:qoo?g08wCv_	{tr!7tתs;}:qp\2jjs#w՜W~5Bqmۙp<f@?][VZoG:ħsɵk.~s(Pkk1ap72fW~cgb
T7b;v]GCd֡w8G2;_4`~-qKеveV;f`2|pݑI\wd[LqmH3r[o;wgU1ECa\s>|><:]_~߱btGFJFw}\E/F_8Ns({1r'o>ͮQ.3^:Fã9$La3E%ð?Q1]ofV4Z<sXTg6Y?~[ߌa߰,\pnVUM~w]fyz>GѝӳRqGe;gȻt&A,*FʆݣYmDE1ܪNmƓ.9{o^M'(îxou֚891:;sGJ7M쥣h8Jsh\i;z{ǻya\'߷qe\@~5na>{ɳw<ԿFSܭ/s?mF`>=9.|gخHհ߷q|4}|muz_So:>Ϛ]hG~%:~%HLΆ*i\k;Ʉ
R`Ö<7B~l)j W@2Yiî
w`ի9g"]d2gOKo:OߪC9PZLGv`
ځĐZ&STZplEXU(vctP!
yh,<,uR-$n7bf9QSu1R^P,f(fJOH!G1<e/^*JRrǫU*\b_AN.J*J W8/D\(ƍNl9'Sh/i~Ds$8}(CyJ@E%C&:Ş'a(2sڣLwS.NQu\t-4
)??s~"yH04y`<$Gbyz.hBY/39
eYt0]r]0]r!eBYlbdׁZHP,7`XPz.Zy2l=.N!)/^ hFo4Kʧ@+Mۋ&bϓ8kƊU&
]{|'f#_p\ׇsh*%
ݍ	"qvC]W!ErQuð$l	HbP++dE9FʡvZ\KoljhΏp=	$%r*L"+Ȗli-'dSc`ⴓ=O`,R'[yE1gᒃ5?TYoXeOϰu„+?FNyz:&?ECO	2Iξ_	\Z8P8AdpqJBA	Z$TOjOD3vrJlFXȳZj ?@=oF+5v`Lq)?
wG
 ӄ]YV6`p&m\dZK7v`L
qUفV&	L9u]+EH~ҰPvD~P4g=gǂ
bgr\E^s5zJyn}͸aVfL~&.d͉F
h&}*G
[L6b 0e/443btiD	+ل#4H6]xלi)]KU_Dvi1xc2'7$۸g%IyY(ϐ_~qc8SkCɠlNx&s tqGզB*݆MUٜƍa_|Tlj2RĻ=$YM,m\Ē[jwB<h6\<-)lGۓCPm\vf<2TB`-8D2"AqnZ/  ݪJy'R%!NiARW!(Re
dqiI8ƽDA쒮xgF
2aĿ4OOɥr@^V"QsR`	 Jd)aaqkuB,4۸ cش
èJd	2<0%6N2NH-27d028u!3\Ј}y<8?‚j9>؜Ť&&z2j4aa$4]tQ;.ӷqǍN2~G	
aaXD_Ͽ}
W` #"f@ml\E __@Ir
	K({]ic!M#;񬣰Ja)oj"bOxw1xD mEG_(Y*	I\J%gB#zң":5*|yiЉ{>Ԗ5pMCڰ_s7n/il_d'Ϊ5á07<	C.F
#S3DxiZzI%63BOzumgF1Y<9"Uu%}A҈~BHYy` ςYIM&_	6Vơ+,'VKO;6jgy&
]N4TB*JR7	A,㬨Xi,+>AFW/.5oDYs5~o_y)/^=wo<w5pEEfHLMdqC+GQh(*ON!r8mCf̵տu_lʛLXͬX 稉7!TdNxʇG&$9IBD5z6,
H%GqݢBbKx[ wrkܾ;ݷ<@];`}}G0-2{gY5fsw溵):֚Y-˚zeq3U.A4\쿎r,k
۵.~UtZ5k1M]qo1w_jzDvN;6-v
	iF*J«wqD5ḰTxaQ=‚6ըmD>l1Bn_װ|k-SzfV6&M謨MЄĂzt}:B+PF-y8	`@B:S!4I1U=(CX	m
A~m'_o㾍,#D5ud%Vu*%JUᡥ@=c#0&zxP薓QpK	ݐl…V@8sğȥo
4,᡾ZeA
aoɷq,9ԫϸb'HP<’kx
V<Cc
'N/M*iDVB#CC/s =)<?I 6
tlc`K6`}Ck2%!	Scv6:ѐ(!*ɫka$B^|Y=h|gz	Bo<We!1Օ960e!o t
8TJ)'Ho!b	tb{-1rukJ;L9RP5CtZToHr,3RSN4!JʿJW]G,ht*[2niL#4msIkI&Hٵ<>S+x}\dm)Vٰķq7%v254EH&TR/
@Bs+&2v霞X
AMiRe];b@!&g' ,ecR"TTWC'_m\PCÁ#S5Nz6<*w*GvuZ8DWT$/6p
}̧BcļHՎ6&BjlY *b4$ZPt/aT;3t!C*ʳ?5f`PUmX^Vfy!aUA]L+f݄G9NDVT)8Z$8ZC,'u6<6j2XTtM`$(n#6.4jA&!IgaƧI'\JYOϓXw@F(~U=&=UKrM#4t1I6T:TlXqZ<-_=?,<bHh&
/S=umjT;Қv_3ED\b]@$pFN^L9B],˿8BC:m"E-]U]_ZO0R `KS@!OI@Y,oe ِBNPdP@a>Aj"TRPЀ\3Yn3ZMe'$Gc@m\=yIFP7
&L&D*FK.MEz2G)x'R%fL
Fq[~J0VYJˤ>$Faiuer=PAsM(
fZ5Z"Ob"O)*EB!/5诒vr)////vx&1PfC9P%~/:ά㢠RdUpsU9d|"Iy$yH0Ю%xIʻ4G]2suQ(1]r
X›@Q[
NUi+FoK$w
i}O&h7s23/>8tD7tp%:'Sj/|U4lE}P*K;=тp}Y#RUP-v`L& عŐz@]WvOMb*R0e\8؜4@O@6GPDSTPC	/R(5=g$EGb3+oqjCPth)/~#MXRND*XS(XOlP/N\D!A;PfQ!&d<*瑋J4:O$)K'`h!xME.&Q(ڥ_f2>
%KKyhh]!;x;-hĦM„IMl|
QݦtDtdLS=?BXqN)HV+
ei|*]\in̯#iauL 60?;
'PF  %N&(oyjq%@+dӰu=:n(Yj@d]>a%]	P8U$UMQ;2^/FD{4PFIfZCjދ(NX3EhlYnIYwi)ć6M&
Si/j֪ZvN.
GRI;hëM@OlNdٟ<rjS!T
JĪb
[:㢠R"Dx%&/4G%h>
ev2]ܫ^A	RJ,b)`6+(1UIW&_yfܟ:KG"?r>O)9!;T<},6)N&6E8ΦX6̪V3taPFUQL!Cba~W诏:'XHA[:3	FW;6rgV[2!1	'L.6Ӹ(Q.>2TH)xg1u),RK!:D2VLUaշt>˾>.9R|'y 2&aUG[FFX:ZVf
y hupxIɪȾD
m\ɢv`=<S+Z>CCe	Gڭ[YCfVdZaUĞySbR5^+^#?ٕS.#XhLU!ͨzqBKkCR-DA^AD< O
bwR0bQ3ݐc.G[^LƥN@EV[! aIq!5TN
ytyxV7UT*o㾍;(1&SNp>R5+BҬ&)0/qL8meb
4
I#HQut7DZpF/6Ke
UЖi)zW8Ƶ;fJVbT-VTM!Buo>7b
frb1h^TF}O?Vs
!ChLrL/\VInvv"Ɖ-qh/>M,xԬ83LqAlb 2GD-s"̈b;@ ⣩4񠉒܀lu#$"FDDCQfVN4U/KT]Q^E>9@\Z
нp2Oj5ňmE$}w&9vK7F<ᴋHiV^UzoJHȒ䊏t/䳷8PbxEX"aU
5_A#|۸^2eYCni\QOu&+Њ2axU1ʘH>
0ta)iȒC&D$C3x{#m'ڎV`|x*M|B4hqEKD%y0H$-+(J!
Gq*'*+h/^90@99d(&v4wNTjID̼x*A0gfR*EES5;ZکŹ6.Fѯ*\/O)Y)$)J'AR0&,EQ\U8G"JDuĪQm\XUxb	|S`I͒WeF
JfERHܟk*k!A^Ή
#rb@`WsQ>f]>ơUV٧
KGCI).#‘V;y>o9J49@J
E=@Ӑ>vH^Dv(UيR1АܜhH>h+6'*Ɣۿ$"nsPYr
-v̉%99x0E"f%s
ẢCVN4SniBVN4ğJ8IG{(&PV;!4rvRYdکc䢙ozLpBF`[w~uMg
8]7+$у4#QJBծ
HXU$o4l"J1V4aQ'$rԉ0#D?ˆC!(@FrMbu忍+_y>@T'.f$h8$,I3
(rI:ѐxV ՛2e"yh;.@*1rsH#V~BI	O>T
	4,EDÆEDQD#F%zN4CsaTzߜhXJZen7,P؜hM܎9FH)00Qbʉ
g[)'k9IN[o?V`$a<oՉ#x6wpE"aJiĆƩHT.*g 2%B\6\͢qQoJXkoV̈{7eҷa+z2k
f|:i#$!IJ!V@ǕƀB$}'&L
^[amV-V47
bw`@qm'%A<fN8
;7J9P
ʷq³|W*HEƥ2C"m{4͸O!QI}W#w6۸]8+E&ST
#go2f5U|T+S}RnYCZ`7	-
%*jl8a!k^Jh!f0-*Q\|QӨ89XHVGE4j2щ8҇+NVeBKcʐo㾍cdJBvvr{Ec*
*d=Ke4q!+0
ߏJ~

ڒ%wK"'%bH(WpŃR#i/QnXmLժ& QH=%>ŷqAG&" dG1b[ttTB 	F:>4(T<P,0$$#ah8)
PTRIWEBj-D+',ا'$5D %HfpGll8VxM֕S}.
sP8#"AċX<&K5
:O\Rŗ)ʉ~5ZمeTZ|fE_o&m+Ɇ`^
$Krkj 1,L[M:wb	G"PVx=pF^_W?}mvZd+p(n30N辰ߴI2wH7|K	\<)'{kţUin*DERri!nnInEXUT,I[?L޹h7GI(Jw}ɠ6YܠsU.7dc9l)lD2Anڣu`tD#Vma"T͉m"HmNn9':|2B
	[+Et?vM "iԚ(ē6YgWܫ21IO¨i>Olhĭ)԰YGL6.ٟMt5ȥ	3*qR%4M\%!Ȥ-|292C!Bj{V}^ٲ-"eօ	(xbBf:>]ֹfJ`AªYW=!V\5XE߄!?ȉ']T\/^dx` J|5V=hh2n-ۼرR	`{>[PO8v&0F? 1k^<$)ɱZ+NtaRlpʢ@Wt/^Ļ/(_n#oqsI_HXlp,tM0
ueKDWum$C7]c3FaF="Ùh?}SԸ$RhT&
^poqhT	 *j|gaRɚyUAmI:LK%eJ`b9r0X+4Z6&OoX:%PJm,֪E"%Q<,[ԽDž#2C"
4:x8M.|H;Ţ^7+!c-nR8{Q#%Q|sЬ6T୦('!kjVjj6k`O`\
D{~3VWf}vy#&PUA_gZݴTxzԶ!bmp._B2S%HKī~dcr,o:Y'eZdV"qK^		ڎ{~:c~YW4m!5WYH_cKa6I4{a.=m-jFm-t].^^!,c:l^o1&
%YlHV[?.…n5'̴RnZ `,;iD:.hv#nhЍUgbhUdV}'g,ߌQ~;Vk;fM*-{ZM]$}hHL8ϳCc?a(yU\O]4!}˅	"lkvՠ'pйtR'NܺQnS4ݦCJ67hD
A
)vr7a@n>{Xx"nc'zBѬtӎXr0B<!ɹ
|ĔMP|I~0*3$KQ4:ؖ#M,&1(`rqaW(MZ='J'Rp6jmȊ|HȎѽ@+s#z~ djO1]:	G8y|<"`{=5&#F1{Cx%3s<ؕ}n(W6Arӓ6ͭ<[g"hDzuOWҿ*C~c3KA~<	
0L2n |!ihXpw!KO! 82Ǚ}*sJ7*,r/kfBoL
Qv498Nd!
v1&sa17\M/
$@c_Sܲ#mݴ֥)hmr,zX`2˃To{q%?aix`^^	i"^LST
u7м"bEY6o8X>
u!/7NzO/;}с--C/4nՖ<]dN1
czQH`QAL5MЀ	1{5ČJBBKhf#n]RX(X~@WVF/|o`ۛPp%WAX0Rt-uyO^Lffg܆Aqv.MR64RNLq̆գ xBY̎
ICG
teH%1EHXƽlmV٪xhr2jK4YHdpzdb'4@Mb|bqN'D祹&ЦT@'nch3CeyVw ܯ7;VTISiJЈ^Ή}o6hGV",<gZ3,isA5@ٵln󦝫x -aKlY<pfz3L-q7A=Sȧ;*L(Xtp.΁ua,? 
k [wh!o-n0}y:}"VK׌Us\[;!ցڍ<0qq#z"!}ɇwrrNipLxHϤel3CHJyL3)At2qxcMDQn&
?OO]7g>]ƐE+{Rr#7uCU)ew7(TO3M7)vSHg\Dń
oh'L*\ܟ8H9/RҩWϠWe~dl)Yͼ^-Dko*=GL^IUy/ӟlE6ZSr`ncdXt媸6!()OJm $m.2A,`_9*	ļ67'}^-4ȖR@
:q#7Q2r,m^y?jf0֚Y;ߢ4iBCr$Bi48tH$9{Cu6g65AN%9S$4Lz\>u7ϵB?IӨ$_L?O7<ˁ$7<'UҰ/3x	=OBާY$BJv(֍]`pIgz2	IObOy*uVk%e{C@UZ7}<YW#B9ZT5\;}Qs1լ h1JNgwzPW2>PQnǣM"oȈ 4xWaOX`*$
t1Y㨈
d,1L5"f_֖.3萄/`
2!]2C=RaJw
WaUnsvV͈a*.B
@="RW!h#ZOpx*`nd+%r`S!yjUH$?mĀ{FYr"~	\r}L]NXɕnm%
$K,]T&ײݭ@W0T)W	T!

gUI95I(~!od;5?`>'!%sV0h
~}ΑT6nOL}ʒT!i$tIb128zLG=je]~^GAQ'>=sBb≺[4Dxys~`{p,+&qL&+na1Onz؝?%ˑ2b|5&$~K;	:G}fKBXLQFi@6D,YK@'(MW
Տ?Nڱx`7]:l5DΜ8~5LA(s^ABںbOo]@e\> R@-I~e7~S7D%-h!P@̷?6n$u١R0+@kk#||!<8
/\2Synyy|0:Ei]~KrX?vTE+nR|N7Bm wi+1/L88l\@AX4]P@T-}	WjpⒾ	w>\7D#'ᏹ%>2A
[ӿKކc"$Y
I6us}1yFhghOHاS$!Y/Ɠ#GrjMo
VRn`ܺ$w<#IGEF9h"ZPvMUCgqdD{\]8ڜ׺麶)(Lm= `'m	mN[NiN{uAoYK
%fZM̭df;[l$7ȈjuUJa5ELǧr(~vﶣɝC>wd>>4rn+Rz<1$+PNftMJ<$1;@UJ,7`thId_Ri(	Zk[O $xFOǛxDk`;tݘ3:TX(cƕu
II8Krv拄ٸ>M|L!0VI^TE^魣n<bA;!*Swx
)3+4
)gYʋV z`ԇMgV,
pX8'xHu
0 W72
T[~n/t
Sü~'
0	H_|忝"Z."-mI"B@F,ULVljt[]B/bRR"$Tوyt\W<oĿ\&KfLŦvB2)]N
Y.k*.T;SxDPV2%U^RHΨ&JWҚHp~\9YRw"O?
BRNX@cIЯḫ`AK
s
dʤK=ըc
Pc6dC\113܌Dsc
qhR4ilQeTg2E</qHi7/wu~xb3xx;0`&fpk+び־\$@HCB55r:&{b^
*%BM
z4e Ȟl";:nC1|UޭHۄcqMx˽dig4F6mAk$P*]C&Rb)L)R1M>G&L@Ljd"g=yӤbߣ:&e-XȖȳФٖn(%AfD:O/@#ag4RiRnGF+1)n<๞qJN.,)'MտSUCtqI}MΰwTo÷$]j2rZ<2UWzM<`nlҾٱUBNApiB.J2Ӈ{ow$ZaR
6O|5a)` `L70qaGWjjiʇjsXgprXpo-x-X	DS#u>FGfnABhVK;<ݬQ,TXuDhnSĝ]1|H	<#^m5CcDEHjt~˕AU]*6ny9ry~ LS-IԬo-J/<|dq%b@u<s$қ\G<Ś"~!hqU 66M)K@ƜR0w[kP/⫁u5i[+;E`}:Xt?J}9pa[KvT+RiK̡~3?g. jrj_CE^6	ϢQ]F{M2`T)	wI"/rG*.|ס`	5,kӈ (נiSjvvRjjF-P˯	2Ж`Cg܃2*(h}Rɢ"fQ= m\#TA~
$N	!Fce$0u;Espj?.[&&CgEԮ)uKòHHHe3[4QPQKf_x@5V2`Wja.&C̒
%t9!'iCGDSFf"w4Cz&Ċ

tlfFm}|1&c/[}oE!vj{FBLגɅ>Gwxt'Ajh3C=	MryMk݄.EieO0֕=(R*0!xs[@Zc"HClׅDKdjPKX@)2:zPߝC/}4
v؋
3m'A1aGT2
v%_	.藌Cd0OU
L}MlM,W<:{`规o<S(xl
5u![7VSmBcUbN_,V˅w0y<@e\ǍOȥ=2ƭ*k[>+ӗ"#dK]PhӗހǮXZJnCmYf<áMSY4Qx#q<aV 8fDÏƚ3b
-M(dXϬ2z+n4dD
_j(fsM9TtaW98žNU7
xMg$PfX-l?ѭL	G

ZQk{>(m4Pvǎڃ
Ο?N!آZ`teԺܭQ)TYݹѶ2!_	k ]DSdFs6_-kGEX)lk58ޛ!AATL$׫.Yppeetdfљ`m\Ԯ;]Pbɮ!d#a]ćxhkmIcFOIg@ܶGV$"DOrڭ@І@lG&AC,4K/$&6caD	,>AAyߊG^.o0s҈q#V|x0l02X	Y5o9G@BlʃDŽ7f
"Q%c?+{5KϊOѽbvlpƖ%7b(M*VjXKkpFsE(Y#\tԮ3 qrl(ZP^L܀rI/t@BB, D͟$f;$(ͳEOrDbMpa(qla)uAv֛~P$'>JV%o3b9݇wDWO./%qv
㟉ŨDԒvg1і<G3}~Z}(묲/7b>M
v鳴,[-Q>;Z%{|]0s#/lBH8T,D^ak=i"\ev8Z6jt
^RVt@C4Sb(6S*eZq4CB睧VԧQ<'l}ܬ&p+"1{2rGJ!O0#W<CpdߍCh<tzH&G!\^˃bciH\pS.	U:tRJ(+gwmҮ:'Yl 7ˢn֢r1$5;p^m!k	֒v{˺$T+G%oȦiӥ5^ѻ124(툖O
hq
uu`-\S^(
`ؑCMbeWiMx<t-`B;\v\}`i64#ӅMi;^h)nv?Ĉ1҇\ZjsKf0!{5z+N=AMHo-"rwCp%FB@!qu=#ZeN^:%t;{J9&H
A0yXWW+GLVXC<}	_^AQ\S03֋y'%B4EB?h53fB9/qX7	:s)CYgRys
VtBo$Ҋ*RZo0xnœhy,Qg'TG.t=As#58\TTG V\h>wJ{qj	K~1mƁ_Udp>3^pupBh[OND Wul2rI6<_ը9 zt׺[\
J.HDqk+޼o,&G_:Kk׈N2	bӆwp(D-SD"xP>(r79S|y/Oɨ:&s20f,oO~T٢.'w=\BjşΩ#w/ϐzFty<Oz_@
!&_P­JNFzKU:Ј9
g3^
P	<KZ3>*A5Tͨ2w
*g-D:JV$"HV&$IL~H#RHfK5p\&S렬B36~qbR+fGosޭlT387e{jo#wĿn0M	PuWr^X1ÿӳۤ;<}Q`ߘȾO 'beCe
pȪuŋ/%X!=EuC]ߟO2俾Ga%4	
oC%4 ^e3Kě=Mע5
M/1ujoH/~QGX.NB$8g8 #}̉ËL*P=ܛц=Kw|1`b&li.5<M	"W:,,v`Ŵff"*CdGÎ#4{LС"݇JJ[Pԇ9
6;
@6 xF1xڹ&Ȳ$S|
K./Ԕ
&XJ^Ťkq;V;g z#(n.9TpTC~)c/51mthMXxB\9K}P^`O)B{L\EaX	atbY%6G5(nn75{!hL<j˙SvPm+/ !f>ʶ){/TȎL`)֡N1T@0;ϵiu;]V&.1Mdݖwy!}\2/1EU4p(³V%_pd.Q!hQx0k'\bSf(wh=Th8]*i0Csx8&es}̇ha)xJS.JBCDRhsV/§!2@K(Xi;oBHKW} av|FPb2ގ=
.h26j
Z`CLnXGʳ6܂V>)7Q0˿
h꘼Ê;;l'Xp@5?Iqi}ۢj\t\.9{8!J֞Γ{By߅i8 '/o<Ryw}ZF߂nyiQXƺb}&Zt%Y|sl&a'ׇguW4ӞM5*cbz✴dH͙|Yi00Σ!'f,4v"7ɮ,}K#|*DZ/fbnpA'dYn!HPG'גVC[?oXUr`4
;G=
nr"FŒbs},Z%φ6g}1J@oTKc"wn>YDwYt%Kf@%ﯞ67;ǟRMB*چmdѦ27B
qdLmh1u#WW݇AQQbt,ςv[ evZ$/%yz#W
AMN5MK>S$G4xP>!+L,2^ .w	{T!纨mhM){nnIx{ #%U$7,Y'*Bt9aHЮ,CɍNj6m
6&0yAH8/*$rIn_GPEon8xNm
Vc,j":XX=L̥E\x8t|WQ`A/_!.6m_L
&V\J3We:N[r`Lpc{gm/vS'XsuZuKDQߘ) '_aw}.)),.oհ-\c(7Դqlx׳Ј)]p3a`MChXDwvKa){P\f}:.㫔;'Ideƣ~`
J?$i5 D6m:rQTDvΫTC4Y8<ia|c`\e|bP;&\gATPf#~0rQ9m aW/ڔ34iVՅ|^ߟb
Az)6[s&r)n-qaD|̛7.,SJoܙ9ucn%B)?Bio&Udz}EXc84DE5"R<Sc-xkOaC	v/k4d"~bZq+7ڋ$OkR	'MjO4SnK̲QaOB5;z$H#wm\RX5Av 5RÍMncVǩaZ'gL'>Ok(;כbհm9~@J8xPVc!Y$|y{@\V6
(5L=gbWEh𬉰` }*

M'4.uU?K?P>	T!>Lֆdj,jٿ?NRz䰈YZVh?!-|t}pDZg@UkEtAV*#!Θ<T`ܛL{Msg/:U͠D s>!igJ
PrqbG]fs|Nt\V
fxI<6:*_6=g̦C<^My-Ihr#̀>K]8D46<JoMĘU=t*Gc@"~pG4mǴDd(&l`#ƨwSo"UkѪ:.y8lR>v/aTDp㍍%{<z.u
ڎ0d-fy(6
c;?GTpk^tYbؘڌm0JOm
'R9>ZW3Hvߦ%"򩏢#ht#"YvV6\ 2SvـeZoXӨS}oTġK`	u\(-5
K"!}| ma_sV3&er{&>9\0(_sLÞ qUZHoK+/{׿& -Z2,nJ5Jpq.:/]ߋ'͇<ާV:s: g*pܠjpZEK%eF)߁sXK=
9zy(A$6f9(|j;NΕ0P
sFOQNӨ8~:rM?4R50,	_W'@3<,iL!
"RS?J3W^1QꚐOnM܋E5<?ZvR	im%)z @qv\	(vԼ	~?9pbFe-7:&Y?hKFLGs'MNgrS!;=(ܰ#m:Ф,0{O7|~33UJfmj:>N#,\ȩ:c{zfކ[(N**T's^^|Tz
6F<1, hʵQ;\dؘn\$:l~򾉮v1<<xX _l@ ⶳnaqIA0E6Ⱬ0iV٦_:=k-@X$~>rZJn};+-F)=y#4?R_ȸ*TQ3rrZn:'%0I0YgDYJn	rmUBD盝(2km@j'(	(YfUlcot2L
'dGO_+@dXĦ
ߨsAflԂFydn|5o0r
>fuRU>2!FsMEJ
-,9v}(f1e&$!ǐ׮ѐciE(CWo\rWX78Ȳ25̶¦/غGBCBSHNI0y@Mhdن?N;2@;ɁZ*%S+(0'>}i>I+|%{:xZ2Asv*AY.|Ydn!"b5t1fHҊ\vO,#~??-N*1x	N9y¦pwqڵ! 9k#ƮᑴXc;-1j3x08oL2v72>qꅥwVآ]M
ZGb:"ӝhs@
Q&r:LĝDRYIѨ\Zr'I[[	Q uBL|Hp^{jd6ETaznЮ( gUs{sT _~u_vt8ݐ`yiIuq?3Q!oKb6'cfi/yS@k{٩9x8u QF4Ò$@9΋0HŨso([\)%Vzf$6(k!,j~N,0Կ-ژ]qMUuF(-eȎؖGOsjkUEële_|y0;#,C[`.:@I5C+7kʒsfѨEh[LLrL}Oh"2
P2{J kx
;uNi]I[rhzb$Ԟ.95V"
p[
ƌ׆\[I	}^bJ^3>ACݛbѢvo;Z<=19*s7g,\6I2
6|LxR32R)^
rnDV^_5{(1	jIj%`;eC9Q%E37jO_f8wNC{Kё.ŐzIT?> 8FܹB_\:hޤ\>LVt>8n*UVVk"Er6
).pgueܾdT]F,Bh~x5XVɸFK@P<6+kōcPSz©?L4
ǂ	NP:dӀ(@WՖ/{P~Qi{Fu\EH;g(csT@r!JǔS-?@(W+}!FH:z5I3$Uٛ}1\c/,@k~*oɢő
C
yAB"G!*MA_,[VY*|AivI;UuxKw cԛ
,݀>{Q)BvЯ"t9Dra#dOqP7jr7MRkp Km{p3J
KX(CZ`tC/>sZ-i[W#g"@jaً	ʺTl>(n'1ڱ.Ȍ?Qp&m2Lta''w82	Xč^1!I!HTT.js52tflEq~o&
-V85j0$KY8.$TY7T5TI8$c?=(p|yJ%.xdk!Ő`eAӤR2MC #D}cH[VLN~OmՎNAz88zx挽"G+}L.~Io)|Șp	1VT"OZtsZ?^D`Rl-=
,tP$2b(hx7ӊ	"1lӃe:2L+DŽe?7249,;z[
oF37Y#εmSc1Fޅ
d[3;SXYEx4^yOFC	/O#<;l3ALX`԰8~MpDU s9ˇ,\/D`H)ARsTv8MN<!@f6DCO|m1DAb9ΐj$ȷJPCpLD(I9C
M`%No/`,|t,4-nXw(3┶;~JO'=km嫙6jJtִ\uLjOeali+N$3;*Y70/Yr?j-LK
fuB|~Tޭ͵GM+{wA^0\xP}հB$%^lcg#.
ƜC3_ꁉkXVMȔh6I֠$A)ӹdU\rU
=(Ym
ʌ>r&"+$=
mb۵$bԙtγ=h25jha>&ցI6iz
&bƃυǑh;erE12ǣ֥\W2,uNc"8U]C!9UEvx1Jp`cqEXTQ(_\n:,$WmX]^k1I#!=bm)Yźú|&u5('}_kv&^
MBqf\\FRqbs$DUe6EhBOg26sAvR9#sLlZ$̍m[D&WFFmX.;5]u9T<
qSxK+׭6tbtL7
AK#}d^s'NQa1|ӌy٣QΞ2+(ujwۉ%EGwp>=Irȇ]~JJ2NRTX2z^xtٌUHf'3:	IN-k/'JJQaFPtY6ꨓ0{i79vЯT/u#ʳsY/=לv^f:"թL*]JQabP3<hR먡:"R宣F5biQ,e屚!%uhat?,QfF#5oЌ%Ɍ8;iGX1Z|fut)~0(*Pc(*F!EʼnF0cCG (qpС„1cn̸qH	`!&
<XP `CH`
x.N	(*.h!J`p@( :)L50
h0
P(8@‰8 'Ȱ.aD`Ȑ
\* (@?$(*,De`*`
JBJa<
&B 
	(6L
ځJ&|LltFp.0PbJxJ |8`,A5h8
\hha8XhF8ɀ* !$6 a"!BpD,EX
X# h%T8aгf<PL(*"J	B@D`A/lT"@@@T "$PDY`$ z!X@B:<*toP(*0xtp!E:p"78`:T!B
@Ha.:hC8|YA
B7H9hAAqp@+|x8@V@A+|Ѐ$(*	L, A/p4
'pM0ɀD"\g*(C*l]C	@DP'&i`"\>,`@"DH! Jp!8`) X
 R3pn0/>F$Bp08(PB7PA\x.S054b&x0
@'1`(*6A
F!P.X!y ƒ	48aBLPAXd0T%L@%@ C!C1< c	 6A#EF	!8aBp8h6P Bb
.@<& .'İH lpB8+/`NÇ.7
	Dh,lB6xBpPL]؂D%(pAbR@9%:B@@Pa:`䁅B"Ph"HA,9L"	<h 'L@f
al `DA#JA1P# 0
Ip@k@DLBD0„^	>0MF(
6A4X`@ˆ<(T!^0PЀ"	>H	*`_ku2qT*[s)kem27^(*LhŒ̇MR,uTivg,̕(*,茕R474|Io$uv^\";[]ga!;W
~򏣴`
J[kn+azOcդǹRTXԔf2ro	Y}^ASʛU
|(Þw|?kg*oXXqV3.6KýbGQтNX$Ž/v%3۩ly2YӖp(h&rNU=ɤ0QxCS0+o<;qRT\PG
N^)֙JMIlwx4)4f)SDz|1)Ϥ9^2}rĚKMQMSUΕ~+߷K"J-M
QYسG[Z/	_gzS3s'FdtKgfMMvx{wtRU3/cNh>I<4[򼰰lo\#:o>xZs$bsŌrFja^hXUE5Ct3<iHwv4æU<7ȪcF)xFyI5G₢4vώl)*,D9T:ڈVSTXI;"!DjЪ:RXwb#kl?>"9:mJJmUv	Jff#ju+Z"GhE(َSVt|MSS/(*,dLQqaJdRSTX:1R<,7#E8{h~)4EŽgB3qtL-Df)Y,ՍT{QfI[1"cմdNQJY\]X(me<(JQ_I8#C180Ejk\sudj32V:5)\&w%=79id̘u+bhvZUyKP;Z}Mh׬;YH(3>NYҖ|;de;&b5Ksh.%aX%AIf!߁3WG1{\>)7YBǪ]1yu]xإjF#knhl~.qHxi^K/B|dY3vT.iVH7ISo Q	+B7q9wBf7[
m<uH\YBĢ̇~"tɎjNʒ:N#hmm	u!e˽RM=e:*_#dm_U犒#_$di͹\iUQl,Fw$X95%;ʮzYp5TG%H#KEQUojZ IkMi#j^Zd}ˁ67]kOdd=H]ӞY|
RIi\uB7euz[
<9GQaS~O<i)guuFQabXNϵr5JwW#,[d8#DÓutO^gB<An^|ecϣ9^ӓ?PQYGe~^NJ1U,4tiV>jyl5dAVt#&rAcFtx,&Ʈ=_](r	ԝGRot&?ф>/,֓rq`5}“{ܲس[T7ՓCM{ ZVsp:w*̈_I:;L(eN퐪SSuZ"&܃Ҩ3?Es6-_X,&
ЍQξ3Rkմqٚb%gKݪl:͝Qk
ږdNvAe2.=̉M=GT+m˰tIɡ>-_fkbMD4N
4f '6LJ_}Wˢ;;E=#aoV{:hb94.LG2hKkaߕR)Qp:~Ds\;
-qΓb1tM"9ΌMG2A=(g?LM]ƒy\D,?;zg;XcUILulȂ6wbEEF:~cCK\#9yr_f:AvX}'ZUݔ?D$c"4ޜ
:䫒{nVfIYӮ͚,d7#56W$hP^OgrR=&}$a݂wq7r%f]Ӳ?Ƀ~7Wn*a%bQ?5zɮ#2㵔YȞ+g
v^8fy3vYd5pfIiƆcrYoKʕ/-WKޢtDo%[%bTfͤkE{h%:URX3YN:;rGɟ{Pk8tt9<ttZtow.eryFM,I?5]MǑᑼ(*.g9wDɲYR4W7o9yGQTsaHqDT)l]Ͻe5$h$sIR#;2*QeҦYwieh?ʛZpJJ%fynt)f
e:|Uo<#FhK4Z83R6hz8bqfZ7<L:jxVb?] \U
Q(
CJk_bU{*\`Ю\#0<$bB4+	b7x>r8FX=+}YSɜ+~~XD5Kɜ{
.;ڹJ*0OYR毸1A+$NRoL	Q	4߱S^V|͘->ߔdEo"$8+hUn{{G?uVRgY4
L`
_ǵR-~P</Kx-ȞU<hg3B5h|(1:xV6t/j.A<;ɸKʚvT?[d@A2PTB	.HaN*T(N0P@	0@Q

X:A
鎄v篹lf.ÙqQM]I]s:C7̺2¡s̬8'qGcJl|36'kɢ~;!<ihDԗX/i#dVP!Y̸7$4ϳo,36%#ol>	o3yFCy8sgnEXg~[MoJqt8a>w=̚啲7fcwds[wsx6%"U߹CHU1.k=uQpФE.(7'=MXͩ/g0gf<W$+"#)ɬ^ڴ+4
]}_ɣ7&*\1LrUrڇfgcӔ²N<m<RDTTu8G-MTRC!~	M^`ևeb[zuJV!qaNtgJ*c9'+_:D4LA}E;OuY8
%=z{A2B)+̚^}=SחV=3Y8|*1Y3"OXg9TVՒIʍC;7sR%*^
վyF=4
Kz١i<~Ż6Mc?WrD2,;12+sf^L,/'
ezwr9jCǢcUnxZ;ه$&ue,[rzuY[8j#ڙcCTfc+t)QW~T+g߄pTfher>xr,/CGKHʩnaz|t
pPmT*<>z6M;ļhixe=‘UWZWX&.ݙmbS
(Ghr,XߩG7x!fY
ZU
Ӓ+A䏌A;?Μs*L=m5EYil7EϽjnj9q1g+O	(m\Ԭ34s	MjXfTϟG)e=4ù)܎Vʣs%HN*|ٝ݇GwvótU	N3_K6$tdɒ4#n'!O*˓mSs]fc1;YYO8whwއM3n8_Yչ2YIHUv%VEm6)՜ѯGIOK$9WOK4
+Ҳ̜y*:	~QEvNpPo;csMeY(K1R8k;C31)t.^EVh>%N%Zdc
"^T{Yre4묪dҷ4[i;4D	Nϓ9͢(/6L3Şƴ?iy$-,BSTcKFy@$	E!r m30GEQȖHBCA㐚B@ȀQ§?<r9nEʟꆼθaZnx8Qr闖QF$BGZUȝ8&@CˤHi$A}-j8֨ɸt(U{DF|Š06_Ӭv2RnS'70ʿOy<UXaȤc,U}f-OG”Yt@G*OÃz7$8-c3s|wh:Pv:j+ܡ}9
UHΐh~7A( #eh\c#aEμV}=hJ\Fx㖶<w$zS
<d󌚵~6I,I{("FI+@VQϋ!Oahc™&"K-ؐ5!j۵U*[:ꚣ"wT}b,@Aˡc% 8ixx$,x*z
97xd	p eMM:<qa%/OE#<NXmD<ZOGKHO::]Pc,Rb.$`'`
D	<i"$fNTh9#91ѾaonL'(lqV\xQ1D{<{~Ne	\:E4!p$Ԑ,A9<jkm[إ4`Gy,^`B|2ĠCp6o]v2y#>WjrR+LlCRˣȽBDVt}+[O:צ^mK!5	NKaJӜz=Zgz#u!^mQdu"A]bTZgvuͷl/DB%
FvSD3n8y2&!/%%nh-|˓jȱnmހ(MG!Qa=>J"6&H;9EkA)aPW8E;`]hQEExaQ=!KAtR6}Ma|IpCZ	މ0ˉZGY;asU+|0..#?d@KNuçS]mŐEKq8)Mޡj	$܉~(Rgb;id&zb^*t,GUzDNKy63>2*|24A!I+[?á]ƌnVQ/"8n-ʖJftJrzUB3BA+$u29Fr(~FNju5yw#5
Z* r0JW-Vx|ޢ5iuqq%bDMOT.kJ:;!.R+1X.~qF9t(
cӇ`=ZD]
&&L.gӓ3&˝D!<iЖE,#U}цkVq-Adͩ!eNewN +Qe%
ʫi[F_aXm]i#*l|]j_BghCs]-:;țVz/r\tڟ 3wa)C{=2ԲJ+b}"AqEheeC:˴w@%Xpo~4P=Z~
d?hB>{rGs<L>Z+hʞm8f
uH77zMWhe^oYVUzcu$%Oꔃо5.ϧԀY\`;yfʏc%8yck*wvH
$S;>yOĹaFd(AF/9	qg(x&x	{jiFx'۶hF}"k#_tRb{:QsDdħ=/17}>)Z	p\CE,[
'Kʠn{٨2c4*t<U݅9Yw_dٛ5afeOQW=X&
CgܗT?76rKt"2*=u4hPgifM[Te-]u: zn|Oɚ8:ێf
8Yp-, iuiZъT!S5Q;rK瘴Z+zH Ih
V0P|uJA,zW,lpC9R@tҩ"	sU\29]5|Mة\xЈR[^t<N2&qsnٶ9GkͳF98$2IBi
?2
#lb"F4ž8e1}gau2mhJaћ <`rgdWS:eă1S)+d"y	
wÆ!VȌH斓ƪe"ZT5(LmIT\ۺY{Ql‡B㳢z"اpDH:jK9\ȄEhK@/hEҫA_
xbj`:`0]I\Z˞YK:?U햿Z3?ߖ`esfks(Vg,"7,=@p- UPfGlreg-BsLS4DL=X 1{45bUϕ#ǎVҙcd0xSBTJ"0ЈE+[Si@閯#R2I~h&Q]TC+\_%Th+j΢TdءO~+=O$S]#;XG/ "ouPo7XÖX2|(gfJgzװLi%NH-_ȇqKL(6m+iΖeMH
)g{>VUBP;`*h6pXB^?Zx~,gz"Z+KI_zX
~dD~,t5?\wKFDg ?u-+7Ы"(A)aN?k(pԝRRwE^;]FUp}ߠeT2kE#@9bxN[Eo4;,,dqDa=,ns{XBhJ
s=I$sAϝV/;]Cn؝~'7<(7taSi[Q||+Ui[a( Οw0:QU&OrCX5_4ڃ.ac7x~n*:=UĎΝƪ)Z8b$ƙ{r_?GzE
wп1_}`~DVPc4}E7u\ujh9zXݮ_-ófp#@U
Dt<J(|].j(CfW/.K(Te4P 
9_?5ާϚM+*400]5w
`K-K$3rUX8Sp8}aYH9煄k|)u}ohqo+bFMUl62]%@vmfB3diQ y"ؤCO ngX*ee(O~5x)@Yٚάn&aH-:Owv*w7N6||PSNW6P'8["?P]|7]{ǧYrJJؗl7dZަGjy0W-u\6!ZA84+6W.zpOxgAD%%)dvljpkWCrUD#DX(.^PȬ_.><>{FC8^_#mC	 ą 
cSg=E]m@VmΕNfLJn
.x"cw~dSUHA	of4
;++y}85$ɮEefK!Bpz˰P6ps㈏諵18ɆIuA	C
8)Ģ\\VҭjNizR~hCMޮD&dP*;z;7<W#c&t$N5	"Mo^ҼLg3"MV!pyKp
ѷU3@c}g)nx/\,h 	:φZ&GQA@58JD/D#|>1:dzhҀ9kʚ4IV-ڦ;?n|C4jZ<Va74qLJRZRSrvH7ffpS6|4AO`iӠ2[ێM:VhibC򆑈kILW
F!Pj]hj
A4t+z7\|?vi@4YE<("O7GӴ!fX{{Pk27>Y/~W*$om>%HB ?ȵ,D
7t,'-sLXњz6i/YQD u}k:/&όIԤLo=+_BA@t
'+f0p~Fu3T'bF
-]ia],ǜ851%>Ec--|3/eƲ+,î2(+jƓe:8	/DD㌊ķT(,jR3U&xU'cλ
DwzzdPv.)Q
K
WQUz
E	 
sz

N]֔[[Ӎ教q߳הddϱn-
)d	/eM-Hq+5'KtB)fD=xd@c0eߵd1⫣h-OnjB@='*|QX%Ě@S[2M^
+*dGpzy\⪕*We[ie<g49Ǡ&CFFj:p<=<4|-@.i?`	"N4ª빡xJfffb
"CO4Ϩ1V".iPy,ɲhb؉{3Q!r8+e j@E["2*D95̿d#G)Lӣi@GhctIDۀӷP1q+XiW!_Q~xGl
endstream
endobj
19 0 obj
[18 0 R]
endobj
27 0 obj
<</CreationDate(D:20221115174608-04'00')/Creator(Adobe Illustrator 26.5 \(Windows\))/ModDate(D:20221115174608-05'00')/Producer(Adobe PDF library 16.07)/Title(connect-query)>>
endobj
xref
0 28
0000000004 65535 f
0000000016 00000 n
0000000147 00000 n
0000031392 00000 n
0000000000 00000 f
0000031443 00000 n
0000000000 00000 f
0000036465 00000 n
0000000000 00000 f
0000000000 00000 f
0000000000 00000 f
0000000000 00000 f
0000000000 00000 f
0000000000 00000 f
0000036538 00000 n
0000036679 00000 n
0000038208 00000 n
0000000000 00000 f
0000036165 00000 n
0000077176 00000 n
0000031797 00000 n
0000036352 00000 n
0000035233 00000 n
0000035603 00000 n
0000035651 00000 n
0000036236 00000 n
0000036267 00000 n
0000077201 00000 n
trailer
<</Size 28/Root 1 0 R/Info 27 0 R/ID[<6033E0CCD2B580498183EBFA38AF0F65><1C85417C8E6E7F45A66543808DE86DA0>]>>
startxref
77392
%%EOF


================================================
FILE: assets/connect-query_dependency_graph.excalidraw
================================================
{
  "type": "excalidraw",
  "version": 2,
  "source": "https://excalidraw.com",
  "elements": [
    {
      "type": "rectangle",
      "version": 338,
      "versionNonce": 2062451677,
      "isDeleted": false,
      "id": "XeSFIfHiUS6jxoqpDlWJf",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "dotted",
      "roughness": 0,
      "opacity": 100,
      "angle": 0,
      "x": 460.8332824707031,
      "y": 499.1667175292969,
      "strokeColor": "#000000",
      "backgroundColor": "#868e96",
      "width": 258,
      "height": 104.66665649414062,
      "seed": 922502867,
      "groupIds": [],
      "roundness": {
        "type": 3
      },
      "boundElements": [
        {
          "type": "text",
          "id": "nCL0iXpxT4jwwx2rTwPB8"
        },
        {
          "id": "KmuiK-MBdqr2GTx-Jkug_",
          "type": "arrow"
        }
      ],
      "updated": 1673457524342,
      "link": null,
      "locked": false
    },
    {
      "type": "text",
      "version": 281,
      "versionNonce": 922683517,
      "isDeleted": false,
      "id": "nCL0iXpxT4jwwx2rTwPB8",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 524.8332824707031,
      "y": 539.5000457763672,
      "strokeColor": "#000000",
      "backgroundColor": "transparent",
      "width": 130,
      "height": 24,
      "seed": 543194013,
      "groupIds": [],
      "roundness": null,
      "boundElements": null,
      "updated": 1673457516212,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 3,
      "text": "Connect-Web",
      "baseline": 19,
      "textAlign": "center",
      "verticalAlign": "middle",
      "containerId": "XeSFIfHiUS6jxoqpDlWJf",
      "originalText": "Connect-Web"
    },
    {
      "type": "rectangle",
      "version": 653,
      "versionNonce": 1196429683,
      "isDeleted": false,
      "id": "HdkWX-Z70zh5w9kpusrjy",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "angle": 0,
      "x": 900,
      "y": 780,
      "strokeColor": "#000000",
      "backgroundColor": "#228be6",
      "width": 258,
      "height": 104.66665649414062,
      "seed": 1886852829,
      "groupIds": [],
      "roundness": null,
      "boundElements": [
        {
          "type": "text",
          "id": "v4h5RDwi8qngLrgWkXvyY"
        },
        {
          "id": "gvjIhXtSYcnwYBZ2oDDpS",
          "type": "arrow"
        },
        {
          "id": "7wHm2jFQS6ITLYsjqcOU2",
          "type": "arrow"
        },
        {
          "id": "KmuiK-MBdqr2GTx-Jkug_",
          "type": "arrow"
        },
        {
          "id": "a_FVwdNlnqR-gZIKraQ74",
          "type": "arrow"
        },
        {
          "id": "FvGaYurosrW130jE07qnK",
          "type": "arrow"
        },
        {
          "id": "PAWB2iARdE5gRjLXwnX02",
          "type": "arrow"
        }
      ],
      "updated": 1673457529506,
      "link": null,
      "locked": false
    },
    {
      "type": "text",
      "version": 629,
      "versionNonce": 1087894771,
      "isDeleted": false,
      "id": "v4h5RDwi8qngLrgWkXvyY",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 917,
      "y": 820.3333282470703,
      "strokeColor": "#000000",
      "backgroundColor": "transparent",
      "width": 224,
      "height": 24,
      "seed": 224714451,
      "groupIds": [],
      "roundness": null,
      "boundElements": null,
      "updated": 1673456334543,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 3,
      "text": "Your Generated Code",
      "baseline": 19,
      "textAlign": "center",
      "verticalAlign": "middle",
      "containerId": "HdkWX-Z70zh5w9kpusrjy",
      "originalText": "Your Generated Code"
    },
    {
      "type": "rectangle",
      "version": 539,
      "versionNonce": 1221815059,
      "isDeleted": false,
      "id": "1QmxoknneXyizwjmTBfsW",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "angle": 0,
      "x": 900,
      "y": 1060,
      "strokeColor": "#000000",
      "backgroundColor": "#228be6",
      "width": 258,
      "height": 104.66665649414062,
      "seed": 579482429,
      "groupIds": [],
      "roundness": null,
      "boundElements": [
        {
          "type": "text",
          "id": "TqMtSvn1VfRhyRcNsGcbp"
        },
        {
          "id": "I_CLj4w8V5pobtEXl2Buj",
          "type": "arrow"
        },
        {
          "id": "7wHm2jFQS6ITLYsjqcOU2",
          "type": "arrow"
        }
      ],
      "updated": 1673457529506,
      "link": null,
      "locked": false
    },
    {
      "type": "text",
      "version": 524,
      "versionNonce": 512941715,
      "isDeleted": false,
      "id": "TqMtSvn1VfRhyRcNsGcbp",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 923,
      "y": 1100.3333282470703,
      "strokeColor": "#000000",
      "backgroundColor": "transparent",
      "width": 212,
      "height": 24,
      "seed": 1530453501,
      "groupIds": [],
      "roundness": null,
      "boundElements": null,
      "updated": 1673456334543,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 3,
      "text": "Your Frontend Code",
      "baseline": 19,
      "textAlign": "center",
      "verticalAlign": "middle",
      "containerId": "1QmxoknneXyizwjmTBfsW",
      "originalText": "Your Frontend Code"
    },
    {
      "type": "rectangle",
      "version": 453,
      "versionNonce": 629932093,
      "isDeleted": false,
      "id": "70r-ffCEpPw4jZ47fTXY6",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "dotted",
      "roughness": 0,
      "opacity": 100,
      "angle": 0,
      "x": 1340,
      "y": 220,
      "strokeColor": "#000000",
      "backgroundColor": "#868e96",
      "width": 258,
      "height": 104.66665649414062,
      "seed": 1410462835,
      "groupIds": [],
      "roundness": {
        "type": 3
      },
      "boundElements": [
        {
          "type": "text",
          "id": "zgjnIw46XBD2g0GOjB_qZ"
        },
        {
          "id": "pq6WADDyw4BOp77bAngzy",
          "type": "arrow"
        },
        {
          "id": "EUUJPfgFQLQKC9QmFn2Hj",
          "type": "arrow"
        }
      ],
      "updated": 1673457524342,
      "link": null,
      "locked": false
    },
    {
      "type": "text",
      "version": 401,
      "versionNonce": 75469875,
      "isDeleted": false,
      "id": "zgjnIw46XBD2g0GOjB_qZ",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 1404,
      "y": 260.3333282470703,
      "strokeColor": "#000000",
      "backgroundColor": "transparent",
      "width": 130,
      "height": 24,
      "seed": 825000477,
      "groupIds": [],
      "roundness": null,
      "boundElements": null,
      "updated": 1673456334543,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 3,
      "text": "Protobuf-ES",
      "baseline": 19,
      "textAlign": "center",
      "verticalAlign": "middle",
      "containerId": "70r-ffCEpPw4jZ47fTXY6",
      "originalText": "Protobuf-ES"
    },
    {
      "type": "rectangle",
      "version": 552,
      "versionNonce": 737865885,
      "isDeleted": false,
      "id": "lN_Z7SPGJvUJ1_qQgp_my",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "dotted",
      "roughness": 0,
      "opacity": 100,
      "angle": 0,
      "x": 900.8332824707031,
      "y": 499.1667175292969,
      "strokeColor": "#000000",
      "backgroundColor": "#868e96",
      "width": 258,
      "height": 104.66665649414062,
      "seed": 1231089171,
      "groupIds": [],
      "roundness": {
        "type": 3
      },
      "boundElements": [
        {
          "type": "text",
          "id": "6HsLOBS0-yHGej94R9uAN"
        },
        {
          "id": "gvjIhXtSYcnwYBZ2oDDpS",
          "type": "arrow"
        },
        {
          "id": "pq6WADDyw4BOp77bAngzy",
          "type": "arrow"
        },
        {
          "id": "FvGaYurosrW130jE07qnK",
          "type": "arrow"
        },
        {
          "id": "a_FVwdNlnqR-gZIKraQ74",
          "type": "arrow"
        },
        {
          "id": "EUUJPfgFQLQKC9QmFn2Hj",
          "type": "arrow"
        }
      ],
      "updated": 1673457524342,
      "link": null,
      "locked": false
    },
    {
      "type": "text",
      "version": 541,
      "versionNonce": 1575669053,
      "isDeleted": false,
      "id": "6HsLOBS0-yHGej94R9uAN",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 953.3332824707031,
      "y": 527.5000457763672,
      "strokeColor": "#000000",
      "backgroundColor": "transparent",
      "width": 153,
      "height": 48,
      "seed": 543020243,
      "groupIds": [],
      "roundness": null,
      "boundElements": null,
      "updated": 1673457516213,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 3,
      "text": "protoc-gen-\nconnect-query",
      "baseline": 43,
      "textAlign": "center",
      "verticalAlign": "middle",
      "containerId": "lN_Z7SPGJvUJ1_qQgp_my",
      "originalText": "protoc-gen-\nconnect-query"
    },
    {
      "type": "rectangle",
      "version": 537,
      "versionNonce": 2079118589,
      "isDeleted": false,
      "id": "IJST3a9MULbY3nKP5O-vj",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "dotted",
      "roughness": 0,
      "opacity": 100,
      "angle": 0,
      "x": 1340,
      "y": 780,
      "strokeColor": "#000000",
      "backgroundColor": "#868e96",
      "width": 258,
      "height": 104.66665649414062,
      "seed": 1507832755,
      "groupIds": [],
      "roundness": {
        "type": 3
      },
      "boundElements": [
        {
          "type": "text",
          "id": "pmTReKQQCE0eqd4B1ZO4t"
        },
        {
          "id": "I_CLj4w8V5pobtEXl2Buj",
          "type": "arrow"
        },
        {
          "id": "7wHm2jFQS6ITLYsjqcOU2",
          "type": "arrow"
        }
      ],
      "updated": 1673457524342,
      "link": null,
      "locked": false
    },
    {
      "type": "text",
      "version": 525,
      "versionNonce": 476151059,
      "isDeleted": false,
      "id": "pmTReKQQCE0eqd4B1ZO4t",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 1386.5,
      "y": 820.3333282470703,
      "strokeColor": "#000000",
      "backgroundColor": "transparent",
      "width": 165,
      "height": 24,
      "seed": 433861949,
      "groupIds": [],
      "roundness": null,
      "boundElements": null,
      "updated": 1673456334543,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 3,
      "text": "TanStack Query",
      "baseline": 19,
      "textAlign": "center",
      "verticalAlign": "middle",
      "containerId": "IJST3a9MULbY3nKP5O-vj",
      "originalText": "TanStack Query"
    },
    {
      "type": "arrow",
      "version": 404,
      "versionNonce": 1650651357,
      "isDeleted": false,
      "id": "KmuiK-MBdqr2GTx-Jkug_",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 737.6617093328613,
      "y": 609.239365369029,
      "strokeColor": "#1864ab",
      "backgroundColor": "transparent",
      "width": 152.24842287378317,
      "height": 159.87055354799793,
      "seed": 458946877,
      "groupIds": [],
      "roundness": null,
      "boundElements": [
        {
          "type": "text",
          "id": "LwfPx1xIn8ViH6r4EKaCf"
        }
      ],
      "updated": 1673457516212,
      "link": null,
      "locked": false,
      "startBinding": {
        "elementId": "XeSFIfHiUS6jxoqpDlWJf",
        "focus": -0.5197748421647741,
        "gap": 19.589139861980925
      },
      "endBinding": {
        "elementId": "HdkWX-Z70zh5w9kpusrjy",
        "focus": -0.4410732002860223,
        "gap": 14.845851207698502
      },
      "lastCommittedPoint": null,
      "startArrowhead": null,
      "endArrowhead": "arrow",
      "points": [
        [
          0,
          0
        ],
        [
          152.24842287378317,
          159.87055354799793
        ]
      ]
    },
    {
      "id": "LwfPx1xIn8ViH6r4EKaCf",
      "type": "text",
      "x": 758.6592881134363,
      "y": 675.748149562487,
      "width": 106,
      "height": 24,
      "angle": 0,
      "strokeColor": "#1864ab",
      "backgroundColor": "transparent",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "groupIds": [],
      "roundness": null,
      "seed": 1474013971,
      "version": 34,
      "versionNonce": 589494973,
      "isDeleted": false,
      "boundElements": null,
      "updated": 1673456334544,
      "link": null,
      "locked": false,
      "text": "Transport",
      "fontSize": 20,
      "fontFamily": 3,
      "textAlign": "center",
      "verticalAlign": "middle",
      "baseline": 19,
      "containerId": "KmuiK-MBdqr2GTx-Jkug_",
      "originalText": "Transport"
    },
    {
      "type": "arrow",
      "version": 123,
      "versionNonce": 1761090973,
      "isDeleted": false,
      "id": "gvjIhXtSYcnwYBZ2oDDpS",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 1021.2470991923436,
      "y": 618.9294060114771,
      "strokeColor": "#1864ab",
      "backgroundColor": "transparent",
      "width": 0.37181829465941973,
      "height": 140.83328247070312,
      "seed": 633861949,
      "groupIds": [],
      "roundness": null,
      "boundElements": [],
      "updated": 1673457516213,
      "link": null,
      "locked": false,
      "startBinding": {
        "elementId": "lN_Z7SPGJvUJ1_qQgp_my",
        "focus": 0.06439858402412948,
        "gap": 15.096031988039613
      },
      "endBinding": {
        "elementId": "HdkWX-Z70zh5w9kpusrjy",
        "focus": -0.06439858402412948,
        "gap": 20.237311517819762
      },
      "lastCommittedPoint": null,
      "startArrowhead": null,
      "endArrowhead": "arrow",
      "points": [
        [
          0,
          0
        ],
        [
          -0.37181829465941973,
          140.83328247070312
        ]
      ]
    },
    {
      "type": "arrow",
      "version": 426,
      "versionNonce": 1592209277,
      "isDeleted": false,
      "id": "I_CLj4w8V5pobtEXl2Buj",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 1323.7183536001407,
      "y": 896.2816463998595,
      "strokeColor": "#1864ab",
      "backgroundColor": "transparent",
      "width": 149.19417890388058,
      "height": 149.19417890388058,
      "seed": 699791827,
      "groupIds": [],
      "roundness": null,
      "boundElements": [
        {
          "type": "text",
          "id": "CUlnnQd_zqWGo4jP9YXIQ"
        }
      ],
      "updated": 1673456334544,
      "link": null,
      "locked": false,
      "startBinding": {
        "elementId": "IJST3a9MULbY3nKP5O-vj",
        "focus": 0.44852939629637206,
        "gap": 20
      },
      "endBinding": {
        "elementId": "1QmxoknneXyizwjmTBfsW",
        "focus": 0.4338235696294328,
        "gap": 22
      },
      "lastCommittedPoint": null,
      "startArrowhead": null,
      "endArrowhead": "arrow",
      "points": [
        [
          0,
          0
        ],
        [
          -149.19417890388058,
          149.19417890388058
        ]
      ]
    },
    {
      "id": "CUlnnQd_zqWGo4jP9YXIQ",
      "type": "text",
      "x": 1184.1212641482005,
      "y": 958.8787358517998,
      "width": 130,
      "height": 24,
      "angle": 0,
      "strokeColor": "#1864ab",
      "backgroundColor": "transparent",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "groupIds": [],
      "roundness": null,
      "seed": 1784188211,
      "version": 35,
      "versionNonce": 1241731795,
      "isDeleted": false,
      "boundElements": null,
      "updated": 1673456334544,
      "link": null,
      "locked": false,
      "text": "Query Logic",
      "fontSize": 20,
      "fontFamily": 3,
      "textAlign": "center",
      "verticalAlign": "middle",
      "baseline": 19,
      "containerId": "I_CLj4w8V5pobtEXl2Buj",
      "originalText": "Query Logic"
    },
    {
      "type": "arrow",
      "version": 347,
      "versionNonce": 173506675,
      "isDeleted": false,
      "id": "7wHm2jFQS6ITLYsjqcOU2",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 1020,
      "y": 900,
      "strokeColor": "#1864ab",
      "backgroundColor": "transparent",
      "width": 0,
      "height": 140,
      "seed": 84359645,
      "groupIds": [],
      "roundness": null,
      "boundElements": [
        {
          "type": "text",
          "id": "LHppZw4mGtiNgeBRWCQIc"
        }
      ],
      "updated": 1673456334544,
      "link": null,
      "locked": false,
      "startBinding": {
        "elementId": "HdkWX-Z70zh5w9kpusrjy",
        "focus": 0.06976744186046512,
        "gap": 15.333343505859375
      },
      "endBinding": {
        "elementId": "1QmxoknneXyizwjmTBfsW",
        "focus": -0.06976744186046512,
        "gap": 20
      },
      "lastCommittedPoint": null,
      "startArrowhead": null,
      "endArrowhead": "arrow",
      "points": [
        [
          0,
          0
        ],
        [
          0,
          140
        ]
      ]
    },
    {
      "id": "LHppZw4mGtiNgeBRWCQIc",
      "type": "text",
      "x": 943.5,
      "y": 958,
      "width": 153,
      "height": 24,
      "angle": 0,
      "strokeColor": "#1864ab",
      "backgroundColor": "transparent",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "groupIds": [],
      "roundness": null,
      "seed": 687336477,
      "version": 37,
      "versionNonce": 154481725,
      "isDeleted": false,
      "boundElements": null,
      "updated": 1673456334544,
      "link": null,
      "locked": false,
      "text": "Query Helpers",
      "fontSize": 20,
      "fontFamily": 3,
      "textAlign": "center",
      "verticalAlign": "middle",
      "baseline": 19,
      "containerId": "7wHm2jFQS6ITLYsjqcOU2",
      "originalText": "Query Helpers"
    },
    {
      "type": "arrow",
      "version": 1349,
      "versionNonce": 1522295293,
      "isDeleted": false,
      "id": "pq6WADDyw4BOp77bAngzy",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 1323.6385511190695,
      "y": 336.1689601989077,
      "strokeColor": "#1864ab",
      "backgroundColor": "transparent",
      "width": 148.31503045010072,
      "height": 148.4350637552135,
      "seed": 1060741971,
      "groupIds": [],
      "roundness": null,
      "boundElements": [],
      "updated": 1673457516213,
      "link": null,
      "locked": false,
      "startBinding": {
        "elementId": "70r-ffCEpPw4jZ47fTXY6",
        "focus": 0.44852939629637206,
        "gap": 20
      },
      "endBinding": {
        "elementId": "lN_Z7SPGJvUJ1_qQgp_my",
        "focus": 0.4338235696294328,
        "gap": 22
      },
      "lastCommittedPoint": null,
      "startArrowhead": null,
      "endArrowhead": "arrow",
      "points": [
        [
          0,
          0
        ],
        [
          -148.31503045010072,
          148.4350637552135
        ]
      ]
    },
    {
      "type": "rectangle",
      "version": 774,
      "versionNonce": 1357065565,
      "isDeleted": false,
      "id": "wmmX8X0PhUxG4APAQUfdA",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "dotted",
      "roughness": 0,
      "opacity": 100,
      "angle": 0,
      "x": 1340,
      "y": 500,
      "strokeColor": "#000000",
      "backgroundColor": "#868e96",
      "width": 258,
      "height": 104.66665649414062,
      "seed": 632603987,
      "groupIds": [],
      "roundness": {
        "type": 3
      },
      "boundElements": [
        {
          "type": "text",
          "id": "o8v54ziV3hNiqpchzZcem"
        },
        {
          "id": "FvGaYurosrW130jE07qnK",
          "type": "arrow"
        },
        {
          "id": "-w3ngGHZOH7S7mmdmHwqP",
          "type": "arrow"
        },
        {
          "id": "EUUJPfgFQLQKC9QmFn2Hj",
          "type": "arrow"
        }
      ],
      "updated": 1673457524342,
      "link": null,
      "locked": false
    },
    {
      "type": "text",
      "version": 773,
      "versionNonce": 1171851517,
      "isDeleted": false,
      "id": "o8v54ziV3hNiqpchzZcem",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 1404,
      "y": 528.3333282470703,
      "strokeColor": "#000000",
      "backgroundColor": "transparent",
      "width": 130,
      "height": 48,
      "seed": 1027074227,
      "groupIds": [],
      "roundness": null,
      "boundElements": null,
      "updated": 1673456334544,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 3,
      "text": "protoc-gen-\nes",
      "baseline": 43,
      "textAlign": "center",
      "verticalAlign": "middle",
      "containerId": "wmmX8X0PhUxG4APAQUfdA",
      "originalText": "protoc-gen-\nes"
    },
    {
      "type": "arrow",
      "version": 1343,
      "versionNonce": 1725288787,
      "isDeleted": false,
      "id": "FvGaYurosrW130jE07qnK",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 1320,
      "y": 620,
      "strokeColor": "#1864ab",
      "backgroundColor": "transparent",
      "width": 140,
      "height": 140,
      "seed": 814557597,
      "groupIds": [],
      "roundness": null,
      "boundElements": [],
      "updated": 1673456334544,
      "link": null,
      "locked": false,
      "startBinding": {
        "elementId": "wmmX8X0PhUxG4APAQUfdA",
        "focus": 0.44852939629637206,
        "gap": 20
      },
      "endBinding": {
        "elementId": "HdkWX-Z70zh5w9kpusrjy",
        "focus": 0.4338235696294328,
        "gap": 22
      },
      "lastCommittedPoint": null,
      "startArrowhead": null,
      "endArrowhead": "arrow",
      "points": [
        [
          0,
          0
        ],
        [
          -140,
          140
        ]
      ]
    },
    {
      "type": "rectangle",
      "version": 735,
      "versionNonce": 2049931709,
      "isDeleted": false,
      "id": "NLMbxwdPMz1O8gu8ku7cT",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "dotted",
      "roughness": 0,
      "opacity": 100,
      "angle": 0,
      "x": 460,
      "y": 640,
      "strokeColor": "#000000",
      "backgroundColor": "#868e96",
      "width": 258,
      "height": 104.66665649414062,
      "seed": 70689523,
      "groupIds": [],
      "roundness": {
        "type": 3
      },
      "boundElements": [
        {
          "type": "text",
          "id": "FKPW0XXW-xf9J70NAgjEI"
        },
        {
          "id": "PAWB2iARdE5gRjLXwnX02",
          "type": "arrow"
        }
      ],
      "updated": 1673457524342,
      "link": null,
      "locked": false
    },
    {
      "type": "text",
      "version": 700,
      "versionNonce": 899591613,
      "isDeleted": false,
      "id": "FKPW0XXW-xf9J70NAgjEI",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 512.5,
      "y": 680.3333282470703,
      "strokeColor": "#000000",
      "backgroundColor": "transparent",
      "width": 153,
      "height": 24,
      "seed": 808891261,
      "groupIds": [],
      "roundness": null,
      "boundElements": null,
      "updated": 1673456334544,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 3,
      "text": "Connect-Query",
      "baseline": 19,
      "textAlign": "center",
      "verticalAlign": "middle",
      "containerId": "NLMbxwdPMz1O8gu8ku7cT",
      "originalText": "Connect-Query"
    },
    {
      "type": "rectangle",
      "version": 840,
      "versionNonce": 536514739,
      "isDeleted": false,
      "id": "58DCEeIe5AGFChCK8Lm0R",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "angle": 0,
      "x": 900,
      "y": 220,
      "strokeColor": "#000000",
      "backgroundColor": "#228be6",
      "width": 258,
      "height": 104.66665649414062,
      "seed": 1891287965,
      "groupIds": [],
      "roundness": null,
      "boundElements": [
        {
          "type": "text",
          "id": "vIDwM655KULSinXrVbpHD"
        },
        {
          "id": "a_FVwdNlnqR-gZIKraQ74",
          "type": "arrow"
        },
        {
          "id": "-w3ngGHZOH7S7mmdmHwqP",
          "type": "arrow"
        }
      ],
      "updated": 1673457529506,
      "link": null,
      "locked": false
    },
    {
      "type": "text",
      "version": 827,
      "versionNonce": 1348202013,
      "isDeleted": false,
      "id": "vIDwM655KULSinXrVbpHD",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 946.5,
      "y": 260.3333282470703,
      "strokeColor": "#000000",
      "backgroundColor": "transparent",
      "width": 165,
      "height": 24,
      "seed": 1728515901,
      "groupIds": [],
      "roundness": null,
      "boundElements": null,
      "updated": 1673456334544,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 3,
      "text": "Your Protofile",
      "baseline": 19,
      "textAlign": "center",
      "verticalAlign": "middle",
      "containerId": "58DCEeIe5AGFChCK8Lm0R",
      "originalText": "Your Protofile"
    },
    {
      "id": "a_FVwdNlnqR-gZIKraQ74",
      "type": "arrow",
      "x": 1020,
      "y": 339.1666793823242,
      "width": 0.5369143190519026,
      "height": 139.16671752929688,
      "angle": 0,
      "strokeColor": "#1864ab",
      "backgroundColor": "#ced4da",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "groupIds": [],
      "roundness": {
        "type": 2
      },
      "seed": 1769855859,
      "version": 697,
      "versionNonce": 674830941,
      "isDeleted": false,
      "boundElements": [],
      "updated": 1673457516213,
      "link": null,
      "locked": false,
      "points": [
        [
          0,
          0
        ],
        [
          0.5369143190519026,
          139.16671752929688
        ]
      ],
      "lastCommittedPoint": null,
      "startBinding": {
        "elementId": "58DCEeIe5AGFChCK8Lm0R",
        "focus": 0.06976744186046512,
        "gap": 14.500022888183594
      },
      "endBinding": {
        "elementId": "lN_Z7SPGJvUJ1_qQgp_my",
        "focus": -0.06976744186046512,
        "gap": 20.83332061767578
      },
      "startArrowhead": null,
      "endArrowhead": "arrow"
    },
    {
      "type": "rectangle",
      "version": 387,
      "versionNonce": 1626552861,
      "isDeleted": false,
      "id": "8A9Hj-N3wkhESFIv5cuO9",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "dotted",
      "roughness": 0,
      "opacity": 100,
      "angle": 0,
      "x": 460,
      "y": 1060,
      "strokeColor": "#000000",
      "backgroundColor": "#868e96",
      "width": 160,
      "height": 40,
      "seed": 501992595,
      "groupIds": [],
      "roundness": {
        "type": 3
      },
      "boundElements": [
        {
          "type": "text",
          "id": "xtKa4RSXNkP5YhJ4M_VYx"
        }
      ],
      "updated": 1673457524342,
      "link": null,
      "locked": false
    },
    {
      "type": "text",
      "version": 339,
      "versionNonce": 582969149,
      "isDeleted": false,
      "id": "xtKa4RSXNkP5YhJ4M_VYx",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 475,
      "y": 1068,
      "strokeColor": "#000000",
      "backgroundColor": "transparent",
      "width": 130,
      "height": 24,
      "seed": 1601738291,
      "groupIds": [],
      "roundness": null,
      "boundElements": null,
      "updated": 1673456334544,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 3,
      "text": "npm package",
      "baseline": 19,
      "textAlign": "center",
      "verticalAlign": "middle",
      "containerId": "8A9Hj-N3wkhESFIv5cuO9",
      "originalText": "npm package"
    },
    {
      "type": "rectangle",
      "version": 692,
      "versionNonce": 2025551635,
      "isDeleted": false,
      "id": "kl6tzqBN_O2oPLMieESou",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 460,
      "y": 1120,
      "strokeColor": "#000000",
      "backgroundColor": "#228be6",
      "width": 160,
      "height": 40,
      "seed": 314591827,
      "groupIds": [],
      "roundness": null,
      "boundElements": [
        {
          "type": "text",
          "id": "uJxuk7GZFFnxpY8yy_bUC"
        }
      ],
      "updated": 1673456334544,
      "link": null,
      "locked": false
    },
    {
      "type": "text",
      "version": 683,
      "versionNonce": 472479645,
      "isDeleted": false,
      "id": "uJxuk7GZFFnxpY8yy_bUC",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 475,
      "y": 1128,
      "strokeColor": "#000000",
      "backgroundColor": "transparent",
      "width": 130,
      "height": 24,
      "seed": 805206109,
      "groupIds": [],
      "roundness": null,
      "boundElements": null,
      "updated": 1673456334544,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 3,
      "text": "source code",
      "baseline": 19,
      "textAlign": "center",
      "verticalAlign": "middle",
      "containerId": "kl6tzqBN_O2oPLMieESou",
      "originalText": "source code"
    },
    {
      "type": "arrow",
      "version": 550,
      "versionNonce": 788602035,
      "isDeleted": false,
      "id": "PAWB2iARdE5gRjLXwnX02",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 731.2059132037748,
      "y": 750.780397087813,
      "strokeColor": "#1864ab",
      "backgroundColor": "transparent",
      "width": 148.7940867962252,
      "height": 89.21960291218704,
      "seed": 890429011,
      "groupIds": [],
      "roundness": null,
      "boundElements": [
        {
          "type": "text",
          "id": "WRx0CxczbENMaHeXeBTVU"
        }
      ],
      "updated": 1673456334545,
      "link": null,
      "locked": false,
      "startBinding": {
        "elementId": "NLMbxwdPMz1O8gu8ku7cT",
        "focus": -0.20682688999780358,
        "gap": 14.552455723772255
      },
      "endBinding": {
        "elementId": "HdkWX-Z70zh5w9kpusrjy",
        "focus": -0.7480468885848,
        "gap": 20
      },
      "lastCommittedPoint": null,
      "startArrowhead": null,
      "endArrowhead": "arrow",
      "points": [
        [
          0,
          0
        ],
        [
          148.7940867962252,
          89.21960291218704
        ]
      ]
    },
    {
      "type": "text",
      "version": 40,
      "versionNonce": 313687037,
      "isDeleted": false,
      "id": "WRx0CxczbENMaHeXeBTVU",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 775.6029566018874,
      "y": 783.3901985439065,
      "strokeColor": "#1864ab",
      "backgroundColor": "transparent",
      "width": 60,
      "height": 24,
      "seed": 13575261,
      "groupIds": [],
      "roundness": null,
      "boundElements": null,
      "updated": 1673456334545,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 3,
      "text": "hooks",
      "baseline": 19,
      "textAlign": "center",
      "verticalAlign": "middle",
      "containerId": "PAWB2iARdE5gRjLXwnX02",
      "originalText": "hooks"
    },
    {
      "type": "arrow",
      "version": 1336,
      "versionNonce": 79760979,
      "isDeleted": false,
      "id": "-w3ngGHZOH7S7mmdmHwqP",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 1180,
      "y": 339.1666793823242,
      "strokeColor": "#1864ab",
      "backgroundColor": "#ced4da",
      "width": 140,
      "height": 140,
      "seed": 417848861,
      "groupIds": [],
      "roundness": {
        "type": 2
      },
      "boundElements": null,
      "updated": 1673456334545,
      "link": null,
      "locked": false,
      "startBinding": {
        "elementId": "58DCEeIe5AGFChCK8Lm0R",
        "focus": -0.46415432661152806,
        "gap": 22
      },
      "endBinding": {
        "elementId": "wmmX8X0PhUxG4APAQUfdA",
        "focus": -0.41819863931427675,
        "gap": 20.83332061767578
      },
      "lastCommittedPoint": null,
      "startArrowhead": null,
      "endArrowhead": "arrow",
      "points": [
        [
          0,
          0
        ],
        [
          140,
          140
        ]
      ]
    },
    {
      "type": "arrow",
      "version": 1996,
      "versionNonce": 993645971,
      "isDeleted": false,
      "id": "EUUJPfgFQLQKC9QmFn2Hj",
      "fillStyle": "hachure",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 1,
      "opacity": 100,
      "angle": 0,
      "x": 1460,
      "y": 340,
      "strokeColor": "#1864ab",
      "backgroundColor": "transparent",
      "width": 0,
      "height": 140,
      "seed": 795421171,
      "groupIds": [],
      "roundness": null,
      "boundElements": [],
      "updated": 1673456334545,
      "link": null,
      "locked": false,
      "startBinding": {
        "elementId": "70r-ffCEpPw4jZ47fTXY6",
        "focus": 0.06976744186046512,
        "gap": 15.333343505859375
      },
      "endBinding": {
        "elementId": "wmmX8X0PhUxG4APAQUfdA",
        "focus": -0.06976744186046512,
        "gap": 20
      },
      "lastCommittedPoint": null,
      "startArrowhead": null,
      "endArrowhead": "arrow",
      "points": [
        [
          0,
          0
        ],
        [
          0,
          140
        ]
      ]
    }
  ],
  "appState": {
    "gridSize": null,
    "viewBackgroundColor": "#ffffff"
  },
  "files": {}
}

================================================
FILE: cspell.config.json
================================================
{
  "words": [
    "Deno",
    "Dimitri",
    "Mitropoulos",
    "Quickstart",
    "Stamm",
    "Timo",
    "Vindaloo",
    "Weizenbaum's",
    "attw",
    "backoffs",
    "bufbuild",
    "codegen",
    "connectquery",
    "connectrpc",
    "connectweb",
    "descriptorset",
    "excalidraw",
    "idempotence",
    "idempotency",
    "inferencing",
    "invalidators",
    "keyof",
    "lcov",
    "nocheck",
    "pnpm",
    "preconfigured",
    "proto",
    "protobuf",
    "protoc",
    "protofile",
    "protoplugin",
    "tanstack",
    "todos",
    "tsdoc",
    "corepack",
    "printables",
    "arethetypeswrong",
    "oneof",
    "typesafe",
    "setversion",
    "getversion",
    "postsetversion",
    "postgenerate",
    "npmjs"
  ],
  "ignorePaths": [
    "**/*.svg",
    "**/*.ai",
    "**/pnpm-lock.yaml",
    "*.excalidraw",
    "**/gen",
    "**/snapshots",
    "**/*.css",
    "**/*.xml",
    "**/tsconfig.vitest-temp.json"
  ]
}


================================================
FILE: package.json
================================================
{
  "private": true,
  "name": "root",
  "type": "module",
  "workspaces": [
    "packages/connect-query-core",
    "packages/connect-query",
    "packages/examples/react/basic",
    "packages/protoc-gen-connect-query",
    "packages/test-utils"
  ],
  "scripts": {
    "all": "turbo run --ui tui build format test lint attw license-header",
    "clean": "git clean -Xdf",
    "setversion": "node scripts/set-workspace-version.js",
    "getversion": "node scripts/find-workspace-version.js",
    "postsetversion": "npm run all",
    "release": "node scripts/release.js",
    "prerelease": "npm run all",
    "format": "prettier --write --ignore-unknown '.' '!packages' '!.turbo' '!node_modules'",
    "license-header": "license-header --ignore 'packages/**'",
    "lint": "eslint --max-warnings 0 . --ignore-pattern 'packages/**' && npm run check:spelling",
    "check:spelling": "cspell \"**\" --gitignore"
  },
  "packageManager": "npm@10.1.0",
  "licenseHeader": {
    "licenseType": "apache",
    "yearRange": "2021-2023",
    "copyrightHolder": "The Connect Authors"
  },
  "devDependencies": {
    "@bufbuild/license-header": "^0.0.4",
    "@types/node": "^22.15.29",
    "@typescript-eslint/eslint-plugin": "8.33.0",
    "@typescript-eslint/parser": "8.33.0",
    "@typescript-eslint/utils": "8.33.0",
    "@vitest/ui": "^3.2.4",
    "cspell": "9.0.2",
    "eslint": "8.57.0",
    "eslint-config-prettier": "10.1.5",
    "eslint-import-resolver-typescript": "^4.4.2",
    "eslint-plugin-eslint-comments": "3.2.0",
    "eslint-plugin-import": "^2.29.1",
    "eslint-plugin-n": "^17.18.0",
    "eslint-plugin-react-hooks": "^5.2.0",
    "eslint-plugin-simple-import-sort": "^12.1.1",
    "eslint-plugin-vitest": "0.5.4",
    "prettier": "3.5.3",
    "turbo": "^2.5.4",
    "typescript": "5.8.3",
    "vitest": "^3.2.4"
  },
  "engineStrict": true,
  "engines": {
    "node": ">=20",
    "npm": ">=10.8"
  }
}


================================================
FILE: packages/connect-query/README.md
================================================
# @connectrpc/connect-query

This is the runtime library package for Connect-Query. You'll find its code generator at [@connectrpc/protoc-gen-connect-query](https://www.npmjs.com/package/@connectrpc/protoc-gen-connect-query).

Connect-Query is a wrapper around [TanStack Query](https://tanstack.com/query) (react-query), written in TypeScript and thoroughly tested. It enables effortless communication with servers that speak the [Connect Protocol](https://connectrpc.com/docs/protocol).

To get started, head over to the [docs](https://github.com/connectrpc/connect-query-es) for a tutorial, or take a look at [our examples](https://github.com/connectrpc/connect-query-es/tree/main/examples).


================================================
FILE: packages/connect-query/package.json
================================================
{
  "name": "@connectrpc/connect-query",
  "version": "2.2.0",
  "description": "TypeScript-first expansion pack for TanStack Query that gives you Protobuf superpowers.",
  "license": "Apache-2.0",
  "repository": {
    "type": "git",
    "url": "https://github.com/connectrpc/connect-query-es.git",
    "directory": "packages/connect-query"
  },
  "scripts": {
    "prebuild": "rm -rf ./dist/*",
    "build": "npm run build:cjs && npm run build:esm",
    "build:cjs": "tsc --project tsconfig.build.json --module commonjs --verbatimModuleSyntax false --moduleResolution node10 --outDir ./dist/cjs --declaration --declarationDir ./dist/cjs && echo >./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
    "build:esm": "tsc --project tsconfig.build.json --outDir ./dist/esm --declaration --declarationDir ./dist/esm",
    "test": "vitest --run",
    "test:watch": "vitest --watch",
    "format": "prettier --write --ignore-unknown '.' '!dist'",
    "license-header": "license-header",
    "lint": "eslint --max-warnings 0 .",
    "attw": "attw --pack"
  },
  "type": "module",
  "sideEffects": false,
  "main": "./dist/cjs/index.js",
  "exports": {
    ".": {
      "import": "./dist/esm/index.js",
      "require": "./dist/cjs/index.js"
    }
  },
  "dependencies": {
    "@connectrpc/connect-query-core": "^2.2.0"
  },
  "devDependencies": {
    "@arethetypeswrong/cli": "^0.18.1",
    "@bufbuild/buf": "1.54.0",
    "@bufbuild/jest-environment-jsdom": "^0.1.1",
    "@bufbuild/protobuf": "^2.5.1",
    "@bufbuild/protoc-gen-es": "^2.5.1",
    "@connectrpc/connect": "^2.0.2",
    "@connectrpc/connect-web": "^2.0.2",
    "@tanstack/react-query": "^5.79.0",
    "@testing-library/react": "^16.3.0",
    "@types/react": "^19.1.6",
    "@types/react-dom": "^19.1.5",
    "react": "^19.1.0",
    "react-dom": "^19.1.0",
    "test-utils": "*",
    "typescript": "^5.8.3"
  },
  "peerDependencies": {
    "@bufbuild/protobuf": "2.x",
    "@connectrpc/connect": "^2.0.1",
    "@tanstack/react-query": ">=5.62.0",
    "react": "^18 || ^19",
    "react-dom": "^18 || ^19"
  },
  "files": [
    "dist/**"
  ]
}


================================================
FILE: packages/connect-query/src/call-unary-method.test.ts
================================================
// Copyright 2021-2023 The Connect Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { create } from "@bufbuild/protobuf";
import type { ConnectQueryKey } from "@connectrpc/connect-query-core";
import {
  callUnaryMethod,
  createConnectQueryKey,
} from "@connectrpc/connect-query-core";
import type { QueryFunctionContext } from "@tanstack/react-query";
import { useQueries } from "@tanstack/react-query";
import { renderHook, waitFor } from "@testing-library/react";
import { mockEliza } from "test-utils";
import type { SayRequest } from "test-utils/gen/eliza_pb.js";
import { ElizaService, SayRequestSchema } from "test-utils/gen/eliza_pb.js";
import { describe, expect, it } from "vitest";

import { wrapper } from "./test/test-wrapper.js";

describe("callUnaryMethod", () => {
  it("can be used with useQueries", async () => {
    const transport = mockEliza({
      sentence: "Response 1",
    });
    const { result } = renderHook(() => {
      const input: SayRequest = create(SayRequestSchema, {
        sentence: "query 1",
      });
      const [query1] = useQueries({
        queries: [
          {
            queryKey: createConnectQueryKey({
              schema: ElizaService.method.say,
              input,
              transport,
              cardinality: "finite",
            }),
            queryFn: async ({
              signal,
            }: QueryFunctionContext<ConnectQueryKey>) => {
              const res = await callUnaryMethod(
                transport,
                ElizaService.method.say,
                input,
                {
                  signal,
                },
              );
              return res;
            },
          },
        ],
      });
      return {
        query1,
      };
    }, wrapper());

    await waitFor(() => {
      expect(result.current.query1.isSuccess).toBeTruthy();
    });
    expect(result.current.query1.data?.sentence).toEqual("Response 1");
  });
  it("can pass headers through", async () => {
    let resolve: () => void;
    const promise = new Promise<void>((res) => {
      resolve = res;
    });
    const transport = mockEliza(
      {
        sentence: "Response 1",
      },
      false,
      {
        router: {
          interceptors: [
            (next) => (req) => {
              expect(req.header.get("x-custom-header")).toEqual("custom-value");
              resolve();
              return next(req);
            },
          ],
        },
      },
    );
    const input: SayRequest = create(SayRequestSchema, {
      sentence: "query 1",
    });
    const res = await callUnaryMethod(
      transport,
      ElizaService.method.say,
      input,
      {
        headers: {
          "x-custom-header": "custom-value",
        },
      },
    );
    await promise;
    expect(res.sentence).toEqual("Response 1");
  });
});


================================================
FILE: packages/connect-query/src/index.ts
================================================
// Copyright 2021-2023 The Connect Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

export * from "@connectrpc/connect-query-core";
export { useTransport, TransportProvider } from "./use-transport.js";
export {
  useInfiniteQuery,
  useSuspenseInfiniteQuery,
} from "./use-infinite-query.js";
export { useQuery, useSuspenseQuery } from "./use-query.js";
export type { UseMutationOptions } from "./use-mutation.js";
export { useMutation } from "./use-mutation.js";
export type { UseInfiniteQueryOptions } from "./use-infinite-query.js";
export type { UseQueryOptions } from "./use-query.js";


================================================
FILE: packages/connect-query/src/test/test-wrapper.tsx
================================================
// Copyright 2021-2023 The Connect Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import type { Transport } from "@connectrpc/connect";
import { createConnectTransport } from "@connectrpc/connect-web";
import type { QueryClientConfig } from "@tanstack/react-query";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import type { JSXElementConstructor, PropsWithChildren } from "react";

import { TransportProvider } from "../use-transport.js";

/**
 * A utils wrapper that supplies Tanstack Query's `QueryClientProvider` as well as Connect-Query's `TransportProvider`.
 */
export const wrapper = (
  config?: QueryClientConfig,
  transport = createConnectTransport({
    baseUrl: "https://demo.connectrpc.com",
  }),
): {
  wrapper: JSXElementConstructor<PropsWithChildren>;
  queryClient: QueryClient;
  transport: Transport;
  queryClientWrapper: JSXElementConstructor<PropsWithChildren>;
} => {
  const queryClient = new QueryClient(config);
  return {
    wrapper: ({ children }) => (
      <TransportProvider transport={transport}>
        <QueryClientProvider client={queryClient}>
          {children}
        </QueryClientProvider>
      </TransportProvider>
    ),
    queryClient,
    transport,
    queryClientWrapper: ({ children }) => (
      <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
    ),
  };
};


================================================
FILE: packages/connect-query/src/use-infinite-query.test.ts
================================================
// Copyright 2021-2023 The Connect Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { create } from "@bufbuild/protobuf";
import { createConnectQueryKey } from "@connectrpc/connect-query-core";
import { QueryCache, skipToken } from "@tanstack/react-query";
import { renderHook, waitFor } from "@testing-library/react";
import {
  mockNestedPaginatedTransport,
  mockPaginatedTransport,
} from "test-utils";
import {
  ListRequestSchema,
  ListResponseSchema,
  ListService,
} from "test-utils/gen/list_pb.js";
import { describe, expect, it, vi } from "vitest";

import { wrapper } from "./test/test-wrapper.js";
import {
  useInfiniteQuery,
  useSuspenseInfiniteQuery,
} from "./use-infinite-query.js";
import { useQuery } from "./use-query.js";

// TODO: maybe create a helper to take a service and method and generate this.
const methodDescriptor = ListService.method.list;
const nestedMethodDescriptor = ListService.method.nestedList;

const mockedPaginatedTransport = mockPaginatedTransport();
const mockedNestedPaginatedTransport = mockNestedPaginatedTransport();

describe("useInfiniteQuery", () => {
  it("can query paginated data", async () => {
    const { result } = renderHook(
      () => {
        return useInfiniteQuery(
          methodDescriptor,
          {
            page: 0n,
          },
          {
            getNextPageParam: (lastPage) => lastPage.page + 1n,
            pageParamKey: "page",
          },
        );
      },
      wrapper({}, mockedPaginatedTransport),
    );

    await waitFor(() => {
      expect(result.current.isSuccess).toBeTruthy();
    });
    expect(result.current.data).toEqual({
      pageParams: [0n],
      pages: [
        create(ListResponseSchema, {
          items: ["-2 Item", "-1 Item", "0 Item"],
          page: 0n,
        }),
      ],
    });

    await result.current.fetchNextPage();

    await waitFor(() => {
      expect(result.current.isFetching).toBeFalsy();
    });

    expect(result.current.data).toEqual({
      pageParams: [0n, 1n],
      pages: [
        create(ListResponseSchema, {
          items: ["-2 Item", "-1 Item", "0 Item"],
          page: 0n,
        }),
        create(ListResponseSchema, {
          items: ["1 Item", "2 Item", "3 Item"],
          page: 1n,
        }),
      ],
    });
  });

  it("can be disabled with skipToken", () => {
    const { result } = renderHook(
      () => {
        return useInfiniteQuery(methodDescriptor, skipToken, {
          getNextPageParam: (lastPage) => lastPage.page + 1n,
          pageParamKey: "page",
        });
      },
      wrapper(undefined, mockedPaginatedTransport),
    );
    expect(result.current.isPending).toBeTruthy();
    expect(result.current.isFetching).toBeFalsy();
  });

  it("can be provided a custom transport", async () => {
    const customTransport = mockPaginatedTransport({
      items: ["Intercepted!"],
      page: 0n,
    });
    const { result } = renderHook(
      () => {
        return useInfiniteQuery(
          methodDescriptor,
          {
            page: 0n,
          },
          {
            getNextPageParam: (lastPage) => lastPage.page + 1n,
            pageParamKey: "page",
            transport: customTransport,
          },
        );
      },
      wrapper({}, mockedPaginatedTransport),
    );
    await waitFor(() => {
      expect(result.current.isSuccess).toBeTruthy();
    });

    expect(result.current.data?.pages[0].items).toEqual(["Intercepted!"]);
  });

  it("can be provided other props for react-query", () => {
    const { result } = renderHook(
      () => {
        return useInfiniteQuery(
          methodDescriptor,
          {
            page: 0n,
          },
          {
            getNextPageParam: (lastPage) => lastPage.page + 1n,
            pageParamKey: "page",
            transport: mockPaginatedTransport(undefined, true),
            placeholderData: {
              pageParams: [-1n],
              pages: [
                create(methodDescriptor.output, {
                  page: -1n,
                  items: [],
                }),
              ],
            },
          },
        );
      },
      wrapper({}, mockedPaginatedTransport),
    );
    expect(result.current.data?.pages[0].page).toEqual(-1n);
  });

  it("can be used along with the select", async () => {
    const { result } = renderHook(
      () => {
        return useInfiniteQuery(
          methodDescriptor,
          {
            page: 0n,
          },
          {
            select: ({ pages, pageParams }) => ({
              pages: pages.map((p) => p.items.join(",")),
              pageParams: pageParams.map((p) => p?.toString()),
            }),
            getNextPageParam: (lastPage) => lastPage.page + 1n,
            pageParamKey: "page",
          },
        );
      },
      wrapper({}, mockedPaginatedTransport),
    );

    await waitFor(() => {
      expect(result.current.isSuccess).toBeTruthy();
    });
    expect(result.current.data).toEqual({
      pageParams: ["0"],
      pages: ["-2 Item,-1 Item,0 Item"],
    });

    await result.current.fetchNextPage();

    await waitFor(() => {
      expect(result.current.isFetching).toBeFalsy();
    });
    expect(result.current.data).toEqual({
      pageParams: ["0", "1"],
      pages: ["-2 Item,-1 Item,0 Item", "1 Item,2 Item,3 Item"],
    });
  });

  it("page param doesn't persist to the query cache", async () => {
    const { queryClient, ...remainingWrapper } = wrapper(
      {},
      mockedPaginatedTransport,
    );
    const { result } = renderHook(() => {
      return useInfiniteQuery(
        methodDescriptor,
        {
          page: 0n,
        },
        {
          getNextPageParam: (lastPage) => lastPage.page + 1n,
          pageParamKey: "page",
        },
      );
    }, remainingWrapper);

    const cache = queryClient.getQueryCache().getAll();

    expect(cache).toHaveLength(1);
    expect(cache[0].queryKey).toEqual(
      createConnectQueryKey({
        schema: methodDescriptor,
        transport: mockedPaginatedTransport,
        cardinality: "infinite",
        pageParamKey: "page",
        input: {},
      }),
    );

    await waitFor(() => {
      expect(result.current.isSuccess).toBeTruthy();
    });

    expect(result.current.data?.pageParams[0]).toEqual(0n);
  });

  it("doesn't share data with a similar non-infinite query", async () => {
    const remainingWrapper = wrapper({}, mockedPaginatedTransport);
    const { result } = renderHook(() => {
      return useInfiniteQuery(
        methodDescriptor,
        {
          page: 0n,
        },
        {
          getNextPageParam: (lastPage) => lastPage.page + 1n,
          pageParamKey: "page",
        },
      );
    }, remainingWrapper);
    await waitFor(() => {
      expect(result.current.isSuccess).toBeTruthy();
    });
    expect(result.current.data?.pages[0].items).toHaveLength(3);

    const { result: useQueryResult } = renderHook(() => {
      return useQuery(methodDescriptor);
    }, remainingWrapper);

    await waitFor(() => {
      expect(useQueryResult.current.isSuccess).toBeTruthy();
    });

    expect(useQueryResult.current.data?.items).toHaveLength(3);
  });

  it("cache can be invalidated with the shared, non-infinite key", async () => {
    const onSuccessSpy = vi.fn();
    const spiedQueryCache = new QueryCache({
      onSuccess: onSuccessSpy,
    });
    const { queryClient, ...remainingWrapper } = wrapper(
      { queryCache: spiedQueryCache },
      mockedPaginatedTransport,
    );
    const { result } = renderHook(() => {
      return useInfiniteQuery(
        methodDescriptor,
        {
          page: 0n,
        },
        {
          getNextPageParam: (lastPage) => lastPage.page + 1n,
          pageParamKey: "page",
        },
      );
    }, remainingWrapper);

    await waitFor(() => {
      expect(result.current.isSuccess).toBeTruthy();
    });

    expect(onSuccessSpy).toHaveBeenCalledTimes(1);

    await queryClient.invalidateQueries({
      queryKey: createConnectQueryKey({
        schema: methodDescriptor,
        transport: mockedPaginatedTransport,
        cardinality: undefined,
        pageParamKey: "page",
        input: {
          page: 0n,
        },
      }),
    });

    expect(onSuccessSpy).toHaveBeenCalledTimes(2);
  });

  it("cache can be invalidated with a non-exact key", async () => {
    const onSuccessSpy = vi.fn();
    const spiedQueryCache = new QueryCache({
      onSuccess: onSuccessSpy,
    });
    const { queryClient, ...remainingWrapper } = wrapper(
      { queryCache: spiedQueryCache },
      mockedPaginatedTransport,
    );
    const { result } = renderHook(() => {
      return useInfiniteQuery(
        methodDescriptor,
        {
          page: 0n,
        },
        {
          getNextPageParam: (lastPage) => lastPage.page + 1n,
          pageParamKey: "page",
        },
      );
    }, remainingWrapper);

    await waitFor(() => {
      expect(result.current.isSuccess).toBeTruthy();
    });

    expect(onSuccessSpy).toHaveBeenCalledTimes(1);

    await queryClient.invalidateQueries({
      exact: false,
      queryKey: createConnectQueryKey({
        schema: methodDescriptor,
        cardinality: "infinite",
      }),
    });

    expect(onSuccessSpy).toHaveBeenCalledTimes(2);
  });

  it("can query paginated data with a non-zero page param", async () => {
    const wrapperOpts = wrapper({}, mockedPaginatedTransport);
    const { result } = renderHook(() => {
      return useInfiniteQuery(
        methodDescriptor,
        {
          page: 1n,
          preview: true,
        },
        {
          getNextPageParam: (lastPage) => lastPage.page + 1n,
          pageParamKey: "page",
        },
      );
    }, wrapperOpts);
    await waitFor(() => {
      expect(result.current.isSuccess).toBeTruthy();
    });
    expect(result.current.data?.pages[0].items).toEqual([
      "1 Item",
      "2 Item",
      "3 Item",
    ]);
    const manuallyCreatedQueryKey = createConnectQueryKey({
      schema: methodDescriptor,
      transport: mockedPaginatedTransport,
      cardinality: "infinite",
      pageParamKey: "page",
      input: create(ListRequestSchema, {
        preview: true,
      }),
    });
    expect(
      wrapperOpts.queryClient.getQueryData(manuallyCreatedQueryKey),
    ).toEqual(result.current.data);
  });

  it("builds nested page input for successive pages", async () => {
    const wrapperOpts = wrapper({}, mockedNestedPaginatedTransport);
    const { result } = renderHook(() => {
      return useInfiniteQuery(
        nestedMethodDescriptor,
        {
          nested: {
            page: 1n,
            preview: true,
          },
        },
        {
          getNextPageParam: (lastPage) => (lastPage.nested?.page ?? 0n) + 1n,
          pageParamKey: "nested.page",
        },
      );
    }, wrapperOpts);

    await waitFor(() => {
      expect(result.current.isSuccess).toBeTruthy();
    });

    expect(result.current.data?.pageParams).toEqual([1n]);
    expect(result.current.data?.pages.map((page) => page.nested?.page)).toEqual(
      [1n],
    );

    await result.current.fetchNextPage();
    await waitFor(() => {
      expect(result.current.isFetching).toBeFalsy();
    });

    await result.current.fetchNextPage();
    await waitFor(() => {
      expect(result.current.isFetching).toBeFalsy();
    });

    expect(result.current.data?.pageParams).toEqual([1n, 2n, 3n]);
    expect(result.current.data?.pages.map((page) => page.nested?.page)).toEqual(
      [1n, 2n, 3n],
    );

    const manuallyCreatedQueryKey = createConnectQueryKey({
      schema: nestedMethodDescriptor,
      transport: mockedNestedPaginatedTransport,
      cardinality: "infinite",
      pageParamKey: "nested.page",
      input: {
        nested: {
          page: 1n,
          preview: true,
        },
      },
    });
    expect(
      wrapperOpts.queryClient.getQueryData(manuallyCreatedQueryKey),
    ).toEqual(result.current.data);
  });
});

describe("useSuspenseInfiniteQuery", () => {
  it("can query paginated data", async () => {
    const { result } = renderHook(
      () => {
        return useSuspenseInfiniteQuery(
          methodDescriptor,
          {
            page: 0n,
          },
          {
            getNextPageParam: (lastPage) => lastPage.page + 1n,
            pageParamKey: "page",
          },
        );
      },
      wrapper({}, mockedPaginatedTransport),
    );

    await waitFor(() => {
      expect(result.current.isSuccess).toBeTruthy();
    });
    expect(result.current.data).toEqual({
      pageParams: [0n],
      pages: [
        create(ListResponseSchema, {
          items: ["-2 Item", "-1 Item", "0 Item"],
          page: 0n,
        }),
      ],
    });

    await result.current.fetchNextPage();

    await waitFor(() => {
      expect(result.current.isFetching).toBeFalsy();
    });

    expect(result.current.data).toEqual({
      pageParams: [0n, 1n],
      pages: [
        create(ListResponseSchema, {
          items: ["-2 Item", "-1 Item", "0 Item"],
          page: 0n,
        }),
        create(ListResponseSchema, {
          items: ["1 Item", "2 Item", "3 Item"],
          page: 1n,
        }),
      ],
    });
  });

  // eslint-disable-next-line vitest/expect-expect -- We are asserting via @ts-expect-error
  it("can not be disabled with skipToken", () => {
    renderHook(
      () => {
        return useSuspenseInfiniteQuery(
          methodDescriptor,
          // @ts-expect-error(2345) skipToken is not allowed
          skipToken,
          {
            getNextPageParam: (lastPage) => lastPage.page + 1n,
            pageParamKey: "page",
          },
        );
      },
      wrapper({}, mockedPaginatedTransport),
    );
  });

  // eslint-disable-next-line vitest/expect-expect -- We are asserting via @ts-expect-error
  it("does not allow excess properties", () => {
    renderHook(
      () => {
        return useInfiniteQuery(
          methodDescriptor,
          {
            page: 0n,
            // @ts-expect-error(2345) extra fields should not be allowed
            extraField: "extra",
          },
          {
            getNextPageParam: (lastPage) => lastPage.page + 1n,
            pageParamKey: "page",
          },
        );
      },
      wrapper({}, mockedPaginatedTransport),
    );
  });

  it("can pass headers through", async () => {
    let resolve: () => void;
    const promise = new Promise<void>((res) => {
      resolve = res;
    });
    const transport = mockPaginatedTransport(
      {
        items: ["Intercepted!"],
        page: 0n,
      },
      false,
      {
        router: {
          interceptors: [
            (next) => (req) => {
              expect(req.header.get("x-custom-header")).toEqual("custom-value");
              resolve();
              return next(req);
            },
          ],
        },
      },
    );
    const { result } = renderHook(() => {
      return useSuspenseInfiniteQuery(
        methodDescriptor,
        {
          page: 0n,
        },
        {
          getNextPageParam: (lastPage) => lastPage.page + 1n,
          pageParamKey: "page",
          transport,
          headers: {
            "x-custom-header": "custom-value",
          },
        },
      );
    }, wrapper({}));

    await waitFor(() => {
      expect(result.current.isSuccess).toBeTruthy();
    });

    await promise;

    expect(result.current.data.pages[0].items).toEqual(["Intercepted!"]);
  });
});


================================================
FILE: packages/connect-query/src/use-infinite-query.ts
================================================
// Copyright 2021-2023 The Connect Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import type {
  DescMessage,
  DescMethodUnary,
  MessageInitShape,
  MessageShape,
} from "@bufbuild/protobuf";
import type { ConnectError, Transport } from "@connectrpc/connect";
import type {
  ConnectInfiniteQueryOptions,
  ConnectQueryKey,
  MessageInitWithPageParam,
  MessagePageParamKey,
  MessagePageParamValue,
} from "@connectrpc/connect-query-core";
import { createInfiniteQueryOptions } from "@connectrpc/connect-query-core";
import type {
  InfiniteData,
  SkipToken,
  UseInfiniteQueryOptions as TanStackUseInfiniteQueryOptions,
  UseInfiniteQueryResult,
  UseSuspenseInfiniteQueryOptions as TanStackUseSuspenseInfiniteQueryOptions,
  UseSuspenseInfiniteQueryResult,
} from "@tanstack/react-query";
import {
  useInfiniteQuery as tsUseInfiniteQuery,
  useSuspenseInfiniteQuery as tsUseSuspenseInfiniteQuery,
} from "@tanstack/react-query";

import { useTransport } from "./use-transport.js";

/**
 * Options for useInfiniteQuery
 */
export type UseInfiniteQueryOptions<
  I extends DescMessage,
  O extends DescMessage,
  ParamKey extends MessagePageParamKey<MessageInitShape<I>>,
  SelectOutData = MessageShape<O>,
  SelectOutPageParam = unknown,
> = Omit<
  TanStackUseInfiniteQueryOptions<
    MessageShape<O>,
    ConnectError,
    InfiniteData<SelectOutData, SelectOutPageParam>,
    ConnectQueryKey<O>,
    MessagePageParamValue<MessageInitShape<I>, ParamKey>
  >,
  "getNextPageParam" | "initialPageParam" | "queryFn" | "queryKey"
> &
  ConnectInfiniteQueryOptions<I, O, ParamKey> & {
    /** The transport to be used for the fetching. */
    transport?: Transport;
  };

/**
 * Query the method provided. Maps to useInfiniteQuery on tanstack/react-query
 */
export function useInfiniteQuery<
  I extends DescMessage,
  O extends DescMessage,
  const ParamKey extends MessagePageParamKey<MessageInitShape<I>>,
  SelectOutData = MessageShape<O>,
  SelectOutPageParam = unknown,
>(
  schema: DescMethodUnary<I, O>,
  input: SkipToken | MessageInitWithPageParam<MessageInitShape<I>, ParamKey>,
  {
    transport,
    pageParamKey,
    getNextPageParam,
    ...queryOptions
  }: UseInfiniteQueryOptions<I, O, ParamKey, SelectOutData, SelectOutPageParam>,
): UseInfiniteQueryResult<
  InfiniteData<SelectOutData, SelectOutPageParam>,
  ConnectError
> {
  const transportFromCtx = useTransport();
  const baseOptions = createInfiniteQueryOptions(schema, input, {
    transport: transport ?? transportFromCtx,
    getNextPageParam,
    pageParamKey,
  });
  return tsUseInfiniteQuery({
    ...baseOptions,
    ...queryOptions,
  });
}

/**
 * Options for useSuspenseInfiniteQuery
 */
export type UseSuspenseInfiniteQueryOptions<
  I extends DescMessage,
  O extends DescMessage,
  ParamKey extends MessagePageParamKey<MessageInitShape<I>>,
  SelectOutData = MessageShape<O>,
  SelectOutPageParam = unknown,
> = Omit<
  TanStackUseSuspenseInfiniteQueryOptions<
    MessageShape<O>,
    ConnectError,
    InfiniteData<SelectOutData, SelectOutPageParam>,
    ConnectQueryKey<O>,
    MessagePageParamValue<MessageInitShape<I>, ParamKey>
  >,
  "getNextPageParam" | "initialPageParam" | "queryFn" | "queryKey"
> &
  ConnectInfiniteQueryOptions<I, O, ParamKey> & {
    /** The transport to be used for the fetching. */
    transport?: Transport;
  };

/**
 * Query the method provided. Maps to useSuspenseInfiniteQuery on tanstack/react-query
 */
export function useSuspenseInfiniteQuery<
  I extends DescMessage,
  O extends DescMessage,
  const ParamKey extends MessagePageParamKey<MessageInitShape<I>>,
  SelectOutData = MessageShape<O>,
  SelectOutPageParam = unknown,
>(
  schema: DescMethodUnary<I, O>,
  input: MessageInitWithPageParam<MessageInitShape<I>, ParamKey>,
  {
    transport,
    pageParamKey,
    getNextPageParam,
    headers,
    ...queryOptions
  }: UseSuspenseInfiniteQueryOptions<
    I,
    O,
    ParamKey,
    SelectOutData,
    SelectOutPageParam
  >,
): UseSuspenseInfiniteQueryResult<
  InfiniteData<SelectOutData, SelectOutPageParam>,
  ConnectError
> {
  const transportFromCtx = useTransport();
  const baseOptions = createInfiniteQueryOptions(schema, input, {
    transport: transport ?? transportFromCtx,
    getNextPageParam,
    pageParamKey,
    headers,
  });
  return tsUseSuspenseInfiniteQuery({
    ...baseOptions,
    ...queryOptions,
  });
}


================================================
FILE: packages/connect-query/src/use-mutation.test.ts
================================================
// Copyright 2021-2023 The Connect Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { create } from "@bufbuild/protobuf";
import { renderHook, waitFor } from "@testing-library/react";
import { mockPaginatedTransport } from "test-utils";
import { ListResponseSchema, ListService } from "test-utils/gen/list_pb.js";
import { describe, expect, it, vi } from "vitest";

import { wrapper } from "./test/test-wrapper.js";
import { useMutation } from "./use-mutation.js";

// TODO: maybe create a helper to take a service and method and generate this.
const methodDescriptor = ListService.method.list;

const mockedPaginatedTransport = mockPaginatedTransport();

describe("useMutation", () => {
  it("performs a mutation", async () => {
    const onSuccess = vi.fn();
    const { result } = renderHook(
      () => {
        return useMutation(methodDescriptor, {
          onSuccess,
        });
      },
      wrapper({}, mockedPaginatedTransport),
    );

    result.current.mutate({
      page: 0n,
    });

    await waitFor(() => {
      expect(result.current.isSuccess).toBeTruthy();
    });

    expect(onSuccess).toHaveBeenCalledWith(
      create(ListResponseSchema, {
        items: ["-2 Item", "-1 Item", "0 Item"],
        page: 0n,
      }),
      {
        page: 0n,
      },
      undefined,
    );
  });

  it("can be provided a custom transport", async () => {
    const { result } = renderHook(
      () => {
        return useMutation(methodDescriptor, {
          transport: mockPaginatedTransport({
            page: 1n,
            items: ["Intercepted!"],
          }),
        });
      },
      wrapper({}, mockedPaginatedTransport),
    );

    result.current.mutate({
      page: 0n,
    });

    await waitFor(() => {
      expect(result.current.isSuccess).toBeTruthy();
    });

    expect(result.current.data?.items[0]).toBe("Intercepted!");
  });

  it("can forward onMutate params", async () => {
    const onSuccess = vi.fn();
    const { result } = renderHook(
      () => {
        return useMutation(methodDescriptor, {
          onMutate: (variables) => {
            return {
              somethingElse: `Some additional context: ${(variables.page ?? 0n) + 2n}`,
            };
          },
          onSuccess: (data, variables, context) => {
            onSuccess(data, variables, context);
            // Customizing on success so we can test the types
            expect(context.somethingElse).toBe("Some additional context: 2");
          },
        });
      },
      wrapper({}, mockedPaginatedTransport),
    );

    result.current.mutate({
      page: 0n,
    });

    await waitFor(() => {
      expect(result.current.isSuccess).toBeTruthy();
    });

    expect(onSuccess).toHaveBeenCalledWith(
      create(ListResponseSchema, {
        items: ["-2 Item", "-1 Item", "0 Item"],
        page: 0n,
      }),
      {
        page: 0n,
      },
      { somethingElse: "Some additional context: 2" },
    );
  });
});


================================================
FILE: packages/connect-query/src/use-mutation.ts
================================================
// Copyright 2021-2023 The Connect Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import type {
  DescMessage,
  DescMethodUnary,
  MessageInitShape,
  MessageShape,
} from "@bufbuild/protobuf";
import type { ConnectError, Transport } from "@connectrpc/connect";
import { callUnaryMethod } from "@connectrpc/connect-query-core";
import type {
  UseMutationOptions as TSUseMutationOptions,
  UseMutationResult,
} from "@tanstack/react-query";
import { useMutation as tsUseMutation } from "@tanstack/react-query";
import { useCallback } from "react";

import { useTransport } from "./use-transport.js";

/**
 * Options for useMutation
 */
export type UseMutationOptions<
  I extends DescMessage,
  O extends DescMessage,
  Ctx = unknown,
> = TSUseMutationOptions<
  MessageShape<O>,
  ConnectError,
  MessageInitShape<I>,
  Ctx
> & {
  /** The transport to be used for the fetching. */
  transport?: Transport;
};

/**
 * Query the method provided. Maps to useMutation on tanstack/react-query
 */
export function useMutation<
  I extends DescMessage,
  O extends DescMessage,
  Ctx = unknown,
>(
  schema: DescMethodUnary<I, O>,
  { transport, ...queryOptions }: UseMutationOptions<I, O, Ctx> = {},
): UseMutationResult<MessageShape<O>, ConnectError, MessageInitShape<I>, Ctx> {
  const transportFromCtx = useTransport();
  const transportToUse = transport ?? transportFromCtx;
  const mutationFn = useCallback(
    async (input: MessageInitShape<I>) =>
      callUnaryMethod(transportToUse, schema, input),
    [transportToUse, schema],
  );
  return tsUseMutation({
    ...queryOptions,
    mutationFn,
  });
}


================================================
FILE: packages/connect-query/src/use-query.test.ts
================================================
// Copyright 2021-2023 The Connect Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { create } from "@bufbuild/protobuf";
import {
  createConnectQueryKey,
  skipToken,
} from "@connectrpc/connect-query-core";
import { renderHook, waitFor } from "@testing-library/react";
import { mockBigInt, mockEliza } from "test-utils";
import { BigIntService } from "test-utils/gen/bigint_pb.js";
import { ElizaService } from "test-utils/gen/eliza_pb.js";
import { describe, expect, it } from "vitest";

import { wrapper } from "./test/test-wrapper.js";
import { useQuery, useSuspenseQuery } from "./use-query.js";

// TODO: maybe create a helper to take a service and method and generate this.
const sayMethodDescriptor = ElizaService.method.say;

const mockedElizaTransport = mockEliza();

const bigintTransport = mockBigInt();

const elizaWithDelayTransport = mockEliza(undefined, true);

describe("useQuery", () => {
  it("can query data", async () => {
    const { result } = renderHook(
      () => {
        return useQuery(sayMethodDescriptor, {
          sentence: "hello",
        });
      },
      wrapper({}, mockedElizaTransport),
    );

    await waitFor(() => {
      expect(result.current.isSuccess).toBeTruthy();
    });

    expect(typeof result.current.data?.sentence).toBe("string");
  });

  it("can be disabled", () => {
    const { result } = renderHook(
      () => {
        return useQuery(sayMethodDescriptor, skipToken);
      },
      wrapper(undefined, mockedElizaTransport),
    );
    expect(result.current.isPending).toBeTruthy();
    expect(result.current.isFetching).toBeFalsy();
  });

  it("can be provided a custom transport", async () => {
    const transport = mockEliza({
      sentence: "Intercepted!",
    });
    const { result } = renderHook(
      () => {
        return useQuery(
          sayMethodDescriptor,
          {},
          {
            transport,
          },
        );
      },
      wrapper(undefined, mockedElizaTransport),
    );
    await waitFor(() => {
      expect(result.current.isSuccess).toBeTruthy();
    });

    expect(result.current.data?.sentence).toBe("Intercepted!");
  });

  it("can be provided other props for react-query", () => {
    const { result } = renderHook(
      () => {
        return useQuery(
          sayMethodDescriptor,
          {},
          {
            transport: elizaWithDelayTransport,
            placeholderData: create(sayMethodDescriptor.output, {
              sentence: "placeholder!",
            }),
          },
        );
      },
      wrapper(undefined, mockedElizaTransport),
    );
    expect(result.current.data?.sentence).toBe("placeholder!");
  });

  it("can be used along with the select", async () => {
    const { result } = renderHook(
      () => {
        return useQuery(
          sayMethodDescriptor,
          {},
          {
            select: (data) => data.sentence.length,
          },
        );
      },
      wrapper(undefined, mockedElizaTransport),
    );

    await waitFor(() => {
      expect(result.current.isSuccess).toBeTruthy();
    });

    expect(result.current.data).toBe(6);
  });

  it("can be disabled with enabled: false", () => {
    const { result } = renderHook(
      () => {
        return useQuery(
          sayMethodDescriptor,
          {
            sentence: "hello",
          },
          {
            enabled: false,
          },
        );
      },
      wrapper({}, mockedElizaTransport),
    );

    expect(result.current.data).toBeUndefined();
    expect(result.current.isPending).toBeTruthy();
    expect(result.current.isFetching).toBeFalsy();
  });

  it("can be disabled with enabled: false in QueryClient default options", () => {
    const { result } = renderHook(
      () => {
        return useQuery(sayMethodDescriptor, {
          sentence: "hello",
        });
      },
      wrapper(
        {
          defaultOptions: {
            queries: {
              enabled: false,
            },
          },
        },
        mockedElizaTransport,
      ),
    );

    expect(result.current.data).toBeUndefined();
    expect(result.current.isPending).toBeTruthy();
    expect(result.current.isFetching).toBeFalsy();
  });

  it("can be disabled with skipToken", () => {
    const { result } = renderHook(
      () => {
        return useQuery(sayMethodDescriptor, skipToken);
      },
      wrapper({}, mockedElizaTransport),
    );

    expect(result.current.data).toBeUndefined();
    expect(result.current.isPending).toBeTruthy();
    expect(result.current.isFetching).toBeFalsy();
  });

  it("supports schemas with bigint keys", async () => {
    const { result } = renderHook(
      () => {
        return 
Download .txt
gitextract_bg1etjgz/

├── .eslintrc.cjs
├── .gitattributes
├── .github/
│   ├── CODE_OF_CONDUCT.md
│   ├── CONTRIBUTING.md
│   ├── RELEASING.md
│   ├── dependabot.yaml
│   ├── release.yaml
│   └── workflows/
│       ├── add-to-project.yaml
│       ├── ci.yaml
│       ├── pr-title.yaml
│       ├── prepare-release.yml
│       └── publish-release.yml
├── .gitignore
├── .nvmrc
├── .vscode/
│   ├── extensions.json
│   └── settings.json
├── LICENSE
├── MAINTAINERS.md
├── README.md
├── SECURITY.md
├── assets/
│   ├── connect-query.ai
│   └── connect-query_dependency_graph.excalidraw
├── cspell.config.json
├── package.json
├── packages/
│   ├── connect-query/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── call-unary-method.test.ts
│   │   │   ├── index.ts
│   │   │   ├── test/
│   │   │   │   └── test-wrapper.tsx
│   │   │   ├── use-infinite-query.test.ts
│   │   │   ├── use-infinite-query.ts
│   │   │   ├── use-mutation.test.ts
│   │   │   ├── use-mutation.ts
│   │   │   ├── use-query.test.ts
│   │   │   ├── use-query.ts
│   │   │   ├── use-transport.test.tsx
│   │   │   └── use-transport.tsx
│   │   ├── tsconfig.build.json
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── connect-query-core/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── call-unary-method.ts
│   │   │   ├── connect-query-key.test.ts
│   │   │   ├── connect-query-key.ts
│   │   │   ├── create-infinite-query-options.test.ts
│   │   │   ├── create-infinite-query-options.ts
│   │   │   ├── create-query-options.test.ts
│   │   │   ├── create-query-options.ts
│   │   │   ├── index.ts
│   │   │   ├── message-key.test.ts
│   │   │   ├── message-key.ts
│   │   │   ├── page-param-key.ts
│   │   │   ├── structural-sharing.test.ts
│   │   │   ├── structural-sharing.ts
│   │   │   ├── transport-key.test.ts
│   │   │   ├── transport-key.ts
│   │   │   ├── utils.test.ts
│   │   │   └── utils.ts
│   │   ├── tsconfig.build.json
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── examples/
│   │   └── react/
│   │       └── basic/
│   │           ├── .gitignore
│   │           ├── buf.gen.yaml
│   │           ├── eliza.proto
│   │           ├── index.html
│   │           ├── package.json
│   │           ├── src/
│   │           │   ├── css.ts
│   │           │   ├── datum.tsx
│   │           │   ├── example.tsx
│   │           │   ├── gen/
│   │           │   │   ├── eliza-ElizaService_connectquery.ts
│   │           │   │   └── eliza_pb.ts
│   │           │   ├── index.css
│   │           │   ├── indicator.tsx
│   │           │   ├── main.test.tsx
│   │           │   ├── main.tsx
│   │           │   ├── page.tsx
│   │           │   └── vite-env.d.ts
│   │           ├── tsconfig.json
│   │           └── vite.config.ts
│   ├── protoc-gen-connect-query/
│   │   ├── .eslintignore
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── bin/
│   │   │   └── protoc-gen-connect-query
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── generateDts.ts
│   │   │   ├── generateTs.ts
│   │   │   ├── protoc-gen-connect-query-plugin.ts
│   │   │   └── utils.ts
│   │   └── tsconfig.json
│   └── test-utils/
│       ├── buf.gen.yaml
│       ├── package.json
│       ├── proto/
│       │   ├── bigint.proto
│       │   ├── eliza.proto
│       │   ├── list.proto
│       │   ├── proto2.proto
│       │   └── proto3.proto
│       ├── src/
│       │   ├── gen/
│       │   │   ├── bigint_pb.ts
│       │   │   ├── eliza_pb.ts
│       │   │   ├── list_pb.ts
│       │   │   ├── proto2_pb.ts
│       │   │   └── proto3_pb.ts
│       │   └── index.tsx
│       └── tsconfig.json
├── scripts/
│   ├── find-workspace-version.js
│   ├── gh-diffcheck.js
│   ├── release.js
│   ├── set-workspace-version.js
│   └── utils.js
├── tsconfig.base.json
└── turbo.json
Download .txt
SYMBOL INDEX (87 symbols across 26 files)

FILE: packages/connect-query-core/src/call-unary-method.ts
  function callUnaryMethod (line 28) | async function callUnaryMethod<

FILE: packages/connect-query-core/src/connect-query-key.test.ts
  method stream (line 42) | async stream() {
  method unary (line 45) | async unary() {
  type Key (line 110) | type Key = MessagePageParamKey<
  type Key (line 119) | type Key = MessagePageParamKey<{
  type Key (line 131) | type Key = MessagePageParamKey<MessageInitShape<typeof SayRequestSchema>>;

FILE: packages/connect-query-core/src/connect-query-key.ts
  type SharedConnectQueryOptions (line 30) | type SharedConnectQueryOptions = {
  type InfiniteConnectQueryKey (line 55) | type InfiniteConnectQueryKey<OutputMessage extends DescMessage = DescMes...
  type FiniteConnectQueryKey (line 68) | type FiniteConnectQueryKey<OutputMessage extends DescMessage = DescMessa...
  type ConnectQueryKey (line 100) | type ConnectQueryKey<OutputMessage extends DescMessage = DescMessage> =
  type KeyParamsForMethod (line 110) | type KeyParamsForMethod<Desc extends DescMethod> = {
  type KeyParamsForService (line 141) | type KeyParamsForService<Desc extends DescService> = {
  function createConnectQueryKey (line 221) | function createConnectQueryKey<
  function createHeadersKey (line 275) | function createHeadersKey(headers: HeadersInit): Record<string, string> {

FILE: packages/connect-query-core/src/create-infinite-query-options.ts
  type InfiniteQueryOptions (line 47) | interface InfiniteQueryOptions<
  type InfiniteQueryOptionsWithSkipToken (line 70) | interface InfiniteQueryOptionsWithSkipToken<
  type ConnectInfiniteQueryOptions (line 81) | interface ConnectInfiniteQueryOptions<
  function createUnaryInfiniteQueryFn (line 97) | function createUnaryInfiniteQueryFn<
  function createInfiniteQueryOptions (line 177) | function createInfiniteQueryOptions<

FILE: packages/connect-query-core/src/create-query-options.ts
  type QueryOptions (line 34) | interface QueryOptions<O extends DescMessage> {
  type QueryOptionsWithSkipToken (line 40) | interface QueryOptionsWithSkipToken<O extends DescMessage>
  function createUnaryQueryFn (line 45) | function createUnaryQueryFn<I extends DescMessage, O extends DescMessage>(
  function createQueryOptions (line 103) | function createQueryOptions<

FILE: packages/connect-query-core/src/message-key.ts
  function createMessageKey (line 43) | function createMessageKey<
  function scalarKey (line 60) | function scalarKey(value: unknown): unknown {
  function listKey (line 73) | function listKey(list: ReflectList): unknown[] {
  function mapKey (line 86) | function mapKey(map: ReflectMap): Record<string, unknown> {
  function messageKey (line 107) | function messageKey(

FILE: packages/connect-query-core/src/page-param-key.ts
  type StringKeyOf (line 17) | type StringKeyOf<T> = Exclude<Extract<keyof T, string>, keyof Message>;
  type PrevDepth (line 18) | type PrevDepth = [never, 0, 1, 2, 3, 4, 5];
  type CanDescend (line 20) | type CanDescend<T> = T extends readonly unknown[]
  type MessagePageParamPathString (line 26) | type MessagePageParamPathString<T, Depth extends number = 5> = Depth ext...
  type MessagePageParamKey (line 45) | type MessagePageParamKey<T> = MessagePageParamPathString<T>;
  type DotPathValue (line 47) | type DotPathValue<T, P extends string> = P extends `${infer Head}.${infe...
  type MessagePageParamValue (line 58) | type MessagePageParamValue<
  type RootKey (line 63) | type RootKey<K> = K extends `${infer Head}.${string}`
  type MessageInitWithPageParam (line 72) | type MessageInitWithPageParam<T, K extends MessagePageParamKey<T>> = T &
  function pageParamPathSegments (line 75) | function pageParamPathSegments(
  function getValueAtPath (line 81) | function getValueAtPath(
  function setValueAtPath (line 100) | function setValueAtPath(

FILE: packages/connect-query-core/src/structural-sharing.ts
  function createStructuralSharing (line 27) | function createStructuralSharing(

FILE: packages/connect-query-core/src/transport-key.ts
  type TransportWithStaticKey (line 22) | interface TransportWithStaticKey extends Transport {
  function createTransportKey (line 32) | function createTransportKey(transport: TransportWithStaticKey): string {
  function addStaticKeyToTransport (line 49) | function addStaticKeyToTransport(

FILE: packages/connect-query-core/src/utils.ts
  function assert (line 26) | function assert(condition: boolean, message: string): asserts condition {
  type ConnectUpdater (line 56) | type ConnectUpdater<O extends DescMessage> =

FILE: packages/connect-query/src/use-infinite-query.ts
  type UseInfiniteQueryOptions (line 48) | type UseInfiniteQueryOptions<
  function useInfiniteQuery (line 72) | function useInfiniteQuery<
  type UseSuspenseInfiniteQueryOptions (line 106) | type UseSuspenseInfiniteQueryOptions<
  function useSuspenseInfiniteQuery (line 130) | function useSuspenseInfiniteQuery<

FILE: packages/connect-query/src/use-mutation.ts
  type UseMutationOptions (line 35) | type UseMutationOptions<
  function useMutation (line 52) | function useMutation<

FILE: packages/connect-query/src/use-query.ts
  type UseQueryOptions (line 43) | type UseQueryOptions<
  function useQuery (line 62) | function useQuery<
  type UseSuspenseQueryOptions (line 84) | type UseSuspenseQueryOptions<
  function useSuspenseQuery (line 104) | function useSuspenseQuery<

FILE: packages/examples/react/basic/src/datum.tsx
  type DatumProps (line 27) | interface DatumProps {

FILE: packages/examples/react/basic/src/gen/eliza_pb.ts
  type SayRequest (line 34) | type SayRequest = Message<"connectrpc.eliza.v1.SayRequest"> & {
  type SayResponse (line 53) | type SayResponse = Message<"connectrpc.eliza.v1.SayResponse"> & {

FILE: packages/examples/react/basic/src/main.tsx
  function App (line 31) | function App({ transport }: { transport?: Transport }) {

FILE: packages/protoc-gen-connect-query/src/utils.ts
  type PluginInit (line 20) | type PluginInit = Required<Parameters<typeof createEcmaScriptPlugin>[0]>;

FILE: packages/test-utils/src/gen/bigint_pb.ts
  type CountRequest (line 34) | type CountRequest = Message<"CountRequest"> & {
  type CountResponse (line 51) | type CountResponse = Message<"CountResponse"> & {

FILE: packages/test-utils/src/gen/eliza_pb.ts
  type SayRequest (line 34) | type SayRequest = Message<"connectrpc.eliza.v1.SayRequest"> & {
  type SayResponse (line 53) | type SayResponse = Message<"connectrpc.eliza.v1.SayResponse"> & {

FILE: packages/test-utils/src/gen/list_pb.ts
  type ListRequest (line 32) | type ListRequest = Message<"ListRequest"> & {
  type ListResponse (line 54) | type ListResponse = Message<"ListResponse"> & {
  type NestedListRequest (line 76) | type NestedListRequest = Message<"NestedListRequest"> & {
  type NestedListRequest_Nested (line 93) | type NestedListRequest_Nested = Message<"NestedListRequest.Nested"> & {
  type NestedListResponse (line 115) | type NestedListResponse = Message<"NestedListResponse"> & {
  type NestedListResponse_Nested (line 137) | type NestedListResponse_Nested = Message<"NestedListResponse.Nested"> & {

FILE: packages/test-utils/src/gen/proto2_pb.ts
  type Proto2Message (line 32) | type Proto2Message = Message<"test.Proto2Message"> & {

FILE: packages/test-utils/src/gen/proto3_pb.ts
  type Proto3Message (line 34) | type Proto3Message = Message<"test.Proto3Message"> & {
  type Proto3Enum (line 138) | enum Proto3Enum {

FILE: scripts/gh-diffcheck.js
  function gitUncommitted (line 31) | function gitUncommitted() {

FILE: scripts/release.js
  function npmPublish (line 37) | function npmPublish() {
  function gitUncommitted (line 51) | function gitUncommitted() {
  function determinePublishTag (line 65) | function determinePublishTag(version) {

FILE: scripts/set-workspace-version.js
  function readWorkspaces (line 99) | function readWorkspaces(rootPackagePath) {
  function updatePackageDep (line 120) | function updatePackageDep(pkg, depName, toVersion) {
  function formatLog (line 171) | function formatLog(log) {
  function readPackage (line 197) | function readPackage(path) {
  function readLockfile (line 231) | function readLockfile(path) {
  function findLockPackage (line 253) | function findLockPackage(lock, packageName) {
  function readRootPackage (line 285) | function readRootPackage(path) {
  function writeJson (line 303) | function writeJson(path, json) {

FILE: scripts/utils.js
  function findWorkspaceVersion (line 24) | function findWorkspaceVersion(packagesDir) {
Condensed preview — 111 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (413K chars).
[
  {
    "path": ".eslintrc.cjs",
    "chars": 3407,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": ".gitattributes",
    "chars": 378,
    "preview": "# This is similar to the git option core.autocrlf but it applies to all\n# users of the repository and therefore doesn't "
  },
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "chars": 141,
    "preview": "## Community Code of Conduct\n\nConnect follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "chars": 2573,
    "preview": "# Contributing\n\nWe'd love your help making `connect-query-es` better!\n\nIf you'd like to add new exported APIs, please [o"
  },
  {
    "path": ".github/RELEASING.md",
    "chars": 2313,
    "preview": "# Releasing\n\n## Prerequisites\n\n- See the setup and tools required in CONTRIBUTING.md\n- A granular access token for npmjs"
  },
  {
    "path": ".github/dependabot.yaml",
    "chars": 1114,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"monthly\"\n "
  },
  {
    "path": ".github/release.yaml",
    "chars": 98,
    "preview": "changelog:\n  exclude:\n    labels:\n      - ignore-for-release\n    authors:\n      - dependabot[bot]\n"
  },
  {
    "path": ".github/workflows/add-to-project.yaml",
    "chars": 411,
    "preview": "name: Add issues and PRs to project\n\non:\n  issues:\n    types:\n      - opened\n      - reopened\n      - transferred\n  pull"
  },
  {
    "path": ".github/workflows/ci.yaml",
    "chars": 1688,
    "preview": "name: ci\n\non:\n  push:\n    branches: [main, \"v*\"]\n    tags: [\"v*\"]\n  pull_request:\n    branches: [main, \"v*\"]\n  workflow_"
  },
  {
    "path": ".github/workflows/pr-title.yaml",
    "chars": 612,
    "preview": "name: Lint PR Title\n# Prevent writing to the repository using the CI token.\n# Ref: https://docs.github.com/en/actions/re"
  },
  {
    "path": ".github/workflows/prepare-release.yml",
    "chars": 2484,
    "preview": "name: Prepare Release\n\non:\n  workflow_dispatch:\n    inputs:\n      version:\n        description: \"Version to release (e.g"
  },
  {
    "path": ".github/workflows/publish-release.yml",
    "chars": 1924,
    "preview": "name: Publish Release\n\non:\n  pull_request:\n    types: [closed]\n    branches:\n      - main\n\njobs:\n  publish-release:\n    "
  },
  {
    "path": ".gitignore",
    "chars": 93,
    "preview": ".turbo\n.wrangler\nnode_modules\n/packages/*/dist\n/packages/*/coverage\ntsconfig.vitest-temp.json"
  },
  {
    "path": ".nvmrc",
    "chars": 8,
    "preview": "v24.5.0\n"
  },
  {
    "path": ".vscode/extensions.json",
    "chars": 58,
    "preview": "{\n  \"recommendations\": [\"orta.vscode-twoslash-queries\"]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 119,
    "preview": "{\n  \"git.enableCommitSigning\": true,\n  \"git.alwaysSignOff\": true,\n  \"typescript.tsdk\": \"node_modules/typescript/lib\"\n}\n"
  },
  {
    "path": "LICENSE",
    "chars": 10944,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "MAINTAINERS.md",
    "chars": 310,
    "preview": "# Maintainers\n\n## Current\n\n- [Timo Stamm](https://github.com/timostamm), [Buf](https://buf.build)\n- [Steve Ayers](https:"
  },
  {
    "path": "README.md",
    "chars": 28201,
    "preview": "<!-- markdownlint-disable-next-line MD041 MD033 -- 033: necessary for setting the width; 041: this is the style of bufbu"
  },
  {
    "path": "SECURITY.md",
    "chars": 142,
    "preview": "# Security Policy\n\nThis project follows the [Connect security policy and reporting\nprocess](https://connectrpc.com/docs/"
  },
  {
    "path": "assets/connect-query.ai",
    "chars": 58817,
    "preview": "%PDF-1.6\r%\r\n1 0 obj\r<</Metadata 2 0 R/OCProperties<</D<</ON[18 0 R]/Order 19 0 R/RBGroups[]>>/OCGs[18 0 R]>>/Pages 3 0 R"
  },
  {
    "path": "assets/connect-query_dependency_graph.excalidraw",
    "chars": 35830,
    "preview": "{\n  \"type\": \"excalidraw\",\n  \"version\": 2,\n  \"source\": \"https://excalidraw.com\",\n  \"elements\": [\n    {\n      \"type\": \"rec"
  },
  {
    "path": "cspell.config.json",
    "chars": 949,
    "preview": "{\n  \"words\": [\n    \"Deno\",\n    \"Dimitri\",\n    \"Mitropoulos\",\n    \"Quickstart\",\n    \"Stamm\",\n    \"Timo\",\n    \"Vindaloo\",\n"
  },
  {
    "path": "package.json",
    "chars": 1914,
    "preview": "{\n  \"private\": true,\n  \"name\": \"root\",\n  \"type\": \"module\",\n  \"workspaces\": [\n    \"packages/connect-query-core\",\n    \"pac"
  },
  {
    "path": "packages/connect-query/README.md",
    "chars": 694,
    "preview": "# @connectrpc/connect-query\n\nThis is the runtime library package for Connect-Query. You'll find its code generator at [@"
  },
  {
    "path": "packages/connect-query/package.json",
    "chars": 2102,
    "preview": "{\n  \"name\": \"@connectrpc/connect-query\",\n  \"version\": \"2.2.0\",\n  \"description\": \"TypeScript-first expansion pack for Tan"
  },
  {
    "path": "packages/connect-query/src/call-unary-method.test.ts",
    "chars": 3362,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query/src/index.ts",
    "chars": 1110,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query/src/test/test-wrapper.tsx",
    "chars": 1892,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query/src/use-infinite-query.test.ts",
    "chars": 16003,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query/src/use-infinite-query.ts",
    "chars": 4898,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query/src/use-mutation.test.ts",
    "chars": 3484,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query/src/use-mutation.ts",
    "chars": 2132,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query/src/use-query.test.ts",
    "chars": 8104,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query/src/use-query.ts",
    "chars": 3344,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query/src/use-transport.test.tsx",
    "chars": 2380,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query/src/use-transport.tsx",
    "chars": 3478,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query/tsconfig.build.json",
    "chars": 124,
    "preview": "{\n  \"extends\": \"../../tsconfig.base.json\",\n  \"files\": [\"src/index.ts\"],\n  \"compilerOptions\": {\n    \"jsx\": \"react-jsx\"\n  "
  },
  {
    "path": "packages/connect-query/tsconfig.json",
    "chars": 146,
    "preview": "{\n  \"include\": [\n    \"**/*.test.ts\",\n    \"**/*.test.tsx\",\n    \"src/test/**.tsx\",\n    \"vite.config.ts\"\n  ],\n  \"extends\": "
  },
  {
    "path": "packages/connect-query/vite.config.ts",
    "chars": 1102,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/README.md",
    "chars": 404,
    "preview": "# @connectrpc/connect-query-core\n\nThis package provides the core functionality for the Connect-Query API. It exposes all"
  },
  {
    "path": "packages/connect-query-core/package.json",
    "chars": 1806,
    "preview": "{\n  \"name\": \"@connectrpc/connect-query-core\",\n  \"version\": \"2.2.0\",\n  \"description\": \"Core of Connect-Query, framework a"
  },
  {
    "path": "packages/connect-query-core/src/call-unary-method.ts",
    "chars": 1446,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/src/connect-query-key.test.ts",
    "chars": 11483,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/src/connect-query-key.ts",
    "chars": 8384,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/src/create-infinite-query-options.test.ts",
    "chars": 1974,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/src/create-infinite-query-options.ts",
    "chars": 6592,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/src/create-query-options.test.ts",
    "chars": 2552,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/src/create-query-options.ts",
    "chars": 3732,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/src/index.ts",
    "chars": 1572,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/src/message-key.test.ts",
    "chars": 4168,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/src/message-key.ts",
    "chars": 4493,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/src/page-param-key.ts",
    "chars": 3709,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/src/structural-sharing.test.ts",
    "chars": 2497,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/src/structural-sharing.ts",
    "chars": 1558,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/src/transport-key.test.ts",
    "chars": 1815,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/src/transport-key.ts",
    "chars": 1805,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/src/utils.test.ts",
    "chars": 6141,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/src/utils.ts",
    "chars": 2675,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/connect-query-core/tsconfig.build.json",
    "chars": 73,
    "preview": "{\n  \"extends\": \"../../tsconfig.base.json\",\n  \"files\": [\"src/index.ts\"]\n}\n"
  },
  {
    "path": "packages/connect-query-core/tsconfig.json",
    "chars": 146,
    "preview": "{\n  \"include\": [\n    \"**/*.test.ts\",\n    \"**/*.test.tsx\",\n    \"src/test/**.tsx\",\n    \"vite.config.ts\"\n  ],\n  \"extends\": "
  },
  {
    "path": "packages/connect-query-core/vite.config.ts",
    "chars": 1102,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/examples/react/basic/.gitignore",
    "chars": 204,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-debug.log*\n\nnode_modules\ndist\ndist-ssr\n*.local\n\n# Editor directories and files\n.vs"
  },
  {
    "path": "packages/examples/react/basic/buf.gen.yaml",
    "chars": 445,
    "preview": "# buf.gen.yaml defines a local generation template.\n# For details, see https://buf.build/docs/configuration/v2/buf-gen-y"
  },
  {
    "path": "packages/examples/react/basic/eliza.proto",
    "chars": 1370,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/examples/react/basic/index.html",
    "chars": 366,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/"
  },
  {
    "path": "packages/examples/react/basic/package.json",
    "chars": 1070,
    "preview": "{\n  \"name\": \"@connectrpc/connect-query-example-basic\",\n  \"version\": \"2.2.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"s"
  },
  {
    "path": "packages/examples/react/basic/src/css.ts",
    "chars": 860,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/examples/react/basic/src/datum.tsx",
    "chars": 1704,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/examples/react/basic/src/example.tsx",
    "chars": 1754,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/examples/react/basic/src/gen/eliza-ElizaService_connectquery.ts",
    "chars": 1017,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/examples/react/basic/src/gen/eliza_pb.ts",
    "chars": 3176,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/examples/react/basic/src/index.css",
    "chars": 191,
    "preview": ":root {\n  font-family: Inter, Helvetica, Arial, sans-serif;\n  font-size: 16px;\n  line-height: 24px;\n  font-weight: 400;\n"
  },
  {
    "path": "packages/examples/react/basic/src/indicator.tsx",
    "chars": 1635,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/examples/react/basic/src/main.test.tsx",
    "chars": 1494,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/examples/react/basic/src/main.tsx",
    "chars": 1670,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/examples/react/basic/src/page.tsx",
    "chars": 922,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/examples/react/basic/src/vite-env.d.ts",
    "chars": 641,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/examples/react/basic/tsconfig.json",
    "chars": 680,
    "preview": "{\n  \"compilerOptions\": {\n    \"allowJs\": false,\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": false,\n "
  },
  {
    "path": "packages/examples/react/basic/vite.config.ts",
    "chars": 994,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/protoc-gen-connect-query/.eslintignore",
    "chars": 21,
    "preview": "snapshots\n.type-dump\n"
  },
  {
    "path": "packages/protoc-gen-connect-query/.gitignore",
    "chars": 191,
    "preview": "# A directory that exists solely to hold the result of tsc since --noEmit doesn't discover to protability issue found\n# "
  },
  {
    "path": "packages/protoc-gen-connect-query/README.md",
    "chars": 8865,
    "preview": "# @connectrpc/protoc-gen-connect-query\n\n- [@connectrpc/protoc-gen-connect-query](#connectrpcprotoc-gen-connect-query)\n  "
  },
  {
    "path": "packages/protoc-gen-connect-query/bin/protoc-gen-connect-query",
    "chars": 212,
    "preview": "#!/usr/bin/env node\n\nconst { runNodeJs } = require(\"@bufbuild/protoplugin\");\nconst {\n  protocGenConnectQuery,\n} = requir"
  },
  {
    "path": "packages/protoc-gen-connect-query/package.json",
    "chars": 1358,
    "preview": "{\n  \"name\": \"@connectrpc/protoc-gen-connect-query\",\n  \"version\": \"2.2.0\",\n  \"description\": \"Code generator for connect-q"
  },
  {
    "path": "packages/protoc-gen-connect-query/src/generateDts.ts",
    "chars": 1861,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/protoc-gen-connect-query/src/generateTs.ts",
    "chars": 2095,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/protoc-gen-connect-query/src/protoc-gen-connect-query-plugin.ts",
    "chars": 1099,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/protoc-gen-connect-query/src/utils.ts",
    "chars": 824,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/protoc-gen-connect-query/tsconfig.json",
    "chars": 347,
    "preview": "{\n  \"files\": [\"src/protoc-gen-connect-query-plugin.ts\"],\n  \"extends\": \"../../tsconfig.base.json\",\n  \"compilerOptions\": {"
  },
  {
    "path": "packages/test-utils/buf.gen.yaml",
    "chars": 358,
    "preview": "# buf.gen.yaml defines a local generation template.\n# For details, see https://buf.build/docs/configuration/v2/buf-gen-y"
  },
  {
    "path": "packages/test-utils/package.json",
    "chars": 1304,
    "preview": "{\n  \"name\": \"test-utils\",\n  \"private\": true,\n  \"version\": \"2.2.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"generate\": \"b"
  },
  {
    "path": "packages/test-utils/proto/bigint.proto",
    "chars": 891,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/test-utils/proto/eliza.proto",
    "chars": 1370,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/test-utils/proto/list.proto",
    "chars": 1139,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/test-utils/proto/proto2.proto",
    "chars": 733,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/test-utils/proto/proto3.proto",
    "chars": 1471,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/test-utils/src/gen/bigint_pb.ts",
    "chars": 2773,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/test-utils/src/gen/eliza_pb.ts",
    "chars": 3176,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/test-utils/src/gen/list_pb.ts",
    "chars": 5153,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/test-utils/src/gen/proto2_pb.ts",
    "chars": 1705,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/test-utils/src/gen/proto3_pb.ts",
    "chars": 5415,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/test-utils/src/index.tsx",
    "chars": 4478,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "packages/test-utils/tsconfig.json",
    "chars": 67,
    "preview": "{\n  \"include\": [\"src/\"],\n  \"extends\": \"../../tsconfig.base.json\"\n}\n"
  },
  {
    "path": "scripts/find-workspace-version.js",
    "chars": 718,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "scripts/gh-diffcheck.js",
    "chars": 1178,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "scripts/release.js",
    "chars": 2112,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "scripts/set-workspace-version.js",
    "chars": 8899,
    "preview": "#!/usr/bin/env node\n\n// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (th"
  },
  {
    "path": "scripts/utils.js",
    "chars": 1653,
    "preview": "// Copyright 2021-2023 The Connect Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you "
  },
  {
    "path": "tsconfig.base.json",
    "chars": 803,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"lib\": [\n      \"ES2017\",\n      // DOM for the fetch and streams API"
  },
  {
    "path": "turbo.json",
    "chars": 839,
    "preview": "{\n  \"$schema\": \"https://turbo.build/schema.json\",\n  \"tasks\": {\n    \"build\": {\n      \"dependsOn\": [\"^build\", \"generate\"],"
  }
]

About this extraction

This page contains the full source code of the connectrpc/connect-query-es GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 111 files (353.8 KB), approximately 122.2k tokens, and a symbol index with 87 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!