├── .changeset ├── README.md ├── config.json ├── heavy-hairs-bow.md ├── nervous-flies-confess.md ├── old-ears-hunt.md ├── serious-chefs-march.md └── slow-hotels-yawn.md ├── .editorconfig ├── .gitattributes ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── RFC.md │ ├── bug_report.yaml │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md ├── actions │ ├── discord-message │ │ ├── action.mjs │ │ └── action.yml │ └── pnpm-run │ │ ├── action.mjs │ │ └── action.yml └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs ├── README.md ├── advanced │ ├── README.md │ ├── authentication.md │ ├── authoring-exchanges.md │ ├── auto-populate-mutations.md │ ├── debugging.md │ ├── persistence-and-uploads.md │ ├── retry-operations.md │ ├── server-side-rendering.md │ ├── subscriptions.md │ └── testing.md ├── api │ ├── README.md │ ├── auth-exchange.md │ ├── core.md │ ├── execute-exchange.md │ ├── graphcache.md │ ├── preact.md │ ├── refocus-exchange.md │ ├── request-policy-exchange.md │ ├── retry-exchange.md │ ├── svelte.md │ ├── urql.md │ └── vue.md ├── architecture.md ├── assets │ ├── commutative-layers.png │ ├── devtools-timeline.png │ ├── logos │ │ ├── egghead.png │ │ ├── gatsby.png │ │ ├── github.png │ │ ├── loveholidays.png │ │ ├── open-social.png │ │ ├── sturdy.png │ │ ├── swan.png │ │ ├── the-atlantic.png │ │ └── tripadvisor.png │ ├── next-logo.png │ ├── partial-results.png │ ├── query-document-info.png │ ├── urql-client-architecture.png │ ├── urql-combined-error.png │ ├── urql-document-caching.png │ ├── urql-event-hub.png │ ├── urql-exchanges.png │ ├── urql-normalized-cache.png │ ├── urql-operation-keys.png │ ├── urql-signals.png │ └── urql-spoiler.png ├── basics │ ├── README.md │ ├── core.md │ ├── document-caching.md │ ├── errors.md │ ├── react-preact.md │ ├── svelte.md │ ├── typescript-integration.md │ ├── ui-patterns.md │ └── vue.md ├── comparison.md ├── graphcache │ ├── README.md │ ├── cache-updates.md │ ├── errors.md │ ├── local-directives.md │ ├── local-resolvers.md │ ├── normalized-caching.md │ ├── offline.md │ └── schema-awareness.md └── showcase.md ├── examples ├── README.md ├── pnpm-workspace.yaml ├── with-apq │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── LocationsList.jsx │ │ └── index.jsx │ └── vite.config.js ├── with-defer-stream-directives │ ├── README.md │ ├── index.html │ ├── package.json │ ├── server │ │ ├── apollo-server.js │ │ ├── graphql-yoga.js │ │ └── schema.js │ ├── src │ │ ├── App.jsx │ │ ├── Songs.jsx │ │ └── index.jsx │ └── vite.config.js ├── with-graphcache-pagination │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── PaginatedNpmSearch.jsx │ │ └── index.jsx │ └── vite.config.js ├── with-graphcache-updates │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── client.js │ │ ├── index.jsx │ │ └── pages │ │ │ ├── Links.jsx │ │ │ └── LoginForm.jsx │ └── vite.config.js ├── with-infinite-pagination │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── SearchResults.jsx │ │ └── index.jsx │ └── vite.config.js ├── with-multipart │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── FileUpload.jsx │ │ └── index.jsx │ └── vite.config.js ├── with-next │ ├── README.md │ ├── app │ │ ├── layout.tsx │ │ ├── non-rsc │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ │ └── page.tsx │ ├── next-env.d.ts │ ├── package.json │ └── tsconfig.json ├── with-pagination │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── PaginatedNpmSearch.jsx │ │ └── index.jsx │ └── vite.config.js ├── with-react-native │ ├── App.js │ ├── README.md │ ├── app.json │ ├── index.js │ ├── package.json │ └── src │ │ └── screens │ │ └── PokemonList.js ├── with-react │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── PokemonList.jsx │ │ └── index.jsx │ └── vite.config.js ├── with-refresh-auth │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── authStore.js │ │ ├── client.js │ │ ├── index.jsx │ │ └── pages │ │ │ ├── LoginForm.jsx │ │ │ └── Profile.jsx │ └── vite.config.js ├── with-retry │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── Color.jsx │ │ └── index.jsx │ └── vite.config.js ├── with-subscriptions-via-fetch │ ├── README.md │ ├── index.html │ ├── package.json │ ├── server │ │ ├── graphql-yoga.js │ │ └── schema.js │ ├── src │ │ ├── App.jsx │ │ ├── Songs.jsx │ │ └── index.jsx │ └── vite.config.js ├── with-svelte │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.svelte │ │ ├── PokemonList.svelte │ │ └── main.js │ └── vite.config.mjs └── with-vue3 │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ ├── App.vue │ ├── PokemonList.vue │ └── main.js │ └── vite.config.js ├── exchanges ├── auth │ ├── CHANGELOG.md │ ├── README.md │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── authExchange.test.ts │ │ ├── authExchange.ts │ │ └── index.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── context │ ├── CHANGELOG.md │ ├── README.md │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── context.test.ts │ │ ├── context.ts │ │ └── index.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── execute │ ├── CHANGELOG.md │ ├── README.md │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── execute.test.ts │ │ ├── execute.ts │ │ └── index.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── graphcache │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── benchmarks │ │ ├── 10000Reads.html │ │ ├── 10000ReadsComplex.html │ │ ├── 10000Writes.html │ │ ├── 10000WritesComplex.html │ │ ├── 1000Reads.html │ │ ├── 1000ReadsComplex.html │ │ ├── 1000Writes.html │ │ ├── 1000WritesComplex.html │ │ ├── 100Reads.html │ │ ├── 100ReadsComplex.html │ │ ├── 100Writes.html │ │ ├── 100WritesComplex.html │ │ ├── 50000Reads.html │ │ ├── 50000Writes.html │ │ ├── 5000Reads.html │ │ ├── 5000Writes.html │ │ ├── 500Reads.html │ │ ├── 500Writes.html │ │ ├── addTodo.html │ │ ├── benchmarks.js │ │ ├── entities.js │ │ ├── makeEntries.js │ │ ├── operations.js │ │ ├── package.json │ │ ├── readMe.md │ │ ├── updateTodo.html │ │ ├── urqlClient.js │ │ └── yarn.lock │ ├── cypress.config.js │ ├── cypress │ │ ├── fixtures │ │ │ └── example.json │ │ ├── plugins │ │ │ └── index.js │ │ └── support │ │ │ ├── component-index.html │ │ │ └── component.js │ ├── e2e-tests │ │ ├── query.spec.tsx │ │ └── updates.spec.tsx │ ├── help.md │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── ast │ │ │ ├── graphql.ts │ │ │ ├── index.ts │ │ │ ├── node.ts │ │ │ ├── schema.ts │ │ │ ├── schemaPredicates.test.ts │ │ │ ├── schemaPredicates.ts │ │ │ ├── traversal.test.ts │ │ │ ├── traversal.ts │ │ │ ├── variables.test.ts │ │ │ └── variables.ts │ │ ├── cacheExchange-types.test.ts │ │ ├── cacheExchange.test.ts │ │ ├── cacheExchange.ts │ │ ├── default-storage │ │ │ └── index.ts │ │ ├── extras │ │ │ ├── index.ts │ │ │ ├── relayPagination.test.ts │ │ │ ├── relayPagination.ts │ │ │ ├── simplePagination.test.ts │ │ │ └── simplePagination.ts │ │ ├── helpers │ │ │ ├── help.ts │ │ │ └── operation.ts │ │ ├── index.ts │ │ ├── offlineExchange.test.ts │ │ ├── offlineExchange.ts │ │ ├── operations │ │ │ ├── invalidate.ts │ │ │ ├── query.test.ts │ │ │ ├── query.ts │ │ │ ├── shared.test.ts │ │ │ ├── shared.ts │ │ │ ├── write.test.ts │ │ │ └── write.ts │ │ ├── store │ │ │ ├── __snapshots__ │ │ │ │ └── store.test.ts.snap │ │ │ ├── data.test.ts │ │ │ ├── data.ts │ │ │ ├── keys.ts │ │ │ ├── store.test.ts │ │ │ └── store.ts │ │ ├── test-utils │ │ │ ├── altered_root_schema.json │ │ │ ├── examples-1.test.ts │ │ │ ├── examples-2.test.ts │ │ │ ├── examples-3.test.ts │ │ │ ├── relayPagination_schema.json │ │ │ ├── simple_schema.json │ │ │ ├── suite.test.ts │ │ │ └── utils.ts │ │ └── types.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── persisted │ ├── CHANGELOG.md │ ├── README.md │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── persistedExchange.test.ts │ │ ├── persistedExchange.ts │ │ ├── sha256.ts │ │ └── test-utils.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── populate │ ├── CHANGELOG.md │ ├── README.md │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── helpers │ │ │ ├── help.ts │ │ │ ├── node.ts │ │ │ └── traverse.ts │ │ ├── index.ts │ │ ├── populateExchange.test.ts │ │ └── populateExchange.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── refocus │ ├── CHANGELOG.md │ ├── README.md │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── refocusExchange.test.ts │ │ └── refocusExchange.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── request-policy │ ├── CHANGELOG.md │ ├── README.md │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── requestPolicyExchange.test.ts │ │ └── requestPolicyExchange.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── retry │ ├── CHANGELOG.md │ ├── README.md │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── retryExchange.test.ts │ │ └── retryExchange.ts │ ├── tsconfig.json │ └── vitest.config.ts └── throw-on-error │ ├── CHANGELOG.md │ ├── README.md │ ├── jsr.json │ ├── package.json │ ├── src │ ├── index.ts │ ├── throwOnErrorExchange.test.ts │ └── throwOnErrorExchange.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── package.json ├── packages ├── core │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── __snapshots__ │ │ │ └── client.test.ts.snap │ │ ├── client.test.ts │ │ ├── client.ts │ │ ├── exchanges │ │ │ ├── __snapshots__ │ │ │ │ ├── fetch.test.ts.snap │ │ │ │ └── subscription.test.ts.snap │ │ │ ├── cache.test.ts │ │ │ ├── cache.ts │ │ │ ├── compose.test.ts │ │ │ ├── compose.ts │ │ │ ├── debug.test.ts │ │ │ ├── debug.ts │ │ │ ├── fallback.test.ts │ │ │ ├── fallback.ts │ │ │ ├── fetch.test.ts │ │ │ ├── fetch.ts │ │ │ ├── index.ts │ │ │ ├── map.test.ts │ │ │ ├── map.ts │ │ │ ├── ssr.test.ts │ │ │ ├── ssr.ts │ │ │ ├── subscription.test.ts │ │ │ └── subscription.ts │ │ ├── gql.test.ts │ │ ├── gql.ts │ │ ├── index.ts │ │ ├── internal │ │ │ ├── __snapshots__ │ │ │ │ └── fetchSource.test.ts.snap │ │ │ ├── fetchOptions.test.ts │ │ │ ├── fetchOptions.ts │ │ │ ├── fetchSource.test.ts │ │ │ ├── fetchSource.ts │ │ │ └── index.ts │ │ ├── test-utils │ │ │ ├── index.ts │ │ │ └── samples.ts │ │ ├── types.ts │ │ └── utils │ │ │ ├── __snapshots__ │ │ │ └── error.test.ts.snap │ │ │ ├── collectTypenames.test.ts │ │ │ ├── collectTypenames.ts │ │ │ ├── error.test.ts │ │ │ ├── error.ts │ │ │ ├── formatDocument.test.ts │ │ │ ├── formatDocument.ts │ │ │ ├── graphql.ts │ │ │ ├── hash.test.ts │ │ │ ├── hash.ts │ │ │ ├── index.ts │ │ │ ├── operation.ts │ │ │ ├── request.test.ts │ │ │ ├── request.ts │ │ │ ├── result.test.ts │ │ │ ├── result.ts │ │ │ ├── streamUtils.ts │ │ │ ├── variables.test.ts │ │ │ └── variables.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── introspection │ ├── CHANGELOG.md │ ├── README.md │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── getIntrospectedSchema.ts │ │ ├── index.ts │ │ └── minifyIntrospectionQuery.ts │ └── tsconfig.json ├── next-urql │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── DataHydrationContext.ts │ │ ├── Provider.ts │ │ ├── htmlescape.ts │ │ ├── index.ts │ │ ├── rsc.ts │ │ ├── useQuery.ts │ │ └── useUrqlValue.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── preact-urql │ ├── CHANGELOG.md │ ├── README.md │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── components │ │ │ ├── Mutation.test.tsx │ │ │ ├── Mutation.ts │ │ │ ├── Query.test.tsx │ │ │ ├── Query.ts │ │ │ ├── Subscription.test.tsx │ │ │ ├── Subscription.ts │ │ │ └── index.ts │ │ ├── context.ts │ │ ├── hooks │ │ │ ├── constants.ts │ │ │ ├── index.ts │ │ │ ├── useMutation.test.tsx │ │ │ ├── useMutation.ts │ │ │ ├── useQuery.test.tsx │ │ │ ├── useQuery.ts │ │ │ ├── useRequest.ts │ │ │ ├── useSource.ts │ │ │ ├── useSubscription.test.tsx │ │ │ └── useSubscription.ts │ │ └── index.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── react-urql │ ├── CHANGELOG.md │ ├── README.md │ ├── core │ │ ├── index.d.ts │ │ ├── index.esm.js │ │ ├── index.js │ │ ├── package.json │ │ └── yarn.lock │ ├── cypress.config.js │ ├── cypress │ │ ├── fixtures │ │ │ └── example.json │ │ └── support │ │ │ ├── component-index.html │ │ │ └── component.js │ ├── e2e-tests │ │ └── useQuery.spec.tsx │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── components │ │ │ ├── Mutation.test.tsx │ │ │ ├── Mutation.ts │ │ │ ├── Query.test.tsx │ │ │ ├── Query.ts │ │ │ ├── Subscription.ts │ │ │ └── index.ts │ │ ├── context.ts │ │ ├── hooks │ │ │ ├── __snapshots__ │ │ │ │ ├── useMutation.test.tsx.snap │ │ │ │ ├── useQuery.test.tsx.snap │ │ │ │ └── useSubscription.test.tsx.snap │ │ │ ├── cache.ts │ │ │ ├── index.ts │ │ │ ├── state.ts │ │ │ ├── useMutation.test.tsx │ │ │ ├── useMutation.ts │ │ │ ├── useQuery.spec.ts │ │ │ ├── useQuery.test.tsx │ │ │ ├── useQuery.ts │ │ │ ├── useRequest.test.ts │ │ │ ├── useRequest.ts │ │ │ ├── useSubscription.test.tsx │ │ │ └── useSubscription.ts │ │ ├── index.ts │ │ └── test-utils │ │ │ └── ssr.test.tsx │ ├── tsconfig.json │ └── vitest.config.ts ├── site │ ├── CHANGELOG.md │ ├── dist-prod │ │ └── open-source │ │ │ └── urql │ ├── package.json │ ├── plugins │ │ ├── assets-fix │ │ │ └── node.api.js │ │ ├── monorepo-fix │ │ │ └── node.api.js │ │ ├── preact │ │ │ └── node.api.js │ │ └── react-router │ │ │ └── browser.api.js │ ├── public │ │ ├── browserconfig.xml │ │ ├── favicon │ │ │ ├── favicon-16.png │ │ │ ├── favicon-192.png │ │ │ ├── favicon-32.png │ │ │ └── favicon-512.png │ │ └── site.webmanifest │ ├── src │ │ ├── analytics.js │ │ ├── app.js │ │ ├── assets │ │ │ ├── anchor.js │ │ │ ├── anchor.svg │ │ │ ├── badge_runpkg.svg │ │ │ ├── badge_spectacle.svg │ │ │ ├── badge_victory.svg │ │ │ ├── burger.svg │ │ │ ├── chevron.js │ │ │ ├── chevron.svg │ │ │ ├── clock-tile.svg │ │ │ ├── close.svg │ │ │ ├── eagle-tile.svg │ │ │ ├── gql-tile.svg │ │ │ ├── left-triangles.svg │ │ │ ├── logo-sidebar.svg │ │ │ ├── logo_formidable_dark.svg │ │ │ ├── logo_formidable_white.svg │ │ │ ├── logos │ │ │ │ ├── logo-formidable-icon.svg │ │ │ │ └── logo-formidable.svg │ │ │ ├── react-tile.svg │ │ │ ├── right-triangles.svg │ │ │ └── sidebar-badge.svg │ │ ├── components │ │ │ ├── body-copy.js │ │ │ ├── button.js │ │ │ ├── footer.js │ │ │ ├── header.js │ │ │ ├── link.js │ │ │ ├── loading.js │ │ │ ├── markdown.js │ │ │ ├── mdx.js │ │ │ ├── navigation.js │ │ │ ├── panel.js │ │ │ ├── scroll-to-top.js │ │ │ ├── secondary-title.js │ │ │ ├── section-title.js │ │ │ ├── sidebar-search-input.js │ │ │ ├── sidebar.js │ │ │ └── wrapper.js │ │ ├── constants.js │ │ ├── google-analytics.js │ │ ├── google-tag-manager.js │ │ ├── html.js │ │ ├── index.js │ │ ├── screens │ │ │ ├── 404 │ │ │ │ ├── 404.js │ │ │ │ └── index.js │ │ │ ├── docs │ │ │ │ ├── article.js │ │ │ │ ├── header.js │ │ │ │ └── index.js │ │ │ └── home │ │ │ │ ├── _content.js │ │ │ │ ├── features.js │ │ │ │ ├── get-started.js │ │ │ │ ├── hero.js │ │ │ │ ├── index.js │ │ │ │ └── more-oss.js │ │ └── styles │ │ │ ├── global.js │ │ │ └── theme.js │ ├── static.config.js │ └── vercel.json ├── solid-urql │ ├── CHANGELOG.md │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── context.ts │ │ ├── createMutation.test.ts │ │ ├── createMutation.ts │ │ ├── createQuery.test.tsx │ │ ├── createQuery.ts │ │ ├── createSubscription.test.ts │ │ ├── createSubscription.ts │ │ ├── index.ts │ │ ├── suspense.test.tsx │ │ └── utils.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── storage-rn │ ├── CHANGELOG.md │ ├── LICENCE │ ├── README.md │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── makeAsyncStorage.test.ts │ │ └── makeAsyncStorage.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── svelte-urql │ ├── CHANGELOG.md │ ├── README.md │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── common.ts │ │ ├── context.ts │ │ ├── index.ts │ │ ├── mutationStore.test.ts │ │ ├── mutationStore.ts │ │ ├── queryStore.test.ts │ │ ├── queryStore.ts │ │ ├── subscriptionStore.test.ts │ │ └── subscriptionStore.ts │ ├── tsconfig.json │ └── vitest.config.ts └── vue-urql │ ├── CHANGELOG.md │ ├── README.md │ ├── jsr.json │ ├── package.json │ ├── src │ ├── index.ts │ ├── useClient.test.ts │ ├── useClient.ts │ ├── useClientHandle.ts │ ├── useMutation.test.ts │ ├── useMutation.ts │ ├── useQuery.test.ts │ ├── useQuery.ts │ ├── useSubscription.test.ts │ ├── useSubscription.ts │ └── utils.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── scripts ├── actions │ ├── build-all.mjs │ ├── lib │ │ ├── commands.mjs │ │ ├── constants.mjs │ │ ├── github.mjs │ │ └── packages.mjs │ └── pack-all.mjs ├── babel │ ├── transform-debug-target.mjs │ ├── transform-invariant-warning.mjs │ └── transform-pipe.mjs ├── changesets │ ├── changelog.js │ ├── jsr.mjs │ └── version.mjs ├── eslint │ └── preset.js ├── prepare │ ├── index.js │ └── postinstall.js ├── rollup │ ├── cleanup-plugin.mjs │ ├── config.mjs │ ├── plugins.mjs │ └── settings.mjs └── vitest │ └── setup.js ├── tsconfig.json ├── vercel.json └── vitest.config.ts /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/master/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@0.3.0/schema.json", 3 | "changelog": "../scripts/changesets/changelog.js", 4 | "commit": false, 5 | "access": "public", 6 | "baseBranch": "main", 7 | "updateInternalDependencies": "minor", 8 | "snapshot": { 9 | "prereleaseTemplate": "{tag}-{commit}", 10 | "useCalculatedVersion": true 11 | }, 12 | "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": { 13 | "onlyUpdatePeerDependentsWhenOutOfRange": true, 14 | "updateInternalDependents": "out-of-range" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.changeset/heavy-hairs-bow.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@urql/core": patch 3 | --- 4 | 5 | Correct typo in cacheHit debug message of the `debugExchange` 6 | -------------------------------------------------------------------------------- /.changeset/nervous-flies-confess.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@urql/core': patch 3 | --- 4 | 5 | Fix `fetchSource` not text-decoding response chunks as streams, which could cause UTF-8 decoding to break. 6 | -------------------------------------------------------------------------------- /.changeset/old-ears-hunt.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@urql/exchange-graphcache': patch 3 | '@urql/core': patch 4 | --- 5 | 6 | Fix compatibility with Typescript >5.5 (See: https://github.com/0no-co/graphql.web/pull/49) 7 | -------------------------------------------------------------------------------- /.changeset/serious-chefs-march.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@urql/core': patch 3 | --- 4 | 5 | Change debug log verbosity to `console.debug` rather than `console.log` 6 | -------------------------------------------------------------------------------- /.changeset/slow-hotels-yawn.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@urql/exchange-retry": patch 3 | --- 4 | 5 | Mark options argument as optional (`retryExchange()`) 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_size = 2 7 | end_of_line = lf 8 | indent_style = space 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | max_line_length = 100 14 | trim_trailing_whitespace = false 15 | 16 | [COMMIT_EDITMSG] 17 | max_line_length = 0 18 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | /.github/ @urql-graphql/core 2 | /.changeset/config.json @urql-graphql/core 3 | /scripts/actions/* @urql-graphql/core 4 | /scripts/prepare/* @urql-graphql/core 5 | /scripts/rollup/* @urql-graphql/core 6 | /scripts/changesets/* @urql-graphql/core 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/RFC.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'RFC' 3 | about: Propose an enhancement / feature and start a discussion 4 | title: 'RFC: Your Proposal' 5 | labels: "future \U0001F52E" 6 | --- 7 | 8 | 16 | 17 | ## Summary 18 | 19 | 25 | 26 | ## Proposed Solution 27 | 28 | 32 | 33 | ## Requirements 34 | 35 | 43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Ask a question 4 | url: https://github.com/urql-graphql/urql/discussions 5 | about: Ask questions and discuss with other community members 6 | - name: Join the Discord 7 | url: https://urql.dev/discord 8 | about: Chat with maintainers and other community members 9 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 11 | 12 | ## Summary 13 | 14 | 15 | 16 | ## Set of changes 17 | 18 | 23 | -------------------------------------------------------------------------------- /.github/actions/discord-message/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Send a discord message' 2 | description: 'Send a discord message as a result of an urql publish.' 3 | inputs: 4 | publishedPackages: 5 | description: > 6 | A JSON array to present the published packages. The format is `[{"name": "@xx/xx", "version": "1.2.0"}, {"name": "@xx/xy", "version": "0.8.9"}]` 7 | runs: 8 | using: 'node20' 9 | main: 'action.mjs' 10 | -------------------------------------------------------------------------------- /.github/actions/pnpm-run/action.mjs: -------------------------------------------------------------------------------- 1 | import { execa } from 'execa'; 2 | 3 | const run = execa('pnpm', ['run', process.env.INPUT_COMMAND], { 4 | cwd: process.cwd(), 5 | }); 6 | 7 | run.stdout.pipe(process.stdout); 8 | run.stderr.pipe(process.stderr); 9 | 10 | run 11 | .then(result => process.exit(result.exitCode)) 12 | .catch(error => process.exit(error.exitCode || -1)); 13 | -------------------------------------------------------------------------------- /.github/actions/pnpm-run/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Run a pnpm command' 2 | description: 'Locally run a forked pnpm command as an action.' 3 | inputs: 4 | command: 5 | description: 'Command' 6 | default: 'help' 7 | runs: 8 | using: 'node20' 9 | main: 'action.mjs' 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /.vscode 3 | **/node_modules 4 | *.log 5 | .rts2_cache* 6 | .husky 7 | dist/ 8 | build/ 9 | coverage/ 10 | package-lock.json 11 | .DS_Store 12 | .next 13 | 14 | packages/*/LICENSE 15 | exchanges/*/LICENSE 16 | 17 | # TODO: Figure out how to remove these: 18 | tmp/ 19 | dist/ 20 | examples/yarn.lock 21 | examples/pnpm-lock.yaml 22 | examples/package-lock.json 23 | examples/*/public 24 | examples/*/yarn.lock 25 | examples/*/pnpm-lock.yaml 26 | examples/*/package-lock.json 27 | examples/*/ios/ 28 | examples/*/android/ 29 | examples/*/.watchmanconfig 30 | examples/*/metro.config.js 31 | examples/*/babel.config.js 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018–2020 Formidable, 4 | Copyright (c) urql GraphQL Team and other contributors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /docs/api/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: API 3 | order: 9 4 | --- 5 | 6 | # API 7 | 8 | `urql` is a collection of multiple packages. You'll likely be using one of the framework bindings 9 | package or exchange packages, which are all listed in this section. 10 | 11 | Most of these packages will refer to or use utilities and types from the `@urql/core` package. [Read 12 | more about the core package on the "Core" page.](../basics/core.md) 13 | 14 | > **Note:** These API docs are deprecated as we now keep TSDocs in all published packages. 15 | > You can view TSDocs while using these packages in your editor, as long as it supports the 16 | > TypeScript Language Server. 17 | > We're planning to replace these API docs with a separate web app soon. 18 | 19 | - [`@urql/core` API docs](./core.md) 20 | - [`urql` React API docs](./urql.md) 21 | - [`@urql/preact` Preact API docs](./preact.md) 22 | - [`@urql/svelte` Svelte API docs](./svelte.md) 23 | - [`@urql/exchange-graphcache` API docs](./graphcache.md) 24 | - [`@urql/exchange-retry` API docs](./retry-exchange.md) 25 | - [`@urql/exchange-execute` API docs](./execute-exchange.md) 26 | - [`@urql/exchange-request-policy` API docs](./request-policy-exchange.md) 27 | - [`@urql/exchange-auth` API docs](./auth-exchange.md) 28 | - [`@urql/exchange-refocus` API docs](./refocus-exchange.md) 29 | -------------------------------------------------------------------------------- /docs/api/preact.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '@urql/preact' 3 | order: 2 4 | --- 5 | 6 | # @urql/preact 7 | 8 | > **Note:** These API docs are deprecated as we now keep TSDocs in all published packages. 9 | > You can view TSDocs while using these packages in your editor, as long as it supports the 10 | > TypeScript Language Server. 11 | > We're planning to replace these API docs with a separate web app soon. 12 | 13 | The `@urql/preact` API is the same as the React `urql` API. 14 | Please refer to [the "urql" API docs](./urql.md) for details on the Preact API. 15 | -------------------------------------------------------------------------------- /docs/api/refocus-exchange.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '@urql/exchange-refocus' 3 | order: 11 4 | --- 5 | 6 | # Refocus Exchange 7 | 8 | > **Note:** These API docs are deprecated as we now keep TSDocs in all published packages. 9 | > You can view TSDocs while using these packages in your editor, as long as it supports the 10 | > TypeScript Language Server. 11 | > We're planning to replace these API docs with a separate web app soon. 12 | 13 | `@urql/exchange-refocus` is an exchange for the `urql` that tracks currently active operations and redispatches them when the 14 | window regains focus 15 | 16 | ## Quick Start Guide 17 | 18 | First install `@urql/exchange-refocus` alongside `urql`: 19 | 20 | ```sh 21 | yarn add @urql/exchange-refocus 22 | # or 23 | npm install --save @urql/exchange-refocus 24 | ``` 25 | 26 | Then add it to your `Client`, preferably in front of your `cacheExchange` 27 | 28 | ```js 29 | import { createClient, cacheExchange, fetchExchange } from 'urql'; 30 | import { refocusExchange } from '@urql/exchange-refocus'; 31 | 32 | const client = createClient({ 33 | url: 'http://localhost:3000/graphql', 34 | exchanges: [refocusExchange(), cacheExchange, fetchExchange], 35 | }); 36 | ``` 37 | -------------------------------------------------------------------------------- /docs/assets/commutative-layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/commutative-layers.png -------------------------------------------------------------------------------- /docs/assets/devtools-timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/devtools-timeline.png -------------------------------------------------------------------------------- /docs/assets/logos/egghead.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/logos/egghead.png -------------------------------------------------------------------------------- /docs/assets/logos/gatsby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/logos/gatsby.png -------------------------------------------------------------------------------- /docs/assets/logos/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/logos/github.png -------------------------------------------------------------------------------- /docs/assets/logos/loveholidays.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/logos/loveholidays.png -------------------------------------------------------------------------------- /docs/assets/logos/open-social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/logos/open-social.png -------------------------------------------------------------------------------- /docs/assets/logos/sturdy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/logos/sturdy.png -------------------------------------------------------------------------------- /docs/assets/logos/swan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/logos/swan.png -------------------------------------------------------------------------------- /docs/assets/logos/the-atlantic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/logos/the-atlantic.png -------------------------------------------------------------------------------- /docs/assets/logos/tripadvisor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/logos/tripadvisor.png -------------------------------------------------------------------------------- /docs/assets/next-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/next-logo.png -------------------------------------------------------------------------------- /docs/assets/partial-results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/partial-results.png -------------------------------------------------------------------------------- /docs/assets/query-document-info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/query-document-info.png -------------------------------------------------------------------------------- /docs/assets/urql-client-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/urql-client-architecture.png -------------------------------------------------------------------------------- /docs/assets/urql-combined-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/urql-combined-error.png -------------------------------------------------------------------------------- /docs/assets/urql-document-caching.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/urql-document-caching.png -------------------------------------------------------------------------------- /docs/assets/urql-event-hub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/urql-event-hub.png -------------------------------------------------------------------------------- /docs/assets/urql-exchanges.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/urql-exchanges.png -------------------------------------------------------------------------------- /docs/assets/urql-normalized-cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/urql-normalized-cache.png -------------------------------------------------------------------------------- /docs/assets/urql-operation-keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/urql-operation-keys.png -------------------------------------------------------------------------------- /docs/assets/urql-signals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/urql-signals.png -------------------------------------------------------------------------------- /docs/assets/urql-spoiler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/docs/assets/urql-spoiler.png -------------------------------------------------------------------------------- /docs/basics/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Basics 3 | order: 2 4 | --- 5 | 6 | # Basics 7 | 8 | In this chapter we'll explain the basics of `urql` and how to get started with using it without any 9 | prior knowledge. 10 | 11 | - [**React/Preact**](./react-preact.md) covers how to work with the bindings for React/Preact. 12 | - [**Vue**](./vue.md) covers how to work with the bindings for Vue 3. 13 | - [**Svelte**](./svelte.md) covers how to work with the bindings for Svelte. 14 | - [**Core Package**](./core.md) defines why a shared package exists that contains the main 15 | logic of `urql`, and how we can use it directly in Node.js. 16 | 17 | After reading the page for your bindings and the "Core" page you may want to the next two pages in 18 | this section of the documentation: 19 | 20 | - [**Document Caching**](./document-caching.md) explains the default cache mechanism of `urql`, as opposed to the opt-in 21 | [Normalized Cache](../graphcache/normalized-caching.md). 22 | - [**Errors**](../basics/errors.md) contains information on error handling in `urql`. 23 | - [**UI-Patterns**](../basics/ui-patterns.md) presents some common UI-patterns with `urql`. 24 | -------------------------------------------------------------------------------- /examples/pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - '*' 3 | -------------------------------------------------------------------------------- /examples/with-apq/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | with-apq 7 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/with-apq/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-apq", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "vite" 7 | }, 8 | "dependencies": { 9 | "@urql/core": "^5.1.1", 10 | "@urql/exchange-persisted": "^4.3.1", 11 | "graphql": "^16.6.0", 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0", 14 | "urql": "^4.2.2" 15 | }, 16 | "devDependencies": { 17 | "@vitejs/plugin-react": "^3.1.0", 18 | "vite": "^4.2.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/with-apq/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Client, Provider, fetchExchange } from 'urql'; 3 | import { persistedExchange } from '@urql/exchange-persisted'; 4 | 5 | import LocationsList from './LocationsList'; 6 | 7 | const client = new Client({ 8 | url: 'https://trygql.formidable.dev/graphql/apq-weather', 9 | exchanges: [ 10 | persistedExchange({ 11 | preferGetForPersistedQueries: true, 12 | }), 13 | fetchExchange, 14 | ], 15 | }); 16 | 17 | function App() { 18 | return ( 19 | 20 | 21 | 22 | ); 23 | } 24 | 25 | export default App; 26 | -------------------------------------------------------------------------------- /examples/with-apq/src/LocationsList.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { gql, useQuery } from 'urql'; 3 | 4 | const LOCATIONS_QUERY = gql` 5 | query Locations($query: String!) { 6 | locations(query: $query) { 7 | id 8 | name 9 | } 10 | } 11 | `; 12 | 13 | const LocationsList = () => { 14 | const [result] = useQuery({ 15 | query: LOCATIONS_QUERY, 16 | variables: { query: 'LON' }, 17 | }); 18 | 19 | const { data, fetching, error } = result; 20 | 21 | return ( 22 |
23 | {fetching &&

Loading...

} 24 | 25 | {error &&

Oh no... {error.message}

} 26 | 27 | {data && ( 28 | 33 | )} 34 |
35 | ); 36 | }; 37 | 38 | export default LocationsList; 39 | -------------------------------------------------------------------------------- /examples/with-apq/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import App from './App'; 5 | 6 | createRoot(document.getElementById('root')).render(); 7 | -------------------------------------------------------------------------------- /examples/with-apq/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/with-defer-stream-directives/README.md: -------------------------------------------------------------------------------- 1 | # With `@defer` / `@stream` Directives 2 | 3 |

4 | 5 | Open in StackBlitz 9 | 10 | 12 | Open in CodeSandbox 16 | 17 |

18 | 19 | This example shows `urql` in use [with `@defer` and `@stream` 20 | directives](https://graphql.org/blog/2020-12-08-improving-latency-with-defer-and-stream-directives) 21 | in GraphQL. 22 | 23 | To run this example install dependencies and run the `start` script: 24 | 25 | ```sh 26 | yarn install 27 | yarn run start 28 | # or 29 | npm install 30 | npm run start 31 | ``` 32 | 33 | This example contains: 34 | 35 | - The `urql` bindings and a React app with a client set up in [`src/App.jsx`](src/App.jsx) 36 | - A local `graphql-yoga` server set up to test deferred and streamed results in [`server/`](server/). 37 | -------------------------------------------------------------------------------- /examples/with-defer-stream-directives/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | with-defer-stream-directives 7 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/with-defer-stream-directives/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-defer-stream-directives", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "server:apollo": "node server/apollo-server.js", 7 | "server:yoga": "node server/graphql-yoga.js", 8 | "client": "vite", 9 | "start": "run-p client server:yoga" 10 | }, 11 | "pnpm": { 12 | "peerDependencyRules": { 13 | "allowedVersions": { 14 | "graphql": "17" 15 | } 16 | } 17 | }, 18 | "dependencies": { 19 | "@graphql-yoga/plugin-defer-stream": "^1.7.1", 20 | "@urql/core": "^5.1.1", 21 | "@urql/exchange-graphcache": "^7.2.3", 22 | "graphql": "17.0.0-alpha.2", 23 | "react": "^18.2.0", 24 | "react-dom": "^18.2.0", 25 | "urql": "^4.2.2" 26 | }, 27 | "devDependencies": { 28 | "@apollo/server": "^4.4.1", 29 | "@vitejs/plugin-react": "^3.1.0", 30 | "graphql-yoga": "^3.7.1", 31 | "npm-run-all": "^4.1.5", 32 | "vite": "^4.2.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/with-defer-stream-directives/server/apollo-server.js: -------------------------------------------------------------------------------- 1 | // NOTE: This currently fails because responses for @defer/@stream are not sent 2 | // as multipart responses, but the request fails silently with an empty JSON response payload 3 | 4 | const { ApolloServer } = require('@apollo/server'); 5 | const { startStandaloneServer } = require('@apollo/server/standalone'); 6 | const { schema } = require('./schema'); 7 | 8 | const server = new ApolloServer({ schema }); 9 | 10 | startStandaloneServer(server, { 11 | listen: { 12 | port: 3004, 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /examples/with-defer-stream-directives/server/graphql-yoga.js: -------------------------------------------------------------------------------- 1 | const { createYoga } = require('graphql-yoga'); 2 | const { useDeferStream } = require('@graphql-yoga/plugin-defer-stream'); 3 | const { createServer } = require('http'); 4 | const { schema } = require('./schema'); 5 | 6 | const yoga = createYoga({ 7 | schema, 8 | plugins: [useDeferStream()], 9 | }); 10 | 11 | const server = createServer(yoga); 12 | 13 | server.listen(3004); 14 | -------------------------------------------------------------------------------- /examples/with-defer-stream-directives/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Client, Provider, fetchExchange } from 'urql'; 3 | 4 | import { cacheExchange } from '@urql/exchange-graphcache'; 5 | 6 | import Songs from './Songs'; 7 | 8 | const cache = cacheExchange({ 9 | keys: { 10 | Alphabet: data => data.char, 11 | Song: () => null, 12 | }, 13 | }); 14 | 15 | const client = new Client({ 16 | url: 'http://localhost:3004/graphql', 17 | exchanges: [cache, fetchExchange], 18 | }); 19 | 20 | function App() { 21 | return ( 22 | 23 | 24 | 25 | ); 26 | } 27 | 28 | export default App; 29 | -------------------------------------------------------------------------------- /examples/with-defer-stream-directives/src/Songs.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { gql, useQuery } from 'urql'; 3 | 4 | const SecondVerseFragment = gql` 5 | fragment secondVerseFields on Song { 6 | secondVerse 7 | } 8 | `; 9 | 10 | const SONGS_QUERY = gql` 11 | query App_Query { 12 | song { 13 | firstVerse 14 | ...secondVerseFields @defer 15 | } 16 | alphabet @stream(initialCount: 3) { 17 | char 18 | } 19 | } 20 | 21 | ${SecondVerseFragment} 22 | `; 23 | 24 | const Song = React.memo(function Song({ song }) { 25 | return ( 26 |
27 |

{song.firstVerse}

28 |

{song.secondVerse}

29 |
30 | ); 31 | }); 32 | 33 | const LocationsList = () => { 34 | const [result] = useQuery({ 35 | query: SONGS_QUERY, 36 | }); 37 | 38 | const { data } = result; 39 | 40 | return ( 41 |
42 | {data && ( 43 | <> 44 | 45 | {data.alphabet.map(i => ( 46 |
{i.char}
47 | ))} 48 | 49 | )} 50 |
51 | ); 52 | }; 53 | 54 | export default LocationsList; 55 | -------------------------------------------------------------------------------- /examples/with-defer-stream-directives/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import App from './App'; 5 | 6 | createRoot(document.getElementById('root')).render(); 7 | -------------------------------------------------------------------------------- /examples/with-defer-stream-directives/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/with-graphcache-pagination/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | with-graphcache-pagination 7 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/with-graphcache-pagination/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-graphcache-pagination", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "vite" 7 | }, 8 | "dependencies": { 9 | "@urql/core": "^5.1.1", 10 | "@urql/exchange-graphcache": "^7.2.3", 11 | "graphql": "^16.6.0", 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0", 14 | "urql": "^4.2.2" 15 | }, 16 | "devDependencies": { 17 | "@vitejs/plugin-react": "^3.1.0", 18 | "vite": "^4.2.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/with-graphcache-pagination/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Client, Provider, fetchExchange } from 'urql'; 3 | import { cacheExchange } from '@urql/exchange-graphcache'; 4 | import { relayPagination } from '@urql/exchange-graphcache/extras'; 5 | 6 | import PaginatedNpmSearch from './PaginatedNpmSearch'; 7 | 8 | const client = new Client({ 9 | url: 'https://trygql.formidable.dev/graphql/relay-npm', 10 | exchanges: [ 11 | cacheExchange({ 12 | resolvers: { 13 | Query: { 14 | search: relayPagination(), 15 | }, 16 | }, 17 | }), 18 | fetchExchange, 19 | ], 20 | }); 21 | 22 | function App() { 23 | return ( 24 | 25 | 26 | 27 | ); 28 | } 29 | 30 | export default App; 31 | -------------------------------------------------------------------------------- /examples/with-graphcache-pagination/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import App from './App'; 5 | 6 | createRoot(document.getElementById('root')).render(); 7 | -------------------------------------------------------------------------------- /examples/with-graphcache-pagination/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/with-graphcache-updates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | with-graphcache-updates 7 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/with-graphcache-updates/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-graphcache-updates", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "vite" 7 | }, 8 | "dependencies": { 9 | "@urql/core": "^5.1.1", 10 | "@urql/exchange-auth": "^2.2.1", 11 | "@urql/exchange-graphcache": "^7.2.3", 12 | "graphql": "^16.6.0", 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0", 15 | "urql": "^4.2.2" 16 | }, 17 | "devDependencies": { 18 | "@vitejs/plugin-react": "^3.1.0", 19 | "vite": "^4.2.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/with-graphcache-updates/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { Provider } from 'urql'; 3 | 4 | import client from './client'; 5 | import Links from './pages/Links'; 6 | import LoginForm from './pages/LoginForm'; 7 | 8 | const Home = () => { 9 | const [isLoggedIn, setIsLoggedIn] = useState(false); 10 | 11 | const onLoginSuccess = auth => { 12 | localStorage.setItem('authToken', auth.token); 13 | setIsLoggedIn(true); 14 | }; 15 | 16 | useEffect(() => { 17 | if (localStorage.getItem('authToken')) { 18 | setIsLoggedIn(true); 19 | } 20 | }, []); 21 | 22 | return isLoggedIn ? : ; 23 | }; 24 | 25 | function App() { 26 | return ( 27 | 28 | 29 | 30 | ); 31 | } 32 | 33 | export default App; 34 | -------------------------------------------------------------------------------- /examples/with-graphcache-updates/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import App from './App'; 5 | 6 | createRoot(document.getElementById('root')).render(); 7 | -------------------------------------------------------------------------------- /examples/with-graphcache-updates/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/with-infinite-pagination/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | with-pagination 7 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/with-infinite-pagination/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-pagination", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "vite" 7 | }, 8 | "dependencies": { 9 | "@urql/core": "^5.1.1", 10 | "graphql": "^16.6.0", 11 | "react": "^18.2.0", 12 | "react-dom": "^18.2.0", 13 | "urql": "^4.2.2" 14 | }, 15 | "devDependencies": { 16 | "@vitejs/plugin-react": "^3.1.0", 17 | "vite": "^4.2.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/with-infinite-pagination/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import App from './App'; 5 | 6 | createRoot(document.getElementById('root')).render(); 7 | -------------------------------------------------------------------------------- /examples/with-infinite-pagination/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/with-multipart/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | with-multipart 7 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/with-multipart/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-multipart", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "vite" 7 | }, 8 | "dependencies": { 9 | "@urql/core": "^5.1.1", 10 | "graphql": "^16.6.0", 11 | "react": "^18.2.0", 12 | "react-dom": "^18.2.0", 13 | "urql": "^4.2.2" 14 | }, 15 | "devDependencies": { 16 | "@vitejs/plugin-react": "^3.1.0", 17 | "vite": "^4.2.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/with-multipart/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Client, Provider, fetchExchange } from 'urql'; 3 | 4 | import FileUpload from './FileUpload'; 5 | 6 | const client = new Client({ 7 | url: 'https://trygql.formidable.dev/graphql/uploads-mock', 8 | exchanges: [fetchExchange], 9 | }); 10 | 11 | function App() { 12 | return ( 13 | 14 | 15 | 16 | ); 17 | } 18 | 19 | export default App; 20 | -------------------------------------------------------------------------------- /examples/with-multipart/src/FileUpload.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { gql, useMutation } from 'urql'; 3 | 4 | const UPLOAD_FILE = gql` 5 | mutation UploadFile($file: Upload!) { 6 | uploadFile(file: $file) { 7 | filename 8 | } 9 | } 10 | `; 11 | 12 | const FileUpload = () => { 13 | const [selectedFile, setSelectedFile] = useState(); 14 | const [result, uploadFile] = useMutation(UPLOAD_FILE); 15 | 16 | const { data, fetching, error } = result; 17 | 18 | const handleFileUpload = () => { 19 | uploadFile({ file: selectedFile }); 20 | }; 21 | 22 | const handleFileChange = event => { 23 | setSelectedFile(event.target.files[0]); 24 | }; 25 | 26 | return ( 27 |
28 | {fetching &&

Loading...

} 29 | 30 | {error &&

Oh no... {error.message}

} 31 | 32 | {data && data.uploadFile ? ( 33 |

File uploaded to {data.uploadFile.filename}

34 | ) : ( 35 |
36 | 37 | 38 | 39 |
40 | )} 41 |
42 | ); 43 | }; 44 | 45 | export default FileUpload; 46 | -------------------------------------------------------------------------------- /examples/with-multipart/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import App from './App'; 5 | 6 | createRoot(document.getElementById('root')).render(); 7 | -------------------------------------------------------------------------------- /examples/with-multipart/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/with-next/README.md: -------------------------------------------------------------------------------- 1 | # With Next.js 2 | 3 |

4 | 5 | Open in StackBlitz 9 | 10 | 11 | Open in CodeSandbox 15 | 16 |

17 | 18 | This example shows `next-urql` and `urql` in use with Next.js as explained [in the "Next.js" section 19 | on the "Server-side Rendering" docs 20 | page](https://formidable.com/open-source/urql/docs/advanced/server-side-rendering/#nextjs). 21 | 22 | To run this example install dependencies and run the `start` script: 23 | 24 | ```sh 25 | yarn install 26 | yarn run start 27 | # or 28 | npm install 29 | npm run start 30 | ``` 31 | -------------------------------------------------------------------------------- /examples/with-next/app/layout.tsx: -------------------------------------------------------------------------------- 1 | export const metadata = { 2 | title: 'Create Next App', 3 | description: 'Generated by create next app', 4 | }; 5 | 6 | export default function RootLayout({ 7 | children, 8 | }: { 9 | children: React.ReactNode; 10 | }) { 11 | return ( 12 | 13 | {children} 14 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /examples/with-next/app/non-rsc/layout.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useMemo } from 'react'; 4 | import { 5 | UrqlProvider, 6 | ssrExchange, 7 | cacheExchange, 8 | fetchExchange, 9 | createClient, 10 | } from '@urql/next'; 11 | 12 | export default function Layout({ children }: React.PropsWithChildren) { 13 | const [client, ssr] = useMemo(() => { 14 | const ssr = ssrExchange({ 15 | isClient: typeof window !== 'undefined', 16 | }); 17 | const client = createClient({ 18 | url: 'https://graphql-pokeapi.graphcdn.app/', 19 | exchanges: [cacheExchange, ssr, fetchExchange], 20 | suspense: true, 21 | }); 22 | 23 | return [client, ssr]; 24 | }, []); 25 | 26 | return ( 27 | 28 | {children} 29 | 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /examples/with-next/app/page.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | import { cacheExchange, createClient, fetchExchange, gql } from '@urql/core'; 3 | import { registerUrql } from '@urql/next/rsc'; 4 | 5 | const makeClient = () => { 6 | return createClient({ 7 | url: 'https://graphql-pokeapi.graphcdn.app/', 8 | exchanges: [cacheExchange, fetchExchange], 9 | }); 10 | }; 11 | 12 | const { getClient } = registerUrql(makeClient); 13 | 14 | const PokemonsQuery = gql` 15 | query { 16 | pokemons(limit: 10) { 17 | results { 18 | id 19 | name 20 | } 21 | } 22 | } 23 | `; 24 | 25 | export default async function Home() { 26 | const result = await getClient().query(PokemonsQuery, {}); 27 | return ( 28 |
29 |

This is rendered as part of an RSC

30 |
    31 | {result.data 32 | ? result.data.pokemons.results.map((x: any) => ( 33 |
  • {x.name}
  • 34 | )) 35 | : JSON.stringify(result.error)} 36 |
37 | Non RSC 38 |
39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /examples/with-next/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /examples/with-next/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-next", 3 | "version": "0.0.0", 4 | "private": true, 5 | "dependencies": { 6 | "@urql/core": "^5.1.1", 7 | "@urql/next": "^1.1.5", 8 | "graphql": "^16.6.0", 9 | "next": "13.4.2", 10 | "react": "^18.2.0", 11 | "react-dom": "^18.2.0", 12 | "urql": "^4.2.2" 13 | }, 14 | "scripts": { 15 | "dev": "next dev", 16 | "start": "next", 17 | "build": "next build" 18 | }, 19 | "devDependencies": { 20 | "@types/react": "18.2.6" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/with-next/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": false, 7 | "forceConsistentCasingInFileNames": true, 8 | "noEmit": true, 9 | "incremental": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ] 21 | }, 22 | "include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"], 23 | "exclude": ["node_modules"] 24 | } 25 | -------------------------------------------------------------------------------- /examples/with-pagination/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | with-pagination 7 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/with-pagination/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-pagination", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "vite" 7 | }, 8 | "dependencies": { 9 | "@urql/core": "^5.1.1", 10 | "graphql": "^16.6.0", 11 | "react": "^18.2.0", 12 | "react-dom": "^18.2.0", 13 | "urql": "^4.2.2" 14 | }, 15 | "devDependencies": { 16 | "@vitejs/plugin-react": "^3.1.0", 17 | "vite": "^4.2.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/with-pagination/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Client, Provider, cacheExchange, fetchExchange } from 'urql'; 3 | 4 | import PaginatedNpmSearch from './PaginatedNpmSearch'; 5 | 6 | const client = new Client({ 7 | url: 'https://trygql.formidable.dev/graphql/relay-npm', 8 | exchanges: [cacheExchange, fetchExchange], 9 | }); 10 | 11 | function App() { 12 | return ( 13 | 14 | 15 | 16 | ); 17 | } 18 | 19 | export default App; 20 | -------------------------------------------------------------------------------- /examples/with-pagination/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import App from './App'; 5 | 6 | createRoot(document.getElementById('root')).render(); 7 | -------------------------------------------------------------------------------- /examples/with-pagination/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/with-react-native/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Client, Provider, cacheExchange, fetchExchange } from 'urql'; 3 | 4 | import PokemonList from './src/screens/PokemonList'; 5 | 6 | const client = new Client({ 7 | url: 'https://trygql.formidable.dev/graphql/basic-pokedex', 8 | exchanges: [cacheExchange, fetchExchange], 9 | }); 10 | 11 | const App = () => { 12 | return ( 13 | 14 | 15 | 16 | ); 17 | }; 18 | 19 | export default App; 20 | -------------------------------------------------------------------------------- /examples/with-react-native/README.md: -------------------------------------------------------------------------------- 1 | # With React Native 2 | 3 |

4 | 5 | Open in StackBlitz 9 | 10 | 12 | Open in CodeSandbox 16 | 17 |

18 | 19 | This example shows `urql` in use with React Native. 20 | 21 | To run this example install dependencies and run the `start` script: 22 | 23 | ```sh 24 | yarn install 25 | yarn run start 26 | # or 27 | npm install 28 | npm run start 29 | ``` 30 | 31 | This example contains: 32 | 33 | - The `urql` bindings and a React Native app with a client set up in [`App.js`](./App.js) 34 | - A query for pokémon in [`src/screens/PokemonList.js`](src/screens/PokemonList.js) 35 | -------------------------------------------------------------------------------- /examples/with-react-native/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "withReactNative", 3 | "displayName": "withReactNative" 4 | } 5 | -------------------------------------------------------------------------------- /examples/with-react-native/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import { AppRegistry } from 'react-native'; 6 | import App from './App'; 7 | import { name as appName } from './app.json'; 8 | 9 | AppRegistry.registerComponent(appName, () => App); 10 | -------------------------------------------------------------------------------- /examples/with-react-native/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-react-native", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "android": "react-native run-android", 7 | "ios": "react-native run-ios", 8 | "start": "react-native start" 9 | }, 10 | "dependencies": { 11 | "@urql/core": "^5.1.1", 12 | "graphql": "^16.6.0", 13 | "react": "18.2.0", 14 | "react-native": "0.71.4", 15 | "urql": "^4.2.2" 16 | }, 17 | "devDependencies": { 18 | "@babel/core": "^7.12.9", 19 | "@babel/preset-env": "^7.20.2", 20 | "@babel/runtime": "^7.12.5", 21 | "metro-react-native-babel-preset": "^0.76.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/with-react/README.md: -------------------------------------------------------------------------------- 1 | # With React 2 | 3 |

4 | 5 | Open in StackBlitz 9 | 10 | 11 | Open in CodeSandbox 15 | 16 |

17 | 18 | This example shows `urql` in use with React, as explained on the ["React/Preact" page of the "Basics" 19 | documentation.](https://formidable.com/open-source/urql/docs/basics/react-preact/) 20 | 21 | To run this example install dependencies and run the `start` script: 22 | 23 | ```sh 24 | yarn install 25 | yarn run start 26 | # or 27 | npm install 28 | npm run start 29 | ``` 30 | 31 | This example contains: 32 | 33 | - The `urql` bindings and a React app with a client set up in [`src/App.jsx`](src/App.jsx) 34 | - A query for pokémon in [`src/PokemonList.jsx`](src/PokemonList.jsx) 35 | -------------------------------------------------------------------------------- /examples/with-react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | with-react 7 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/with-react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-react", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "vite" 7 | }, 8 | "dependencies": { 9 | "@urql/core": "^5.1.1", 10 | "graphql": "^16.6.0", 11 | "react": "^18.2.0", 12 | "react-dom": "^18.2.0", 13 | "urql": "^4.2.2" 14 | }, 15 | "devDependencies": { 16 | "@vitejs/plugin-react": "^3.1.0", 17 | "vite": "^4.2.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/with-react/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Client, Provider, cacheExchange, fetchExchange } from 'urql'; 3 | 4 | import PokemonList from './PokemonList'; 5 | 6 | const client = new Client({ 7 | url: 'https://trygql.formidable.dev/graphql/basic-pokedex', 8 | exchanges: [cacheExchange, fetchExchange], 9 | }); 10 | 11 | function App() { 12 | return ( 13 | 14 | 15 | 16 | ); 17 | } 18 | 19 | export default App; 20 | -------------------------------------------------------------------------------- /examples/with-react/src/PokemonList.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { gql, useQuery } from 'urql'; 3 | 4 | const POKEMONS_QUERY = gql` 5 | query Pokemons { 6 | pokemons(limit: 10) { 7 | id 8 | name 9 | } 10 | } 11 | `; 12 | 13 | const PokemonList = () => { 14 | const [result] = useQuery({ query: POKEMONS_QUERY }); 15 | 16 | const { data, fetching, error } = result; 17 | 18 | return ( 19 |
20 | {fetching &&

Loading...

} 21 | 22 | {error &&

Oh no... {error.message}

} 23 | 24 | {data && ( 25 |
    26 | {data.pokemons.map(pokemon => ( 27 |
  • {pokemon.name}
  • 28 | ))} 29 |
30 | )} 31 |
32 | ); 33 | }; 34 | 35 | export default PokemonList; 36 | -------------------------------------------------------------------------------- /examples/with-react/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import App from './App'; 5 | 6 | createRoot(document.getElementById('root')).render(); 7 | -------------------------------------------------------------------------------- /examples/with-react/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/with-refresh-auth/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | with-refresh-auth 7 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/with-refresh-auth/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-refresh-auth", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "vite" 7 | }, 8 | "dependencies": { 9 | "@urql/core": "^5.1.1", 10 | "@urql/exchange-auth": "^2.2.1", 11 | "graphql": "^16.6.0", 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0", 14 | "urql": "^4.2.2" 15 | }, 16 | "devDependencies": { 17 | "@vitejs/plugin-react": "^3.1.0", 18 | "vite": "^4.2.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/with-refresh-auth/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { Provider } from 'urql'; 3 | 4 | import client from './client'; 5 | 6 | import { getToken, saveAuthData } from './authStore'; 7 | import Profile from './pages/Profile'; 8 | import LoginForm from './pages/LoginForm'; 9 | 10 | const Home = () => { 11 | const [isLoggedIn, setIsLoggedIn] = useState(false); 12 | 13 | const onLoginSuccess = auth => { 14 | saveAuthData(auth); 15 | setIsLoggedIn(true); 16 | }; 17 | 18 | useEffect(() => { 19 | if (getToken()) { 20 | setIsLoggedIn(true); 21 | } 22 | }, []); 23 | 24 | return isLoggedIn ? ( 25 | 26 | ) : ( 27 | 28 | ); 29 | }; 30 | 31 | function App() { 32 | return ( 33 | 34 | 35 | 36 | ); 37 | } 38 | 39 | export default App; 40 | -------------------------------------------------------------------------------- /examples/with-refresh-auth/src/authStore.js: -------------------------------------------------------------------------------- 1 | const TOKEN_KEY = 'token'; 2 | const REFRESH_TOKEN_KEY = 'refresh_token'; 3 | 4 | export const saveAuthData = ({ token, refreshToken }) => { 5 | localStorage.setItem(TOKEN_KEY, token); 6 | localStorage.setItem(REFRESH_TOKEN_KEY, refreshToken); 7 | }; 8 | 9 | export const getToken = () => { 10 | return localStorage.getItem(TOKEN_KEY); 11 | }; 12 | 13 | export const getRefreshToken = () => { 14 | return localStorage.getItem(REFRESH_TOKEN_KEY); 15 | }; 16 | 17 | export const clearStorage = () => { 18 | localStorage.clear(); 19 | }; 20 | -------------------------------------------------------------------------------- /examples/with-refresh-auth/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import App from './App'; 5 | 6 | createRoot(document.getElementById('root')).render(); 7 | -------------------------------------------------------------------------------- /examples/with-refresh-auth/src/pages/Profile.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { gql, useQuery } from 'urql'; 3 | 4 | const PROFILE_QUERY = gql` 5 | query Profile { 6 | me { 7 | id 8 | username 9 | createdAt 10 | } 11 | } 12 | `; 13 | 14 | const Profile = () => { 15 | const [result] = useQuery({ query: PROFILE_QUERY }); 16 | 17 | const { data, fetching, error } = result; 18 | 19 | return ( 20 |
21 | {fetching &&

Loading...

} 22 | 23 | {error &&

Oh no... {error.message}

} 24 | 25 | {data?.me && ( 26 | <> 27 |

profile data

28 |

id: {data.me.id}

29 |

username: {data.me.username}

30 | 31 | )} 32 |
33 | ); 34 | }; 35 | 36 | export default Profile; 37 | -------------------------------------------------------------------------------- /examples/with-refresh-auth/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/with-retry/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | with-retry 7 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/with-retry/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-retry", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "vite" 7 | }, 8 | "dependencies": { 9 | "@urql/core": "^5.1.1", 10 | "@urql/exchange-retry": "^1.3.1", 11 | "graphql": "^16.6.0", 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0", 14 | "urql": "^4.2.2" 15 | }, 16 | "devDependencies": { 17 | "@vitejs/plugin-react": "^3.1.0", 18 | "vite": "^4.2.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/with-retry/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Client, fetchExchange, Provider } from 'urql'; 3 | import { retryExchange } from '@urql/exchange-retry'; 4 | 5 | import Color from './Color'; 6 | 7 | const client = new Client({ 8 | url: 'https://trygql.formidable.dev/graphql/intermittent-colors', 9 | exchanges: [ 10 | retryExchange({ 11 | maxNumberAttempts: 10, 12 | maxDelayMs: 500, 13 | retryIf: error => { 14 | // NOTE: With this deemo schema we have a specific random error to look out for: 15 | return ( 16 | error.graphQLErrors.some(x => x.extensions?.code === 'NO_SOUP') || 17 | !!error.networkError 18 | ); 19 | }, 20 | }), 21 | fetchExchange, 22 | ], 23 | }); 24 | 25 | function App() { 26 | return ( 27 | 28 | 29 | 30 | ); 31 | } 32 | 33 | export default App; 34 | -------------------------------------------------------------------------------- /examples/with-retry/src/Color.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { gql, useQuery } from 'urql'; 3 | 4 | const RANDOM_COLOR_QUERY = gql` 5 | query RandomColor { 6 | randomColor { 7 | name 8 | hex 9 | } 10 | } 11 | `; 12 | 13 | const RandomColorDisplay = () => { 14 | const [result] = useQuery({ query: RANDOM_COLOR_QUERY }); 15 | 16 | const { data, fetching, error } = result; 17 | 18 | return ( 19 |
20 | {fetching &&

Loading...

} 21 | 22 | {error &&

Oh no... {error.message}

} 23 | 24 | {data && ( 25 |
26 | {data.randomColor.name} 27 |
28 | )} 29 | 30 | {result.operation && ( 31 |

32 | To get a result, the retry exchange retried:{' '} 33 | {result.operation.context.retryCount || 0} times. 34 |

35 | )} 36 |
37 | ); 38 | }; 39 | 40 | export default RandomColorDisplay; 41 | -------------------------------------------------------------------------------- /examples/with-retry/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import App from './App'; 5 | 6 | createRoot(document.getElementById('root')).render(); 7 | -------------------------------------------------------------------------------- /examples/with-retry/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/with-subscriptions-via-fetch/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | with-defer-stream-directives 7 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/with-subscriptions-via-fetch/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-subscriptions-via-fetch", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "server": "node server/graphql-yoga.js", 7 | "client": "vite", 8 | "start": "run-p client server" 9 | }, 10 | "dependencies": { 11 | "@urql/core": "^5.1.1", 12 | "@urql/exchange-graphcache": "^7.2.3", 13 | "graphql": "^16.6.0", 14 | "react": "^18.2.0", 15 | "react-dom": "^18.2.0", 16 | "urql": "^4.2.2" 17 | }, 18 | "devDependencies": { 19 | "@vitejs/plugin-react": "^3.1.0", 20 | "graphql-yoga": "^3.7.1", 21 | "npm-run-all": "^4.1.5", 22 | "vite": "^4.2.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/with-subscriptions-via-fetch/server/graphql-yoga.js: -------------------------------------------------------------------------------- 1 | const { createYoga } = require('graphql-yoga'); 2 | const { createServer } = require('http'); 3 | const { schema } = require('./schema'); 4 | 5 | const yoga = createYoga({ schema }); 6 | const server = createServer(yoga); 7 | server.listen(3004); 8 | -------------------------------------------------------------------------------- /examples/with-subscriptions-via-fetch/server/schema.js: -------------------------------------------------------------------------------- 1 | const { 2 | GraphQLList, 3 | GraphQLObjectType, 4 | GraphQLSchema, 5 | GraphQLString, 6 | } = require('graphql'); 7 | 8 | const Alphabet = new GraphQLObjectType({ 9 | name: 'Alphabet', 10 | fields: { 11 | char: { 12 | type: GraphQLString, 13 | }, 14 | }, 15 | }); 16 | 17 | const schema = new GraphQLSchema({ 18 | query: new GraphQLObjectType({ 19 | name: 'Query', 20 | fields: () => ({ 21 | list: { 22 | type: new GraphQLList(Alphabet), 23 | resolve() { 24 | return [{ char: 'Where are my letters?' }]; 25 | }, 26 | }, 27 | }), 28 | }), 29 | subscription: new GraphQLObjectType({ 30 | name: 'Subscription', 31 | fields: () => ({ 32 | alphabet: { 33 | type: Alphabet, 34 | resolve(root) { 35 | return root; 36 | }, 37 | subscribe: async function* () { 38 | for (let letter = 65; letter <= 90; letter++) { 39 | await new Promise(resolve => setTimeout(resolve, 500)); 40 | yield { char: String.fromCharCode(letter) }; 41 | } 42 | }, 43 | }, 44 | }), 45 | }), 46 | }); 47 | 48 | module.exports = { schema }; 49 | -------------------------------------------------------------------------------- /examples/with-subscriptions-via-fetch/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Client, Provider, fetchExchange } from 'urql'; 3 | 4 | import { cacheExchange } from '@urql/exchange-graphcache'; 5 | 6 | import Songs from './Songs'; 7 | 8 | const cache = cacheExchange({ 9 | keys: { 10 | Alphabet: data => data.char, 11 | }, 12 | updates: { 13 | Subscription: { 14 | alphabet(parent, _args, cache) { 15 | const list = cache.resolve('Query', 'list') || []; 16 | list.push(parent.alphabet); 17 | cache.link('Query', 'list', list); 18 | }, 19 | }, 20 | }, 21 | }); 22 | 23 | const client = new Client({ 24 | url: 'http://localhost:3004/graphql', 25 | fetchSubscriptions: true, 26 | exchanges: [cache, fetchExchange], 27 | }); 28 | 29 | function App() { 30 | return ( 31 | 32 | 33 | 34 | ); 35 | } 36 | 37 | export default App; 38 | -------------------------------------------------------------------------------- /examples/with-subscriptions-via-fetch/src/Songs.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { gql, useQuery, useSubscription } from 'urql'; 3 | 4 | const LIST_QUERY = gql` 5 | query List_Query { 6 | list { 7 | char 8 | } 9 | } 10 | `; 11 | 12 | const SONG_SUBSCRIPTION = gql` 13 | subscription App_Subscription { 14 | alphabet { 15 | char 16 | } 17 | } 18 | `; 19 | 20 | const ListQuery = () => { 21 | const [listResult] = useQuery({ 22 | query: LIST_QUERY, 23 | }); 24 | return ( 25 |
26 |

List

27 | {listResult?.data?.list.map(i => ( 28 |
{i.char}
29 | ))} 30 |
31 | ); 32 | }; 33 | 34 | const SongSubscription = () => { 35 | const [songsResult] = useSubscription( 36 | { query: SONG_SUBSCRIPTION }, 37 | (prev = [], data) => [...prev, data.alphabet] 38 | ); 39 | 40 | return ( 41 |
42 |

Song

43 | {songsResult?.data?.map(i => ( 44 |
{i.char}
45 | ))} 46 |
47 | ); 48 | }; 49 | 50 | const LocationsList = () => { 51 | return ( 52 | <> 53 | 54 | 55 | 56 | ); 57 | }; 58 | 59 | export default LocationsList; 60 | -------------------------------------------------------------------------------- /examples/with-subscriptions-via-fetch/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import App from './App'; 5 | 6 | createRoot(document.getElementById('root')).render(); 7 | -------------------------------------------------------------------------------- /examples/with-subscriptions-via-fetch/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/with-svelte/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /public/build/ 3 | 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /examples/with-svelte/README.md: -------------------------------------------------------------------------------- 1 | # With Svelte 2 | 3 |

4 | 5 | Open in StackBlitz 9 | 10 | 11 | Open in CodeSandbox 15 | 16 |

17 | 18 | This example shows `@urql/svelte` in use with Svelte, as explained on the ["Svelte" page of the "Basics" 19 | documentation.](https://formidable.com/open-source/urql/docs/basics/svelte/) 20 | 21 | To run this example install dependencies and run the `start` script: 22 | 23 | ```sh 24 | yarn install 25 | yarn run start 26 | # or 27 | npm install 28 | npm run start 29 | ``` 30 | 31 | This example contains: 32 | 33 | - The `@urql/svelte` bindings with a client set up in [`src/App.svelte`](src/App.svelte) 34 | - A query for pokémon in [`src/PokemonList.svelte`](src/pages/PokemonList.svelte) 35 | -------------------------------------------------------------------------------- /examples/with-svelte/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | with-svelte 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/with-svelte/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-svelte", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "start": "vite", 7 | "build": "vite build", 8 | "serve": "vite preview" 9 | }, 10 | "dependencies": { 11 | "@urql/core": "^5.1.1", 12 | "@urql/svelte": "^4.2.3", 13 | "graphql": "^16.6.0", 14 | "svelte": "^4.0.5" 15 | }, 16 | "devDependencies": { 17 | "@sveltejs/vite-plugin-svelte": "^2.4.2", 18 | "vite": "^4.2.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/with-svelte/src/App.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/with-svelte/src/PokemonList.svelte: -------------------------------------------------------------------------------- 1 | 27 | 28 |
29 | {#if $pokemons.fetching} 30 | Loading... 31 | {:else if $pokemons.error} 32 | Oh no... {$pokemons.error.message} 33 | {:else} 34 |
    35 | {#each $pokemons.data.pokemons as pokemon} 36 |
  • {pokemon.name}
  • 37 | {/each} 38 |
39 | {/if} 40 | 41 | 42 |
43 | -------------------------------------------------------------------------------- /examples/with-svelte/src/main.js: -------------------------------------------------------------------------------- 1 | import App from './App.svelte'; 2 | 3 | var app = new App({ 4 | target: document.body, 5 | }); 6 | 7 | export default app; 8 | -------------------------------------------------------------------------------- /examples/with-svelte/vite.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import { svelte } from '@sveltejs/vite-plugin-svelte'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [svelte()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/with-vue3/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | *.local -------------------------------------------------------------------------------- /examples/with-vue3/README.md: -------------------------------------------------------------------------------- 1 | # With Vue 3 2 | 3 |

4 | 5 | Open in StackBlitz 9 | 10 | 11 | Open in CodeSandbox 15 | 16 |

17 | 18 | This example shows `@urql/vue` in use with Vue 3, as explained on the ["Vue" page of the "Basics" 19 | documentation.](https://formidable.com/open-source/urql/docs/basics/vue/) 20 | 21 | To run this example install dependencies and run the `start` script: 22 | 23 | ```sh 24 | yarn install 25 | yarn run start 26 | # or 27 | npm install 28 | npm run start 29 | ``` 30 | 31 | This example contains: 32 | 33 | - The `@urql/vue` bindings with a client set up in [`src/App.vue`](src/App.vue) 34 | - A suspense loading boundary in the `App` component in [`src/App.vue`](src/App.vue) 35 | - A query for pokémon in [`src/PokemonList.vue`](src/pages/PokemonList.vue) 36 | -------------------------------------------------------------------------------- /examples/with-vue3/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vite App 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/with-vue3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-vue3", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "vite", 7 | "build": "vite build", 8 | "serve": "vite preview" 9 | }, 10 | "dependencies": { 11 | "@urql/core": "^5.1.1", 12 | "@urql/vue": "^1.4.3", 13 | "graphql": "^16.6.0", 14 | "vue": "^3.2.47" 15 | }, 16 | "devDependencies": { 17 | "@vitejs/plugin-vue": "^4.1.0", 18 | "vite": "^4.2.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/with-vue3/src/App.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 29 | -------------------------------------------------------------------------------- /examples/with-vue3/src/PokemonList.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 42 | -------------------------------------------------------------------------------- /examples/with-vue3/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './App.vue'; 3 | 4 | createApp(App).mount('#app'); 5 | -------------------------------------------------------------------------------- /examples/with-vue3/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import vue from '@vitejs/plugin-vue'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [vue()], 7 | }); 8 | -------------------------------------------------------------------------------- /exchanges/auth/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urql/exchange-auth", 3 | "version": "2.2.1", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "exclude": [ 8 | "node_modules", 9 | "cypress", 10 | "**/*.test.*", 11 | "**/*.spec.*", 12 | "**/*.test.*.snap", 13 | "**/*.spec.*.snap" 14 | ] 15 | } -------------------------------------------------------------------------------- /exchanges/auth/src/index.ts: -------------------------------------------------------------------------------- 1 | export { authExchange } from './authExchange'; 2 | export type { AuthUtilities, AuthConfig } from './authExchange'; 3 | -------------------------------------------------------------------------------- /exchanges/auth/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["src"] 4 | } 5 | -------------------------------------------------------------------------------- /exchanges/auth/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vitest/config'; 2 | import baseConfig from '../../vitest.config'; 3 | 4 | export default mergeConfig(baseConfig, {}); 5 | -------------------------------------------------------------------------------- /exchanges/context/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urql/exchange-context", 3 | "version": "0.3.1", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "exclude": [ 8 | "node_modules", 9 | "cypress", 10 | "**/*.test.*", 11 | "**/*.spec.*", 12 | "**/*.test.*.snap", 13 | "**/*.spec.*.snap" 14 | ] 15 | } -------------------------------------------------------------------------------- /exchanges/context/src/index.ts: -------------------------------------------------------------------------------- 1 | export { contextExchange } from './context'; 2 | export type { ContextExchangeArgs } from './context'; 3 | -------------------------------------------------------------------------------- /exchanges/context/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["src"] 4 | } 5 | -------------------------------------------------------------------------------- /exchanges/context/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vitest/config'; 2 | import baseConfig from '../../vitest.config'; 3 | 4 | export default mergeConfig(baseConfig, {}); 5 | -------------------------------------------------------------------------------- /exchanges/execute/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urql/exchange-execute", 3 | "version": "2.3.1", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "exclude": [ 8 | "node_modules", 9 | "cypress", 10 | "**/*.test.*", 11 | "**/*.spec.*", 12 | "**/*.test.*.snap", 13 | "**/*.spec.*.snap" 14 | ] 15 | } -------------------------------------------------------------------------------- /exchanges/execute/src/index.ts: -------------------------------------------------------------------------------- 1 | export { executeExchange } from './execute'; 2 | export type { ExecuteExchangeArgs } from './execute'; 3 | -------------------------------------------------------------------------------- /exchanges/execute/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["src"] 4 | } 5 | -------------------------------------------------------------------------------- /exchanges/execute/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vitest/config'; 2 | import baseConfig from '../../vitest.config'; 3 | 4 | export default mergeConfig(baseConfig, {}); 5 | -------------------------------------------------------------------------------- /exchanges/graphcache/.gitignore: -------------------------------------------------------------------------------- 1 | /extras 2 | /default-storage 3 | -------------------------------------------------------------------------------- /exchanges/graphcache/benchmarks/10000Reads.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10000 Reads 7 | 10 | 11 | 12 | 13 |
14 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /exchanges/graphcache/benchmarks/10000ReadsComplex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10000 Reads Complex 7 | 10 | 11 | 12 | 13 |
14 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /exchanges/graphcache/benchmarks/10000Writes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10000 Writes 7 | 10 | 11 | 12 | 13 |
14 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /exchanges/graphcache/benchmarks/10000WritesComplex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10000 Writes Complex 7 | 10 | 11 | 12 | 13 |
14 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /exchanges/graphcache/benchmarks/1000Reads.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 1000 Reads 7 | 10 | 11 | 12 | 13 |
14 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /exchanges/graphcache/benchmarks/1000ReadsComplex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 1000 Reads Complex 7 | 10 | 11 | 12 | 13 |
14 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /exchanges/graphcache/benchmarks/1000Writes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 1000 Writes 7 | 10 | 11 | 12 | 13 |
14 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /exchanges/graphcache/benchmarks/1000WritesComplex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 1000 Writes Complex 7 | 10 | 11 | 12 | 13 |
14 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /exchanges/graphcache/benchmarks/100Reads.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 100 Reads 7 | 10 | 11 | 12 | 13 |
14 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /exchanges/graphcache/benchmarks/100ReadsComplex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 100 Reads Complex 7 | 10 | 11 | 12 | 13 |
14 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /exchanges/graphcache/benchmarks/100Writes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 100 Writes 7 | 10 | 11 | 12 | 13 |
14 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /exchanges/graphcache/benchmarks/100WritesComplex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 100 Writes Complex 7 | 10 | 11 | 12 | 13 |
14 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /exchanges/graphcache/benchmarks/addTodo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Add Todo 7 | 10 | 11 | 12 | 13 |
14 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /exchanges/graphcache/benchmarks/makeEntries.js: -------------------------------------------------------------------------------- 1 | // create a function that will take in a number of times to be run and a function that will produce an entry/entity 2 | export const makeEntries = (amount, makeEntry) => { 3 | // create array of entries to be outputted 4 | const entries = []; 5 | // iterate from 0 up to the amount inputted 6 | for (let i = 0; i < amount; i += 1) { 7 | // each iteration, create an entry and pass it the current index & push it into output array 8 | const entry = makeEntry(i); 9 | entries.push(entry); 10 | } 11 | // return array of entries 12 | return entries; 13 | }; 14 | -------------------------------------------------------------------------------- /exchanges/graphcache/benchmarks/updateTodo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Update Todo 7 | 10 | 11 | 12 | 13 |
14 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /exchanges/graphcache/cypress.config.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line 2 | const { defineConfig } = require('cypress'); 3 | // eslint-disable-next-line 4 | const tsconfigPaths = require('vite-tsconfig-paths').default; 5 | 6 | module.exports = defineConfig({ 7 | video: false, 8 | 9 | e2e: { 10 | setupNodeEvents(_on, _config) { 11 | /*noop*/ 12 | }, 13 | supportFile: false, 14 | }, 15 | component: { 16 | specPattern: './**/e2e-tests/*spec.tsx', 17 | devServer: { 18 | framework: 'react', 19 | bundler: 'vite', 20 | viteConfig: { 21 | plugins: [tsconfigPaths()], 22 | server: { 23 | fs: { 24 | allow: ['../..'], 25 | }, 26 | }, 27 | }, 28 | }, 29 | }, 30 | }); 31 | -------------------------------------------------------------------------------- /exchanges/graphcache/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /exchanges/graphcache/cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line 2 | const { startDevServer } = require('@cypress/vite-dev-server'); 3 | // eslint-disable-next-line 4 | const path = require('path'); 5 | 6 | /** 7 | * @type {Cypress.PluginConfig} 8 | */ 9 | module.exports = (on, _config) => { 10 | on('dev-server:start', options => 11 | startDevServer({ 12 | options, 13 | }) 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /exchanges/graphcache/cypress/support/component-index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Components App 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /exchanges/graphcache/cypress/support/component.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/component.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | import { mount } from 'cypress/react'; 17 | 18 | Cypress.Commands.add('mount', mount); 19 | 20 | // Example use: 21 | // cy.mount() 22 | -------------------------------------------------------------------------------- /exchanges/graphcache/help.md: -------------------------------------------------------------------------------- 1 | This file (`exchanges/graphcache/help.md`) has been moved to `docs/graphcache/errors.md` 2 | 3 | If you are looking at this in a browser 4 | 5 | - ...and your URL looks like this: `github.com/urql-graphql/urql/blob/main/exchanges/graphcache/help.md#15` 6 | - ...in the URL, replace `exchanges/graphcache/help.md` with `docs/graphcache/errors.md` 7 | - ...and keep the `#15` 8 | - ...and then you will get help with your error! 9 | -------------------------------------------------------------------------------- /exchanges/graphcache/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urql/exchange-graphcache", 3 | "version": "7.2.3", 4 | "exports": { 5 | ".": "./src/index.ts", 6 | "./extras": "./src/extras/index.ts", 7 | "./default-storage": "./src/default-storage/index.ts" 8 | }, 9 | "exclude": [ 10 | "node_modules", 11 | "cypress", 12 | "**/*.test.*", 13 | "**/*.spec.*", 14 | "**/*.test.*.snap", 15 | "**/*.spec.*.snap" 16 | ] 17 | } -------------------------------------------------------------------------------- /exchanges/graphcache/src/ast/index.ts: -------------------------------------------------------------------------------- 1 | export * from './variables'; 2 | export * from './traversal'; 3 | export * from './schema'; 4 | export * from './schemaPredicates'; 5 | export * from './node'; 6 | -------------------------------------------------------------------------------- /exchanges/graphcache/src/extras/index.ts: -------------------------------------------------------------------------------- 1 | export { relayPagination } from './relayPagination'; 2 | export { simplePagination } from './simplePagination'; 3 | -------------------------------------------------------------------------------- /exchanges/graphcache/src/helpers/operation.ts: -------------------------------------------------------------------------------- 1 | import type { Operation, RequestPolicy, OperationDebugMeta } from '@urql/core'; 2 | import { makeOperation } from '@urql/core'; 3 | 4 | // Returns the given operation result with added cacheOutcome meta field 5 | export const addMetadata = ( 6 | operation: Operation, 7 | meta: OperationDebugMeta 8 | ): Operation => 9 | makeOperation(operation.kind, operation, { 10 | ...operation.context, 11 | meta: { 12 | ...operation.context.meta, 13 | ...meta, 14 | }, 15 | }); 16 | 17 | // Copy an operation and change the requestPolicy to skip the cache 18 | export const toRequestPolicy = ( 19 | operation: Operation, 20 | requestPolicy: RequestPolicy 21 | ): Operation => { 22 | return makeOperation(operation.kind, operation, { 23 | ...operation.context, 24 | requestPolicy, 25 | }); 26 | }; 27 | -------------------------------------------------------------------------------- /exchanges/graphcache/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | export { Store } from './store/store'; 3 | export { cacheExchange } from './cacheExchange'; 4 | export { offlineExchange } from './offlineExchange'; 5 | -------------------------------------------------------------------------------- /exchanges/graphcache/src/operations/invalidate.ts: -------------------------------------------------------------------------------- 1 | import * as InMemoryData from '../store/data'; 2 | import { keyOfField } from '../store/keys'; 3 | import type { FieldArgs } from '../types'; 4 | 5 | interface PartialFieldInfo { 6 | fieldKey: string; 7 | } 8 | 9 | export const invalidateEntity = ( 10 | entityKey: string, 11 | field?: string, 12 | args?: FieldArgs 13 | ) => { 14 | const fields: PartialFieldInfo[] = field 15 | ? [{ fieldKey: keyOfField(field, args) }] 16 | : InMemoryData.inspectFields(entityKey); 17 | 18 | for (let i = 0, l = fields.length; i < l; i++) { 19 | const { fieldKey } = fields[i]; 20 | if (InMemoryData.readLink(entityKey, fieldKey) !== undefined) { 21 | InMemoryData.writeLink(entityKey, fieldKey, undefined); 22 | } else { 23 | InMemoryData.writeRecord(entityKey, fieldKey, undefined); 24 | } 25 | } 26 | }; 27 | 28 | export const invalidateType = ( 29 | typename: string, 30 | excludedEntities: string[] 31 | ) => { 32 | const types = InMemoryData.getEntitiesForType(typename); 33 | for (const entity of types) { 34 | if (excludedEntities.includes(entity)) continue; 35 | invalidateEntity(entity); 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /exchanges/graphcache/src/store/__snapshots__/store.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`Store with storage > should be able to persist embedded data 1`] = ` 4 | { 5 | "Query%2eappointment({"id":"1"}).__typename": ""Appointment"", 6 | "Query%2eappointment({"id":"1"}).info": ""urql meeting"", 7 | "Query.appointment({"id":"1"})": ":"Query.appointment({\\"id\\":\\"1\\"})"", 8 | } 9 | `; 10 | 11 | exports[`Store with storage > should be able to store and rehydrate data 1`] = ` 12 | { 13 | "Appointment:1.__typename": ""Appointment"", 14 | "Appointment:1.id": ""1"", 15 | "Appointment:1.info": ""urql meeting"", 16 | "Query.appointment({"id":"1"})": ":"Appointment:1"", 17 | } 18 | `; 19 | -------------------------------------------------------------------------------- /exchanges/graphcache/src/store/keys.ts: -------------------------------------------------------------------------------- 1 | import { stringifyVariables } from '@urql/core'; 2 | import type { FieldArgs, FieldInfo, KeyInfo } from '../types'; 3 | 4 | export const keyOfField = (fieldName: string, args?: FieldArgs) => 5 | args ? `${fieldName}(${stringifyVariables(args)})` : fieldName; 6 | 7 | export const joinKeys = (parentKey: string, key: string) => 8 | `${parentKey}.${key}`; 9 | 10 | export const fieldInfoOfKey = (fieldKey: string): FieldInfo => { 11 | const parenIndex = fieldKey.indexOf('('); 12 | if (parenIndex > -1) { 13 | return { 14 | fieldKey, 15 | fieldName: fieldKey.slice(0, parenIndex), 16 | arguments: JSON.parse(fieldKey.slice(parenIndex + 1, -1)), 17 | }; 18 | } else { 19 | return { 20 | fieldKey, 21 | fieldName: fieldKey, 22 | arguments: null, 23 | }; 24 | } 25 | }; 26 | 27 | export const serializeKeys = (entityKey: string, fieldKey: string) => 28 | `${entityKey.replace(/\./g, '%2e')}.${fieldKey}`; 29 | 30 | export const deserializeKeyInfo = (key: string): KeyInfo => { 31 | const dotIndex = key.indexOf('.'); 32 | const entityKey = key.slice(0, dotIndex).replace(/%2e/g, '.'); 33 | const fieldKey = key.slice(dotIndex + 1); 34 | return { entityKey, fieldKey }; 35 | }; 36 | -------------------------------------------------------------------------------- /exchanges/graphcache/src/test-utils/examples-3.test.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@urql/core'; 2 | import { it, afterEach, expect } from 'vitest'; 3 | import { __initAnd_query as query } from '../operations/query'; 4 | import { __initAnd_write as write } from '../operations/write'; 5 | import { Store } from '../store/store'; 6 | 7 | afterEach(() => { 8 | expect(console.warn).not.toHaveBeenCalled(); 9 | }); 10 | 11 | it('allows viewer fields to overwrite the root Query data', () => { 12 | const store = new Store(); 13 | const get = gql` 14 | { 15 | int 16 | } 17 | `; 18 | const set = gql` 19 | mutation { 20 | mutate { 21 | viewer { 22 | int 23 | } 24 | } 25 | } 26 | `; 27 | 28 | write( 29 | store, 30 | { query: get }, 31 | { 32 | __typename: 'Query', 33 | int: 42, 34 | } 35 | ); 36 | 37 | write( 38 | store, 39 | { query: set }, 40 | { 41 | __typename: 'Mutation', 42 | mutate: { 43 | __typename: 'MutateResult', 44 | viewer: { 45 | __typename: 'Query', 46 | int: 43, 47 | }, 48 | }, 49 | } 50 | ); 51 | 52 | const res = query(store, { query: get }); 53 | 54 | expect(res.partial).toBe(false); 55 | expect(res.data).toEqual({ 56 | int: 43, 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /exchanges/graphcache/src/test-utils/utils.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line 2 | export const noop = () => {}; 3 | -------------------------------------------------------------------------------- /exchanges/graphcache/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["src"] 4 | } 5 | -------------------------------------------------------------------------------- /exchanges/graphcache/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vitest/config'; 2 | import baseConfig from '../../vitest.config'; 3 | 4 | export default mergeConfig(baseConfig, {}); 5 | -------------------------------------------------------------------------------- /exchanges/persisted/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urql/exchange-persisted", 3 | "version": "4.3.1", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "exclude": [ 8 | "node_modules", 9 | "cypress", 10 | "**/*.test.*", 11 | "**/*.spec.*", 12 | "**/*.test.*.snap", 13 | "**/*.spec.*.snap" 14 | ] 15 | } -------------------------------------------------------------------------------- /exchanges/persisted/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './persistedExchange'; 2 | -------------------------------------------------------------------------------- /exchanges/persisted/src/test-utils.ts: -------------------------------------------------------------------------------- 1 | import type { GraphQLRequest, OperationContext, Operation } from '@urql/core'; 2 | import { gql, makeOperation } from '@urql/core'; 3 | 4 | const context: OperationContext = { 5 | fetchOptions: { 6 | method: 'POST', 7 | }, 8 | requestPolicy: 'cache-first', 9 | url: 'http://localhost:3000/graphql', 10 | }; 11 | 12 | const queryGql: GraphQLRequest = { 13 | key: 2, 14 | query: gql` 15 | query getUser($name: String) { 16 | user(name: $name) { 17 | id 18 | firstName 19 | lastName 20 | } 21 | } 22 | `, 23 | variables: { 24 | name: 'Clara', 25 | }, 26 | }; 27 | 28 | export const mutationGql: GraphQLRequest = { 29 | key: 2, 30 | query: gql` 31 | mutation AddUser($name: String) { 32 | addUser(name: $name) { 33 | name 34 | } 35 | } 36 | `, 37 | variables: { 38 | name: 'Clara', 39 | }, 40 | }; 41 | 42 | export const queryOperation: Operation = makeOperation( 43 | 'query', 44 | queryGql, 45 | context 46 | ); 47 | 48 | export const mutationOperation: Operation = makeOperation( 49 | 'mutation', 50 | mutationGql, 51 | context 52 | ); 53 | -------------------------------------------------------------------------------- /exchanges/persisted/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["src"] 4 | } 5 | -------------------------------------------------------------------------------- /exchanges/persisted/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vitest/config'; 2 | import baseConfig from '../../vitest.config'; 3 | 4 | export default mergeConfig(baseConfig, {}); 5 | -------------------------------------------------------------------------------- /exchanges/populate/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urql/exchange-populate", 3 | "version": "1.2.1", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "exclude": [ 8 | "node_modules", 9 | "cypress", 10 | "**/*.test.*", 11 | "**/*.spec.*", 12 | "**/*.test.*.snap", 13 | "**/*.spec.*.snap" 14 | ] 15 | } -------------------------------------------------------------------------------- /exchanges/populate/src/helpers/help.ts: -------------------------------------------------------------------------------- 1 | // These are guards that are used throughout the codebase to warn or error on 2 | // unexpected behaviour or conditions. 3 | // Every warning and error comes with a number that uniquely identifies them. 4 | // You can read more about the messages themselves in `docs/graphcache/errors.md` 5 | export type ErrorCode = 6 | | 1 7 | | 2 8 | | 3 9 | | 4 10 | | 5 11 | | 6 12 | | 7 13 | | 8 14 | | 9 15 | | 10 16 | | 11 17 | | 12 18 | | 13 19 | | 15 20 | | 16 21 | | 17 22 | | 18 23 | | 19; 24 | 25 | // URL unfurls to https://formidable.com/open-source/urql/docs/graphcache/errors/ 26 | const helpUrl = '\nhttps://bit.ly/2XbVrpR#'; 27 | const cache = new Set(); 28 | 29 | export function warn(message: string, code: ErrorCode) { 30 | if (!cache.has(message)) { 31 | console.warn(message + helpUrl + code); 32 | cache.add(message); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /exchanges/populate/src/helpers/node.ts: -------------------------------------------------------------------------------- 1 | import type { NameNode, GraphQLOutputType, GraphQLWrappingType } from 'graphql'; 2 | import { isWrappingType, Kind } from 'graphql'; 3 | 4 | export type GraphQLFlatType = Exclude; 5 | 6 | /** Returns the name of a given node */ 7 | export const getName = (node: { name: NameNode }): string => node.name.value; 8 | 9 | export const unwrapType = ( 10 | type: null | undefined | GraphQLOutputType 11 | ): GraphQLFlatType | null => { 12 | if (isWrappingType(type)) { 13 | return unwrapType(type.ofType); 14 | } 15 | 16 | return type || null; 17 | }; 18 | 19 | export function createNameNode(value: string): NameNode { 20 | return { 21 | kind: Kind.NAME, 22 | value, 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /exchanges/populate/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './populateExchange'; 2 | -------------------------------------------------------------------------------- /exchanges/populate/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["src"] 4 | } 5 | -------------------------------------------------------------------------------- /exchanges/populate/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vitest/config'; 2 | import baseConfig from '../../vitest.config'; 3 | 4 | export default mergeConfig(baseConfig, {}); 5 | -------------------------------------------------------------------------------- /exchanges/refocus/README.md: -------------------------------------------------------------------------------- 1 | # @urql/exchange-refocus 2 | 3 | `@urql/exchange-refocus` is an exchange for the [`urql`](../../README.md) GraphQL client that tracks currently active operations and redispatches them when the 4 | window regains focus 5 | 6 | ## Quick Start Guide 7 | 8 | First install `@urql/exchange-refocus` alongside `urql`: 9 | 10 | ```sh 11 | yarn add @urql/exchange-refocus 12 | # or 13 | npm install --save @urql/exchange-refocus 14 | ``` 15 | 16 | Then add it to your `Client`, preferably before the `cacheExchange` and in front of any asynchronous 17 | exchanges, like the `fetchExchange`: 18 | 19 | ```js 20 | import { createClient, cacheExchange, fetchExchange } from 'urql'; 21 | import { refocusExchange } from '@urql/exchange-refocus'; 22 | 23 | const client = createClient({ 24 | url: 'http://localhost:3000/graphql', 25 | exchanges: [refocusExchange(), cacheExchange, fetchExchange], 26 | }); 27 | ``` 28 | -------------------------------------------------------------------------------- /exchanges/refocus/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urql/exchange-refocus", 3 | "version": "1.1.1", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "exclude": [ 8 | "node_modules", 9 | "cypress", 10 | "**/*.test.*", 11 | "**/*.spec.*", 12 | "**/*.test.*.snap", 13 | "**/*.spec.*.snap" 14 | ] 15 | } -------------------------------------------------------------------------------- /exchanges/refocus/src/index.ts: -------------------------------------------------------------------------------- 1 | export { refocusExchange } from './refocusExchange'; 2 | -------------------------------------------------------------------------------- /exchanges/refocus/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["src"] 4 | } 5 | -------------------------------------------------------------------------------- /exchanges/refocus/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vitest/config'; 2 | import baseConfig from '../../vitest.config'; 3 | 4 | export default mergeConfig(baseConfig, {}); 5 | -------------------------------------------------------------------------------- /exchanges/request-policy/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urql/exchange-request-policy", 3 | "version": "1.2.1", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "exclude": [ 8 | "node_modules", 9 | "cypress", 10 | "**/*.test.*", 11 | "**/*.spec.*", 12 | "**/*.test.*.snap", 13 | "**/*.spec.*.snap" 14 | ] 15 | } -------------------------------------------------------------------------------- /exchanges/request-policy/src/index.ts: -------------------------------------------------------------------------------- 1 | export { requestPolicyExchange } from './requestPolicyExchange'; 2 | -------------------------------------------------------------------------------- /exchanges/request-policy/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["src"] 4 | } 5 | -------------------------------------------------------------------------------- /exchanges/request-policy/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vitest/config'; 2 | import baseConfig from '../../vitest.config'; 3 | 4 | export default mergeConfig(baseConfig, {}); 5 | -------------------------------------------------------------------------------- /exchanges/retry/README.md: -------------------------------------------------------------------------------- 1 | # @urql/exchange-retry (Exchange factory) 2 | 3 | `@urql/exchange-retry` is an exchange for the [`urql`](../../README.md) GraphQL client that allows operations (queries, mutations, subscriptions) to be retried based on an `options` parameter. 4 | 5 | ## Quick Start Guide 6 | 7 | First install `@urql/exchange-retry` alongside `urql`: 8 | 9 | ```sh 10 | yarn add @urql/exchange-retry 11 | # or 12 | npm install --save @urql/exchange-retry 13 | ``` 14 | 15 | Read more about the [retry exchange](https://formidable.com/open-source/urql/docs/advanced/retry-operations). 16 | -------------------------------------------------------------------------------- /exchanges/retry/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urql/exchange-retry", 3 | "version": "1.3.1", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "exclude": [ 8 | "node_modules", 9 | "cypress", 10 | "**/*.test.*", 11 | "**/*.spec.*", 12 | "**/*.test.*.snap", 13 | "**/*.spec.*.snap" 14 | ] 15 | } -------------------------------------------------------------------------------- /exchanges/retry/src/index.ts: -------------------------------------------------------------------------------- 1 | export { retryExchange } from './retryExchange'; 2 | export type { RetryExchangeOptions } from './retryExchange'; 3 | -------------------------------------------------------------------------------- /exchanges/retry/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["src"] 4 | } 5 | -------------------------------------------------------------------------------- /exchanges/retry/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vitest/config'; 2 | import baseConfig from '../../vitest.config'; 3 | 4 | export default mergeConfig(baseConfig, {}); 5 | -------------------------------------------------------------------------------- /exchanges/throw-on-error/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @urql/exchange-throw-on-error 2 | 3 | ## 0.1.2 4 | 5 | ### Patch Changes 6 | 7 | - Update `graphql-toe` and add more detail to README 8 | Submitted by [@benjie](https://github.com/benjie) (See [#3765](https://github.com/urql-graphql/urql/pull/3765)) 9 | 10 | ## 0.1.1 11 | 12 | ### Patch Changes 13 | 14 | - Omit minified files and sourcemaps' `sourcesContent` in published packages 15 | Submitted by [@kitten](https://github.com/kitten) (See [#3755](https://github.com/urql-graphql/urql/pull/3755)) 16 | - Updated dependencies (See [#3755](https://github.com/urql-graphql/urql/pull/3755)) 17 | - @urql/core@5.1.1 18 | 19 | ## 0.1.0 20 | 21 | ### Minor Changes 22 | 23 | - Initial release 24 | Submitted by [@XiNiHa](https://github.com/XiNiHa) (See [#3677](https://github.com/urql-graphql/urql/pull/3677)) 25 | -------------------------------------------------------------------------------- /exchanges/throw-on-error/README.md: -------------------------------------------------------------------------------- 1 | # @urql/exchange-throw-on-error (Exchange factory) 2 | 3 | `@urql/exchange-throw-on-error` is an exchange for the [`urql`](https://github.com/urql-graphql/urql) GraphQL client that throws on field access to errored fields. 4 | 5 | It is built on top of the [`graphql-toe`](https://github.com/graphile/graphql-toe) package - please see that package for more information. 6 | 7 | ## Quick Start Guide 8 | 9 | First install `@urql/exchange-throw-on-error` alongside `urql`: 10 | 11 | ```sh 12 | yarn add @urql/exchange-throw-on-error 13 | # or 14 | npm install --save @urql/exchange-throw-on-error 15 | ``` 16 | 17 | Then add the `throwOnErrorExchange`, to your client: 18 | 19 | ```js 20 | import { createClient, cacheExchange, fetchExchange } from 'urql'; 21 | import { throwOnErrorExchange } from '@urql/exchange-throw-on-error'; 22 | 23 | const client = createClient({ 24 | url: '/graphql', 25 | exchanges: [cacheExchange, throwOnErrorExchange(), fetchExchange], 26 | }); 27 | ``` 28 | -------------------------------------------------------------------------------- /exchanges/throw-on-error/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urql/exchange-throw-on-error", 3 | "version": "0.1.2", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "exclude": [ 8 | "node_modules", 9 | "cypress", 10 | "**/*.test.*", 11 | "**/*.spec.*", 12 | "**/*.test.*.snap", 13 | "**/*.spec.*.snap" 14 | ] 15 | } -------------------------------------------------------------------------------- /exchanges/throw-on-error/src/index.ts: -------------------------------------------------------------------------------- 1 | export { throwOnErrorExchange } from './throwOnErrorExchange'; 2 | -------------------------------------------------------------------------------- /exchanges/throw-on-error/src/throwOnErrorExchange.ts: -------------------------------------------------------------------------------- 1 | import type { Exchange } from '@urql/core'; 2 | import { mapExchange } from '@urql/core'; 3 | import { toe } from 'graphql-toe'; 4 | 5 | /** Exchange factory that maps the fields of the data to throw an error on access if the field was errored. 6 | * 7 | * @returns the created throw-on-error {@link Exchange}. 8 | */ 9 | export const throwOnErrorExchange = (): Exchange => { 10 | return mapExchange({ 11 | onResult(result) { 12 | if (result.data) { 13 | const errors = result.error && result.error.graphQLErrors; 14 | result.data = toe({ data: result.data, errors }); 15 | } 16 | return result; 17 | }, 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /exchanges/throw-on-error/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["src"] 4 | } 5 | -------------------------------------------------------------------------------- /exchanges/throw-on-error/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vitest/config'; 2 | import baseConfig from '../../vitest.config'; 3 | 4 | export default mergeConfig(baseConfig, {}); 5 | -------------------------------------------------------------------------------- /packages/core/.gitignore: -------------------------------------------------------------------------------- 1 | /internal 2 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # @urql/core 2 | 3 | > The shared core for the highly customizable and versatile GraphQL client, urql 4 | 5 | More documentation is available at [formidable.com/open-source/urql](https://formidable.com/open-source/urql/). 6 | -------------------------------------------------------------------------------- /packages/core/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urql/core", 3 | "version": "5.1.1", 4 | "exports": { 5 | ".": "./src/index.ts", 6 | "./internal": "./src/internal/index.ts" 7 | }, 8 | "exclude": [ 9 | "node_modules", 10 | "cypress", 11 | "**/*.test.*", 12 | "**/*.spec.*", 13 | "**/*.test.*.snap", 14 | "**/*.spec.*.snap" 15 | ] 16 | } -------------------------------------------------------------------------------- /packages/core/src/__snapshots__/client.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`createClient / Client > passes snapshot 1`] = ` 4 | Client2 { 5 | "createRequestOperation": [Function], 6 | "executeMutation": [Function], 7 | "executeQuery": [Function], 8 | "executeRequestOperation": [Function], 9 | "executeSubscription": [Function], 10 | "mutation": [Function], 11 | "operations$": [Function], 12 | "query": [Function], 13 | "readQuery": [Function], 14 | "reexecuteOperation": [Function], 15 | "subscribeToDebugTarget": [Function], 16 | "subscription": [Function], 17 | "suspense": false, 18 | } 19 | `; 20 | -------------------------------------------------------------------------------- /packages/core/src/exchanges/debug.ts: -------------------------------------------------------------------------------- 1 | import { pipe, tap } from 'wonka'; 2 | import type { Exchange } from '../types'; 3 | 4 | /** Simple log debugger exchange. 5 | * 6 | * @remarks 7 | * An exchange that logs incoming {@link Operation | Operations} and 8 | * {@link OperationResult | OperationResults} in development. 9 | * 10 | * This exchange is a no-op in production and often used in issue reporting 11 | * to understand certain usage patterns of `urql` without having access to 12 | * the original source code. 13 | * 14 | * Hint: When you report an issue you’re having with `urql`, adding 15 | * this as your first exchange and posting its output can speed up 16 | * issue triaging a lot! 17 | */ 18 | export const debugExchange: Exchange = ({ forward }) => { 19 | if (process.env.NODE_ENV === 'production') { 20 | return ops$ => forward(ops$); 21 | } else { 22 | return ops$ => 23 | pipe( 24 | ops$, 25 | // eslint-disable-next-line no-console 26 | tap(op => console.debug('[Exchange debug]: Incoming operation: ', op)), 27 | forward, 28 | tap(result => 29 | // eslint-disable-next-line no-console 30 | console.debug('[Exchange debug]: Completed operation: ', result) 31 | ) 32 | ); 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /packages/core/src/exchanges/fallback.test.ts: -------------------------------------------------------------------------------- 1 | import { forEach, fromValue, pipe } from 'wonka'; 2 | import { vi, expect, it, beforeEach, afterAll } from 'vitest'; 3 | 4 | import { queryOperation, teardownOperation } from '../test-utils'; 5 | import { fallbackExchange } from './fallback'; 6 | 7 | const consoleWarn = console.warn; 8 | 9 | const dispatchDebug = vi.fn(); 10 | 11 | beforeEach(() => { 12 | console.warn = vi.fn(); 13 | }); 14 | 15 | afterAll(() => { 16 | console.warn = consoleWarn; 17 | }); 18 | 19 | it('filters all results and warns about input', () => { 20 | const res: any[] = []; 21 | 22 | pipe( 23 | fallbackExchange({ dispatchDebug })(fromValue(queryOperation)), 24 | forEach(x => res.push(x)) 25 | ); 26 | 27 | expect(res.length).toBe(0); 28 | expect(console.warn).toHaveBeenCalled(); 29 | }); 30 | 31 | it('filters all results and does not warn about teardown operations', () => { 32 | const res: any[] = []; 33 | 34 | pipe( 35 | fallbackExchange({ dispatchDebug })(fromValue(teardownOperation)), 36 | forEach(x => res.push(x)) 37 | ); 38 | 39 | expect(res.length).toBe(0); 40 | expect(console.warn).not.toHaveBeenCalled(); 41 | }); 42 | -------------------------------------------------------------------------------- /packages/core/src/exchanges/index.ts: -------------------------------------------------------------------------------- 1 | export { ssrExchange } from './ssr'; 2 | export { cacheExchange } from './cache'; 3 | export { subscriptionExchange } from './subscription'; 4 | export { debugExchange } from './debug'; 5 | export { fetchExchange } from './fetch'; 6 | export { composeExchanges } from './compose'; 7 | 8 | export type { 9 | SerializedResult, 10 | SSRExchangeParams, 11 | SSRExchange, 12 | SSRData, 13 | } from './ssr'; 14 | 15 | export type { 16 | SubscriptionOperation, 17 | SubscriptionForwarder, 18 | SubscriptionExchangeOpts, 19 | } from './subscription'; 20 | 21 | export { mapExchange, mapExchange as errorExchange } from './map'; 22 | export type { MapExchangeOpts } from './map'; 23 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export { gql } from './gql'; 2 | 3 | export * from './client'; 4 | export * from './exchanges'; 5 | export * from './types'; 6 | 7 | export { 8 | CombinedError, 9 | stringifyVariables, 10 | stringifyDocument, 11 | createRequest, 12 | makeResult, 13 | makeErrorResult, 14 | mergeResultPatch, 15 | formatDocument, 16 | makeOperation, 17 | } from './utils'; 18 | -------------------------------------------------------------------------------- /packages/core/src/internal/index.ts: -------------------------------------------------------------------------------- 1 | export * from './fetchOptions'; 2 | export * from './fetchSource'; 3 | -------------------------------------------------------------------------------- /packages/core/src/test-utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './samples'; 2 | -------------------------------------------------------------------------------- /packages/core/src/utils/__snapshots__/error.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`CombinedError > behaves like a normal Error 1`] = `"[Network] test"`; 4 | -------------------------------------------------------------------------------- /packages/core/src/utils/collectTypenames.ts: -------------------------------------------------------------------------------- 1 | interface EntityLike { 2 | [key: string]: EntityLike | EntityLike[] | any; 3 | __typename: string | null | void; 4 | } 5 | 6 | const collectTypes = (obj: EntityLike | EntityLike[], types: Set) => { 7 | if (Array.isArray(obj)) { 8 | for (let i = 0, l = obj.length; i < l; i++) { 9 | collectTypes(obj[i], types); 10 | } 11 | } else if (typeof obj === 'object' && obj !== null) { 12 | for (const key in obj) { 13 | if (key === '__typename' && typeof obj[key] === 'string') { 14 | types.add(obj[key] as string); 15 | } else { 16 | collectTypes(obj[key], types); 17 | } 18 | } 19 | } 20 | 21 | return types; 22 | }; 23 | 24 | /** Finds and returns a list of `__typename` fields found in response data. 25 | * 26 | * @privateRemarks 27 | * This is used by `@urql/core`’s document `cacheExchange` to find typenames 28 | * in a given GraphQL response’s data. 29 | */ 30 | export const collectTypenames = (response: object): string[] => [ 31 | ...collectTypes(response as EntityLike, new Set()), 32 | ]; 33 | -------------------------------------------------------------------------------- /packages/core/src/utils/graphql.ts: -------------------------------------------------------------------------------- 1 | import type * as GraphQLWeb from '@0no-co/graphql.web'; 2 | import type * as GraphQL from 'graphql'; 3 | 4 | type OrNever = void extends T ? never : T; 5 | 6 | export type GraphQLError = 7 | | GraphQLWeb.GraphQLError 8 | | OrNever; 9 | 10 | export type DocumentNode = 11 | | GraphQLWeb.DocumentNode 12 | | OrNever; 13 | 14 | export type DefinitionNode = 15 | | GraphQLWeb.DefinitionNode 16 | | OrNever; 17 | -------------------------------------------------------------------------------- /packages/core/src/utils/hash.test.ts: -------------------------------------------------------------------------------- 1 | import { HashValue, phash } from './hash'; 2 | import { expect, it } from 'vitest'; 3 | 4 | it('hashes given strings', () => { 5 | expect(phash('hello')).toMatchInlineSnapshot('261238937'); 6 | }); 7 | 8 | it('hashes given strings and seeds', () => { 9 | let hash: HashValue; 10 | expect((hash = phash('hello'))).toMatchInlineSnapshot('261238937'); 11 | expect((hash = phash('world', hash))).toMatchInlineSnapshot('-152191'); 12 | expect((hash = phash('!', hash))).toMatchInlineSnapshot('-5022270'); 13 | expect(typeof hash).toBe('number'); 14 | }); 15 | -------------------------------------------------------------------------------- /packages/core/src/utils/hash.ts: -------------------------------------------------------------------------------- 1 | /** A hash value as computed by {@link phash}. 2 | * 3 | * @remarks 4 | * Typically `HashValue`s are used as hashes and keys of GraphQL documents, 5 | * variables, and combined, for GraphQL requests. 6 | */ 7 | export type HashValue = number & { 8 | /** Marker to indicate that a `HashValue` may not be created by a user. 9 | * 10 | * @remarks 11 | * `HashValue`s are created by {@link phash} and are marked as such to not mix them 12 | * up with other numbers and prevent them from being created or used outside of this 13 | * hashing function. 14 | * 15 | * @internal 16 | */ 17 | readonly _opaque: unique symbol; 18 | }; 19 | 20 | /** Computes a djb2 hash of the given string. 21 | * 22 | * @param x - the string to be hashed 23 | * @param seed - optionally a prior hash for progressive hashing 24 | * @returns a hash value, i.e. a number 25 | * 26 | * @remark 27 | * This is the hashing function used throughout `urql`, primarily to compute 28 | * {@link Operation.key}. 29 | * 30 | * @see {@link http://www.cse.yorku.ca/~oz/hash.html#djb2} for a further description of djb2. 31 | */ 32 | export const phash = (x: string, seed?: HashValue): HashValue => { 33 | let h = (seed || 5381) | 0; 34 | for (let i = 0, l = x.length | 0; i < l; i++) 35 | h = (h << 5) + h + x.charCodeAt(i); 36 | return h as HashValue; 37 | }; 38 | -------------------------------------------------------------------------------- /packages/core/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './error'; 2 | export * from './request'; 3 | export * from './result'; 4 | export * from './variables'; 5 | export * from './collectTypenames'; 6 | export * from './formatDocument'; 7 | export * from './streamUtils'; 8 | export * from './operation'; 9 | 10 | export const noop = () => { 11 | /* noop */ 12 | }; 13 | -------------------------------------------------------------------------------- /packages/core/src/utils/streamUtils.ts: -------------------------------------------------------------------------------- 1 | import type { Sink, Source } from 'wonka'; 2 | import { subscribe, take, filter, toPromise, pipe } from 'wonka'; 3 | import type { OperationResult, OperationResultSource } from '../types'; 4 | 5 | /** Patches a `toPromise` method onto the `Source` passed to it. 6 | * @param source$ - the Wonka {@link Source} to patch. 7 | * @returns The passed `source$` with a patched `toPromise` method as a {@link PromisifiedSource}. 8 | * @internal 9 | */ 10 | export function withPromise( 11 | _source$: Source 12 | ): OperationResultSource { 13 | const source$ = ((sink: Sink) => 14 | _source$(sink)) as OperationResultSource; 15 | source$.toPromise = () => 16 | pipe( 17 | source$, 18 | filter(result => !result.stale && !result.hasNext), 19 | take(1), 20 | toPromise 21 | ); 22 | source$.then = (onResolve, onReject) => 23 | source$.toPromise().then(onResolve, onReject); 24 | source$.subscribe = onResult => subscribe(onResult)(source$); 25 | return source$; 26 | } 27 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["src"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/core/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vitest/config'; 2 | import baseConfig from '../../vitest.config'; 3 | 4 | export default mergeConfig(baseConfig, {}); 5 | -------------------------------------------------------------------------------- /packages/introspection/README.md: -------------------------------------------------------------------------------- 1 |

@urql/introspection

2 | 3 |

Utilities for dealing with Introspection Queries and Client Schemas

4 | -------------------------------------------------------------------------------- /packages/introspection/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urql/introspection", 3 | "version": "1.2.1", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "exclude": [ 8 | "node_modules", 9 | "cypress", 10 | "**/*.test.*", 11 | "**/*.spec.*", 12 | "**/*.test.*.snap", 13 | "**/*.spec.*.snap" 14 | ] 15 | } -------------------------------------------------------------------------------- /packages/introspection/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './getIntrospectedSchema'; 2 | export * from './minifyIntrospectionQuery'; 3 | -------------------------------------------------------------------------------- /packages/introspection/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["src"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/next-urql/.gitignore: -------------------------------------------------------------------------------- 1 | /rsc 2 | -------------------------------------------------------------------------------- /packages/next-urql/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018–2020 Formidable, 4 | Copyright (c) urql GraphQL Team and other contributors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /packages/next-urql/README.md: -------------------------------------------------------------------------------- 1 | ## `next-urql` 2 | 3 | A set of convenience utilities for using `urql` with Next.js. 4 | 5 | More documentation is available at https://urql.dev/goto/docs/advanced/server-side-rendering/#nextjs 6 | Examples can be found at https://github.com/urql-graphql/urql/tree/main/examples/with-next 7 | -------------------------------------------------------------------------------- /packages/next-urql/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urql/next", 3 | "version": "1.1.5", 4 | "exports": { 5 | ".": "./src/index.ts", 6 | "./rsc": "./src/rsc.ts" 7 | }, 8 | "exclude": [ 9 | "node_modules", 10 | "cypress", 11 | "**/*.test.*", 12 | "**/*.spec.*", 13 | "**/*.test.*.snap", 14 | "**/*.spec.*.snap" 15 | ] 16 | } -------------------------------------------------------------------------------- /packages/next-urql/src/htmlescape.ts: -------------------------------------------------------------------------------- 1 | // See: https://github.com/vercel/next.js/blob/6bc07792a4462a4bf921a72ab30dc4ab2c4e1bda/packages/next/src/server/htmlescape.ts 2 | // License: https://github.com/vercel/next.js/blob/6bc07792a4462a4bf921a72ab30dc4ab2c4e1bda/packages/next/license.md 3 | 4 | // This utility is based on https://github.com/zertosh/htmlescape 5 | // License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE 6 | 7 | const ESCAPE_LOOKUP: { [match: string]: string } = { 8 | '&': '\\u0026', 9 | '>': '\\u003e', 10 | '<': '\\u003c', 11 | '\u2028': '\\u2028', 12 | '\u2029': '\\u2029', 13 | }; 14 | 15 | export const ESCAPE_REGEX = /[&><\u2028\u2029]/g; 16 | 17 | export function htmlEscapeJsonString(str: string): string { 18 | return str.replace(ESCAPE_REGEX, match => ESCAPE_LOOKUP[match]); 19 | } 20 | -------------------------------------------------------------------------------- /packages/next-urql/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from 'urql'; 2 | export { useQuery } from './useQuery'; 3 | export { UrqlProvider, SSRContext } from './Provider'; 4 | -------------------------------------------------------------------------------- /packages/next-urql/src/rsc.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import type { Client } from '@urql/core'; 3 | 4 | /** Function to cache an urql-client across React Server Components. 5 | * 6 | * @param makeClient - A function that creates an urql-client. 7 | * @returns an object containing a getClient method. 8 | * 9 | * @example 10 | * ```ts 11 | * import { cacheExchange, createClient, fetchExchange, gql } from '@urql/core'; 12 | * import { registerUrql } from '@urql/next/rsc'; 13 | * const makeClient = () => { 14 | * return createClient({ 15 | * url: 'https://trygql.formidable.dev/graphql/basic-pokedex', 16 | * exchanges: [cacheExchange, fetchExchange], 17 | * }); 18 | * }; 19 | * 20 | * const { getClient } = registerUrql(makeClient); 21 | * ``` 22 | */ 23 | export function registerUrql(makeClient: () => Client): { 24 | getClient: () => Client; 25 | } { 26 | // @ts-ignore you exist don't worry 27 | const getClient = React.cache(makeClient); 28 | return { 29 | getClient, 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /packages/next-urql/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["src"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/next-urql/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vitest/config'; 2 | import baseConfig from '../../vitest.config'; 3 | 4 | export default mergeConfig(baseConfig, {}); 5 | -------------------------------------------------------------------------------- /packages/preact-urql/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@urql/preact", 3 | "version": "4.1.2", 4 | "exports": { 5 | ".": "./src/index.ts" 6 | }, 7 | "exclude": [ 8 | "node_modules", 9 | "cypress", 10 | "**/*.test.*", 11 | "**/*.spec.*", 12 | "**/*.test.*.snap", 13 | "**/*.spec.*.snap" 14 | ] 15 | } -------------------------------------------------------------------------------- /packages/preact-urql/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Mutation'; 2 | export * from './Query'; 3 | export * from './Subscription'; 4 | -------------------------------------------------------------------------------- /packages/preact-urql/src/hooks/constants.ts: -------------------------------------------------------------------------------- 1 | export const initialState = { 2 | fetching: false, 3 | stale: false, 4 | hasNext: false, 5 | error: undefined, 6 | data: undefined, 7 | extensions: undefined, 8 | operation: undefined, 9 | }; 10 | -------------------------------------------------------------------------------- /packages/preact-urql/src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useQuery'; 2 | export * from './useMutation'; 3 | export * from './useSubscription'; 4 | -------------------------------------------------------------------------------- /packages/preact-urql/src/hooks/useRequest.ts: -------------------------------------------------------------------------------- 1 | import type { DocumentNode } from 'graphql'; 2 | import { useRef, useMemo } from 'preact/hooks'; 3 | import type { 4 | AnyVariables, 5 | TypedDocumentNode, 6 | GraphQLRequest, 7 | } from '@urql/core'; 8 | import { createRequest } from '@urql/core'; 9 | 10 | /** Creates a request from a query and variables but preserves reference equality if the key isn't changing 11 | * @internal 12 | */ 13 | export function useRequest< 14 | Data = any, 15 | Variables extends AnyVariables = AnyVariables, 16 | >( 17 | query: string | DocumentNode | TypedDocumentNode, 18 | variables: Variables 19 | ): GraphQLRequest { 20 | const prev = useRef>(undefined); 21 | return useMemo(() => { 22 | const request = createRequest(query, variables); 23 | // We manually ensure reference equality if the key hasn't changed 24 | if (prev.current !== undefined && prev.current.key === request.key) { 25 | return prev.current; 26 | } else { 27 | prev.current = request; 28 | return request; 29 | } 30 | }, [query, variables]); 31 | } 32 | -------------------------------------------------------------------------------- /packages/preact-urql/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from '@urql/core'; 2 | export * from './hooks'; 3 | export * from './components'; 4 | export * from './context'; 5 | -------------------------------------------------------------------------------- /packages/preact-urql/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["src"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/preact-urql/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vitest/config'; 2 | import baseConfig from '../../vitest.config'; 3 | 4 | export default mergeConfig(baseConfig, {}); 5 | -------------------------------------------------------------------------------- /packages/react-urql/README.md: -------------------------------------------------------------------------------- 1 | # urql 2 | 3 | > A highly customizable and versatile GraphQL client **for React** 4 | 5 | More documentation is available at [formidable.com/open-source/urql](https://formidable.com/open-source/urql/). 6 | -------------------------------------------------------------------------------- /packages/react-urql/core/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from '@urql/core'; 2 | -------------------------------------------------------------------------------- /packages/react-urql/core/index.esm.js: -------------------------------------------------------------------------------- 1 | export * from '@urql/core'; 2 | -------------------------------------------------------------------------------- /packages/react-urql/core/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('@urql/core'); 2 | -------------------------------------------------------------------------------- /packages/react-urql/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "urql-core", 3 | "private": true, 4 | "main": "index.js", 5 | "module": "index.esm.js", 6 | "types": "index.d.ts", 7 | "dependencies": { 8 | "@urql/core": "^1.7.0" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/react-urql/core/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@urql/core@^1.7.0": 6 | version "1.9.2" 7 | resolved "https://registry.yarnpkg.com/@urql/core/-/core-1.9.2.tgz#bc2880a279dd5ada26527063c7a173fda26abb58" 8 | integrity sha512-0eitjW/HlUAkMTwiWFQyQkcmwAlnWlscH3/AKU1Y5MJUzzehAkOffHFQ9eD5st/0TlKSvehbz/eUAHDq/CnX8w== 9 | dependencies: 10 | wonka "^4.0.7" 11 | 12 | wonka@^4.0.7: 13 | version "4.0.7" 14 | resolved "https://registry.yarnpkg.com/wonka/-/wonka-4.0.7.tgz#b4934685bd2449367bd72ce7770bfe3e6cc8a68b" 15 | integrity sha512-Uhyl2cgWCUksYtU0Jt8MSzKUqK4BVUrewWxnn1YlKL3Zco4sDcCUDkbgH0i762HJs1rtsq03cfzsCWxJKaDgVg== 16 | -------------------------------------------------------------------------------- /packages/react-urql/cypress.config.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line 2 | const { defineConfig } = require('cypress'); 3 | // eslint-disable-next-line 4 | const tsconfigPaths = require('vite-tsconfig-paths').default; 5 | 6 | module.exports = defineConfig({ 7 | video: false, 8 | 9 | e2e: { 10 | setupNodeEvents(_on, _config) { 11 | /*noop*/ 12 | }, 13 | supportFile: false, 14 | }, 15 | component: { 16 | specPattern: './**/e2e-tests/*spec.tsx', 17 | devServer: { 18 | framework: 'react', 19 | bundler: 'vite', 20 | viteConfig: { 21 | plugins: [tsconfigPaths()], 22 | server: { 23 | fs: { 24 | allow: ['..'], 25 | }, 26 | }, 27 | }, 28 | }, 29 | }, 30 | }); 31 | -------------------------------------------------------------------------------- /packages/react-urql/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /packages/react-urql/cypress/support/component-index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Components App 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/react-urql/cypress/support/component.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/component.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | import { mount } from 'cypress/react'; 17 | 18 | Cypress.Commands.add('mount', mount); 19 | -------------------------------------------------------------------------------- /packages/react-urql/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "urql", 3 | "version": "4.2.2", 4 | "exports": "src/index.ts", 5 | "exclude": [ 6 | "node_modules", 7 | "cypress", 8 | "**/*.test.*", 9 | "**/*.spec.*", 10 | "**/*.test.*.snap", 11 | "**/*.spec.*.snap" 12 | ] 13 | } -------------------------------------------------------------------------------- /packages/react-urql/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Mutation'; 2 | export * from './Query'; 3 | export * from './Subscription'; 4 | -------------------------------------------------------------------------------- /packages/react-urql/src/hooks/__snapshots__/useMutation.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`on initial useEffect > initialises default state 1`] = ` 4 | { 5 | "data": undefined, 6 | "error": undefined, 7 | "extensions": undefined, 8 | "fetching": false, 9 | "hasNext": false, 10 | "operation": undefined, 11 | "stale": false, 12 | } 13 | `; 14 | -------------------------------------------------------------------------------- /packages/react-urql/src/hooks/__snapshots__/useQuery.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`on initial useEffect > initialises default state 1`] = ` 4 | { 5 | "data": undefined, 6 | "error": undefined, 7 | "extensions": undefined, 8 | "fetching": true, 9 | "hasNext": false, 10 | "operation": undefined, 11 | "stale": false, 12 | } 13 | `; 14 | -------------------------------------------------------------------------------- /packages/react-urql/src/hooks/__snapshots__/useSubscription.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`on initial useEffect > initialises default state 1`] = ` 4 | { 5 | "data": undefined, 6 | "error": undefined, 7 | "extensions": undefined, 8 | "fetching": true, 9 | "hasNext": false, 10 | "operation": undefined, 11 | "stale": false, 12 | } 13 | `; 14 | -------------------------------------------------------------------------------- /packages/react-urql/src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useMutation'; 2 | export * from './useQuery'; 3 | export * from './useSubscription'; 4 | -------------------------------------------------------------------------------- /packages/react-urql/src/hooks/useRequest.test.ts: -------------------------------------------------------------------------------- 1 | // @vitest-environment jsdom 2 | import { gql } from '@urql/core'; 3 | import { renderHook } from '@testing-library/react'; 4 | import { it, expect } from 'vitest'; 5 | import { useRequest } from './useRequest'; 6 | 7 | it('preserves instance of request when key has not changed', () => { 8 | const query = gql` 9 | query getUser($name: String) { 10 | user(name: $name) { 11 | id 12 | firstName 13 | lastName 14 | } 15 | } 16 | `; 17 | 18 | let variables = { 19 | name: 'Clara', 20 | }; 21 | 22 | const { result, rerender } = renderHook( 23 | ({ query, variables }) => useRequest(query, variables), 24 | { initialProps: { query, variables } } 25 | ); 26 | 27 | const resultA = result.current; 28 | expect(resultA).toEqual({ 29 | key: expect.any(Number), 30 | query: expect.anything(), 31 | variables: variables, 32 | }); 33 | 34 | variables = { ...variables }; // Change reference 35 | rerender({ query, variables }); 36 | 37 | const resultB = result.current; 38 | expect(resultA).toBe(resultB); 39 | 40 | variables = { ...variables, test: true } as any; // Change values 41 | rerender({ query, variables }); 42 | 43 | const resultC = result.current; 44 | expect(resultA).not.toBe(resultC); 45 | }); 46 | -------------------------------------------------------------------------------- /packages/react-urql/src/hooks/useRequest.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import type { AnyVariables, DocumentInput, GraphQLRequest } from '@urql/core'; 3 | import { createRequest } from '@urql/core'; 4 | 5 | /** Creates a request from a query and variables but preserves reference equality if the key isn't changing 6 | * @internal 7 | */ 8 | export function useRequest< 9 | Data = any, 10 | Variables extends AnyVariables = AnyVariables, 11 | >( 12 | query: DocumentInput, 13 | variables: Variables 14 | ): GraphQLRequest { 15 | const prev = React.useRef>( 16 | undefined 17 | ); 18 | 19 | return React.useMemo(() => { 20 | const request = createRequest(query, variables); 21 | // We manually ensure reference equality if the key hasn't changed 22 | if (prev.current !== undefined && prev.current.key === request.key) { 23 | return prev.current; 24 | } else { 25 | prev.current = request; 26 | return request; 27 | } 28 | }, [query, variables]); 29 | } 30 | -------------------------------------------------------------------------------- /packages/react-urql/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from '@urql/core'; 2 | export * from './context'; 3 | export * from './components'; 4 | export * from './hooks'; 5 | -------------------------------------------------------------------------------- /packages/react-urql/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["src"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/react-urql/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vitest/config'; 2 | import baseConfig from '../../vitest.config'; 3 | 4 | export default mergeConfig(baseConfig, { 5 | test: { 6 | environment: 'jsdom', 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /packages/site/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # urql-docs 2 | 3 | ## 1.0.0 4 | 5 | ### Major Changes 6 | 7 | - **Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore, by [@kitten](https://github.com/kitten) (See [#2504](https://github.com/urql-graphql/urql/pull/2504)) 8 | -------------------------------------------------------------------------------- /packages/site/dist-prod/open-source/urql: -------------------------------------------------------------------------------- 1 | ../../dist -------------------------------------------------------------------------------- /packages/site/plugins/assets-fix/node.api.js: -------------------------------------------------------------------------------- 1 | export default () => ({ 2 | webpack(config) { 3 | const rules = config.module.rules[0].oneOf; 4 | for (let i = 0; i < rules.length; i++) { 5 | const rule = rules[i]; 6 | if (rule.loader === 'url-loader') { 7 | delete rule.options; 8 | rule.query = { 9 | limit: 10000, 10 | name: 'static/[name].[hash:8].[ext]', 11 | }; 12 | } 13 | } 14 | 15 | return config; 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /packages/site/plugins/monorepo-fix/node.api.js: -------------------------------------------------------------------------------- 1 | import { silent as resolveFrom } from 'resolve-from'; 2 | 3 | const NODE_MODULES_JS_RE = /node_modules[/\\].*\.js$/; 4 | const REACT_STATIC_RE = /node_modules[/\\]react-static/; 5 | 6 | export default () => ({ 7 | webpack: (config, { stage }) => { 8 | if (stage === 'node') { 9 | config.externals = [ 10 | ...config.externals, 11 | (context, request, callback) => { 12 | if (/^[./]/.test(request)) { 13 | return callback(); 14 | } 15 | 16 | const res = resolveFrom(`${context}/`, request); 17 | if ( 18 | res && 19 | NODE_MODULES_JS_RE.test(res) && 20 | !REACT_STATIC_RE.test(res) 21 | ) { 22 | return callback(null, `commonjs ${request}`); 23 | } else { 24 | return callback(); 25 | } 26 | }, 27 | ]; 28 | } 29 | 30 | return config; 31 | }, 32 | }); 33 | -------------------------------------------------------------------------------- /packages/site/plugins/preact/node.api.js: -------------------------------------------------------------------------------- 1 | export default () => ({ 2 | webpack: config => { 3 | config.resolve.alias = { 4 | ...(config.resolve.alias || {}), 5 | react: 'preact/compat', 6 | 'react-dom': 'preact/compat', 7 | }; 8 | 9 | return config; 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /packages/site/public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #fff 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/site/public/favicon/favicon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/packages/site/public/favicon/favicon-16.png -------------------------------------------------------------------------------- /packages/site/public/favicon/favicon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/packages/site/public/favicon/favicon-192.png -------------------------------------------------------------------------------- /packages/site/public/favicon/favicon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/packages/site/public/favicon/favicon-32.png -------------------------------------------------------------------------------- /packages/site/public/favicon/favicon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urql-graphql/urql/92a101a5497040641306a783b56d5fc3ee0917b1/packages/site/public/favicon/favicon-512.png -------------------------------------------------------------------------------- /packages/site/public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "urql Documentation", 3 | "short_name": "urql", 4 | "icons": [ 5 | { 6 | "src": "./favicon/favicon-32.png", 7 | "sizes": "16x16", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "./favicon/favicon-32.png", 12 | "sizes": "32x32", 13 | "type": "image/png" 14 | }, 15 | { 16 | "src": "./favicon/favicon-192.png", 17 | "sizes": "192x192", 18 | "type": "image/png" 19 | }, 20 | { 21 | "src": "./favicon/favicon-32.png", 22 | "sizes": "512x512", 23 | "type": "image/png" 24 | } 25 | ], 26 | "theme_color": "#ffffff", 27 | "background_color": "#ffffff", 28 | "display": "standalone" 29 | } 30 | -------------------------------------------------------------------------------- /packages/site/src/analytics.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | let GoogleAnalytics = null; 5 | if (typeof window !== 'undefined') { 6 | GoogleAnalytics = require('react-router-ga'); 7 | if (GoogleAnalytics.default) GoogleAnalytics = GoogleAnalytics.default; 8 | } 9 | 10 | export const Analytics = props => 11 | !GoogleAnalytics ? ( 12 | 13 | ) : ( 14 | {props.children} 15 | ); 16 | 17 | Analytics.propTypes = { 18 | children: PropTypes.element, 19 | }; 20 | -------------------------------------------------------------------------------- /packages/site/src/app.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line react/no-multi-comp 2 | 3 | import React, { useEffect } from 'react'; 4 | import { Root, Routes } from 'react-static'; 5 | import { ThemeProvider } from 'styled-components'; 6 | 7 | import constants from './constants'; 8 | import { GlobalStyle } from './styles/global'; 9 | import * as theme from './styles/theme'; 10 | import Analytics from './google-analytics'; 11 | import { initGoogleTagManager } from './google-tag-manager'; 12 | import { Loading } from './components/loading'; 13 | 14 | const App = () => { 15 | useEffect(() => { 16 | initGoogleTagManager(); 17 | }, []); 18 | 19 | return ( 20 | 21 | 22 | 23 | }> 24 | 25 | 26 | 27 | 28 | 29 | 30 | ); 31 | }; 32 | 33 | export default App; 34 | -------------------------------------------------------------------------------- /packages/site/src/assets/anchor.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const SvgAnchor = props => ( 4 | 5 | 10 | 11 | ); 12 | 13 | export default SvgAnchor; 14 | -------------------------------------------------------------------------------- /packages/site/src/assets/anchor.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/site/src/assets/burger.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/site/src/assets/chevron.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const SvgChevron = props => ( 4 | 5 | 10 | 11 | ); 12 | 13 | export default SvgChevron; 14 | -------------------------------------------------------------------------------- /packages/site/src/assets/chevron.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/site/src/assets/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/site/src/assets/right-triangles.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/site/src/components/body-copy.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const BodyCopy = styled.p` 4 | font-size: 1.4rem; 5 | line-height: 2.2rem; 6 | width: 100%; 7 | text-align: center; 8 | ${p => p.noMargin && 'margin: 0'}; 9 | @media (min-width: 768px) { 10 | font-size: 1.5rem; 11 | line-height: 2.4rem; 12 | text-align: left; 13 | } 14 | `; 15 | -------------------------------------------------------------------------------- /packages/site/src/components/button.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled, { css } from 'styled-components'; 3 | 4 | export const buttonLinkStyling = css` 5 | background: white; 6 | color: #383838; 7 | font-weight: normal; 8 | font-size: 1.4rem; 9 | font-style: normal; 10 | font-stretch: normal; 11 | height: 4rem; 12 | line-height: 4rem; 13 | padding: 0 2rem; 14 | letter-spacing: 0.01rem; 15 | text-align: center; 16 | text-transform: uppercase; 17 | transition: opacity 0.4s ease-out; 18 | 19 | &:hover { 20 | opacity: 0.8; 21 | } 22 | &:active { 23 | opacity: 0.6; 24 | } 25 | `; 26 | 27 | const ButtonNoBorder = styled.button` 28 | border: none; 29 | `; 30 | 31 | export const Button = styled(props => ( 32 | {props.children} 33 | ))` 34 | ${buttonLinkStyling} 35 | `; 36 | -------------------------------------------------------------------------------- /packages/site/src/components/link.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | import { Link as ReactRouterLink } from 'react-router-dom'; 4 | 5 | import { buttonLinkStyling } from './button'; 6 | 7 | export const Link = styled(({ isExternal, ...rest }) => 8 | isExternal ? ( 9 | 10 | {rest.children} 11 | 12 | ) : ( 13 | 14 | ) 15 | )` 16 | ${buttonLinkStyling} 17 | `; 18 | -------------------------------------------------------------------------------- /packages/site/src/components/panel.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled, { css } from 'styled-components'; 3 | import constants from '../constants'; 4 | 5 | const dark = css` 6 | background-color: #0d1129; 7 | `; 8 | 9 | const light = css` 10 | background: ${constants.color}; 11 | border-bottom: 1rem solid rgba(0, 0, 0, 0.4); 12 | box-shadow: inset 0 -1rem 0 rgba(0, 0, 0, 0.2); 13 | `; 14 | export const FullWidthContainer = styled.div` 15 | color: #e3eef8; 16 | display: flex; 17 | justify-content: center; 18 | ${p => (p.isLight ? light : dark)}; 19 | ${p => p.background && `background: ${p.background}`} 20 | `; 21 | 22 | export const SectionWrapper = styled.div` 23 | flex-direction: column; 24 | align-items: center; 25 | display: flex; 26 | padding: 8rem 4rem; 27 | width: 100%; 28 | @media (min-width: 768px) { 29 | flex-direction: column; 30 | margin: 0 8rem; 31 | padding: 8rem 8rem; 32 | } 33 | `; 34 | 35 | export const PanelSectionWrapper = ({ 36 | children, 37 | isLight, 38 | background, 39 | ...rest 40 | }) => ( 41 | 42 | {children} 43 | 44 | ); 45 | -------------------------------------------------------------------------------- /packages/site/src/components/scroll-to-top.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef } from 'react'; 2 | import { useLocation } from 'react-router-dom'; 3 | import { useMarkdownPage } from 'react-static-plugin-md-pages'; 4 | 5 | const parsePathname = pathname => { 6 | const match = pathname && pathname.match(/#[a-z|-]+/); 7 | return match && match[0]; 8 | }; 9 | 10 | export const ScrollToTop = () => { 11 | const inputRef = useRef(null); 12 | const location = useLocation(); 13 | const md = useMarkdownPage(); 14 | 15 | const hash = location.hash || parsePathname(location.pathname); 16 | 17 | useEffect(() => { 18 | if (hash && md) { 19 | inputRef.current.click(); 20 | } else { 21 | window.scrollTo(0, 0); 22 | } 23 | }, [hash, md]); 24 | 25 | return ; 26 | }; 27 | -------------------------------------------------------------------------------- /packages/site/src/components/secondary-title.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const SecondaryTitle = styled.h3` 4 | color: white; 5 | font-size: 2rem; 6 | line-height: 2.4rem; 7 | margin: 2rem auto 1rem; 8 | text-align: center; 9 | @media (min-width: 768px) { 10 | font-size: 2.2rem; 11 | line-height: 2.6rem; 12 | } 13 | `; 14 | -------------------------------------------------------------------------------- /packages/site/src/components/section-title.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const SectionTitle = styled.h2` 4 | color: #fff; 5 | font-size: 3.5rem; 6 | flex: auto; 7 | line-height: 1.3; 8 | margin: 0 0 3rem; 9 | width: 100%; 10 | text-align: center; 11 | @media (min-width: 768px) { 12 | font-size: 4.5rem; 13 | margin: 0 0 6rem; 14 | } 15 | `; 16 | -------------------------------------------------------------------------------- /packages/site/src/components/sidebar-search-input.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | 5 | const StyledInput = styled.input` 6 | background-color: rgba(255, 255, 255, 0.8); 7 | border: none; 8 | border-radius: 0.5rem; 9 | color: ${p => p.theme.colors.text}; 10 | font-family: ${p => p.theme.fonts.body}; 11 | font-size: 1.6rem; 12 | line-height: 2.3rem; 13 | letter-spacing: -0.6px; 14 | margin: ${p => 15 | `${p.theme.spacing.sm} 0 ${p.theme.spacing.sm} calc(${p.theme.spacing.xs} * -1.5)`}; 16 | padding: ${p => 17 | `${p.theme.spacing.xs} calc(${p.theme.spacing.xs} * 1.5) ${p.theme.spacing.xs}`}; 18 | width: calc(100% + 1.8rem); 19 | background-color: ${p => p.theme.colors.passiveBg}; 20 | 21 | @media ${p => p.theme.media.sm} { 22 | background-color: ${p => p.theme.colors.bg}; 23 | } 24 | `; 25 | 26 | const SidebarSearchInput = ({ value, onHandleInputChange }) => ( 27 | 33 | ); 34 | 35 | SidebarSearchInput.propTypes = { 36 | value: PropTypes.string, 37 | onHandleInputChange: PropTypes.func, 38 | }; 39 | 40 | export default SidebarSearchInput; 41 | -------------------------------------------------------------------------------- /packages/site/src/components/wrapper.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const Wrapper = styled.div` 4 | display: flex; 5 | flex-direction: column; 6 | flex-wrap: wrap; 7 | justify-content: space-between; 8 | margin: 0; 9 | padding: ${props => (props.noPadding ? '0 4rem' : '4rem')}; 10 | text-align: center; 11 | width: 100%; 12 | 13 | @media (min-width: 768px) { 14 | flex-direction: row; 15 | max-width: 116rem; 16 | padding: ${props => (props.noPadding ? '0 4rem' : '4rem 8rem')}; 17 | } 18 | 19 | @media (max-width: 768px) { 20 | padding: ${props => (props.noPadding ? '0 4rem' : '0 8rem')}; 21 | text-align: center; 22 | img { 23 | max-width: 240px; 24 | } 25 | } 26 | `; 27 | -------------------------------------------------------------------------------- /packages/site/src/constants.js: -------------------------------------------------------------------------------- 1 | const constants = { 2 | docsTitle: 'URQL', 3 | githubIssues: 'https://www.github.com/urql-graphql/urql/issues', 4 | github: 'https://www.github.com/urql-graphql/urql', 5 | readme: 'https://github.com/urql-graphql/urql/blob/main/README.md', 6 | color: '#6B78B8', 7 | googleAnalyticsId: 'UA-43290258-1', 8 | }; 9 | 10 | export default constants; 11 | -------------------------------------------------------------------------------- /packages/site/src/google-analytics.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useBasepath } from 'react-static'; 3 | import PropTypes from 'prop-types'; 4 | 5 | let Analytics = {}; 6 | 7 | if (typeof document !== 'undefined') { 8 | Analytics = require('react-router-ga').default; 9 | } else { 10 | Analytics = React.Fragment; 11 | } 12 | 13 | const GoogleAnalytics = ({ children, ...rest }) => { 14 | const basename = `/${useBasepath() || ''}`; 15 | if (typeof document !== 'undefined') { 16 | // fragment doesn't like it when you try to give it attributes 17 | return ( 18 | 19 | {children} 20 | 21 | ); 22 | } 23 | return {children}; 24 | }; 25 | 26 | GoogleAnalytics.propTypes = { 27 | children: PropTypes.element, 28 | }; 29 | 30 | export default GoogleAnalytics; 31 | -------------------------------------------------------------------------------- /packages/site/src/google-tag-manager.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Google Tag Manager 3 | */ 4 | const TagManager = require('react-gtm-module'); 5 | 6 | export const initGoogleTagManager = () => { 7 | if (typeof document === 'undefined') { 8 | return {}; 9 | } else { 10 | return TagManager.initialize({ gtmId: 'GTM-MD32945' }); 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /packages/site/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, hydrate } from 'react-dom'; 3 | import { AppContainer } from 'react-hot-loader'; 4 | 5 | import App from './app'; 6 | 7 | export default App; 8 | 9 | // Render your app 10 | if (typeof document !== 'undefined') { 11 | const renderMethod = module.hot ? render : hydrate; 12 | const mount = Comp => { 13 | renderMethod( 14 | 15 | 16 | , 17 | document.getElementById('root') 18 | ); 19 | }; 20 | 21 | mount(App); 22 | if (module.hot) { 23 | module.hot.accept('./app', () => mount(require('./app').default)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/site/src/screens/404/404.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const NotFound = () => { 4 | return

404! That page does not exist :(

; 5 | }; 6 | 7 | export default NotFound; 8 | -------------------------------------------------------------------------------- /packages/site/src/screens/404/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Docs from '../docs'; 3 | import NotFoundPage from './404'; 4 | 5 | const NotFound = () => { 6 | return ( 7 | 8 | 9 | 10 | ); 11 | }; 12 | 13 | export default NotFound; 14 | -------------------------------------------------------------------------------- /packages/site/src/screens/home/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | import { usePrefetch } from 'react-static'; 4 | import { useMarkdownTree } from 'react-static-plugin-md-pages'; 5 | 6 | import Features from './features'; 7 | import GetStarted from './get-started'; 8 | import MoreOSS from './more-oss'; 9 | import content from './_content'; 10 | import { Header } from '../../components/header'; 11 | import { Footer } from '../../components/footer'; 12 | 13 | const Container = styled.div` 14 | width: 100%; 15 | `; 16 | 17 | const Home = () => { 18 | const ref = usePrefetch('docs'); 19 | useMarkdownTree(); 20 | 21 | return ( 22 | 23 |
24 | 25 | 26 | 27 |