From 9f22f9f9de435d6601bcce69f8485cfb755b7b65 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Mon, 14 Nov 2022 13:14:06 +0000 Subject: [PATCH 1/6] initial commit --- examples/with-grafbase/.env.example | 2 + examples/with-grafbase/.eslintrc.json | 3 + examples/with-grafbase/.gitignore | 38 +++ examples/with-grafbase/.vscode/settings.json | 4 + examples/with-grafbase/README.md | 66 ++++ examples/with-grafbase/app/globals.css | 3 + examples/with-grafbase/app/head.tsx | 7 + examples/with-grafbase/app/layout.tsx | 80 +++++ examples/with-grafbase/app/page.tsx | 13 + .../with-grafbase/app/posts/[slug]/page.tsx | 34 ++ examples/with-grafbase/codegen.ts | 26 ++ .../with-grafbase/gql/fragment-masking.ts | 40 +++ examples/with-grafbase/gql/gql.ts | 18 ++ examples/with-grafbase/gql/graphql.ts | 302 ++++++++++++++++++ examples/with-grafbase/gql/index.ts | 2 + .../with-grafbase/grafbase/schema.graphql | 12 + examples/with-grafbase/lib/grafbase.ts | 11 + examples/with-grafbase/next.config.js | 11 + examples/with-grafbase/package.json | 34 ++ examples/with-grafbase/postcss.config.js | 6 + examples/with-grafbase/tailwind.config.js | 10 + examples/with-grafbase/tsconfig.json | 36 +++ 22 files changed, 758 insertions(+) create mode 100644 examples/with-grafbase/.env.example create mode 100644 examples/with-grafbase/.eslintrc.json create mode 100644 examples/with-grafbase/.gitignore create mode 100644 examples/with-grafbase/.vscode/settings.json create mode 100644 examples/with-grafbase/README.md create mode 100644 examples/with-grafbase/app/globals.css create mode 100644 examples/with-grafbase/app/head.tsx create mode 100644 examples/with-grafbase/app/layout.tsx create mode 100644 examples/with-grafbase/app/page.tsx create mode 100644 examples/with-grafbase/app/posts/[slug]/page.tsx create mode 100644 examples/with-grafbase/codegen.ts create mode 100644 examples/with-grafbase/gql/fragment-masking.ts create mode 100644 examples/with-grafbase/gql/gql.ts create mode 100644 examples/with-grafbase/gql/graphql.ts create mode 100644 examples/with-grafbase/gql/index.ts create mode 100644 examples/with-grafbase/grafbase/schema.graphql create mode 100644 examples/with-grafbase/lib/grafbase.ts create mode 100644 examples/with-grafbase/next.config.js create mode 100644 examples/with-grafbase/package.json create mode 100644 examples/with-grafbase/postcss.config.js create mode 100644 examples/with-grafbase/tailwind.config.js create mode 100644 examples/with-grafbase/tsconfig.json diff --git a/examples/with-grafbase/.env.example b/examples/with-grafbase/.env.example new file mode 100644 index 000000000000000..b1de6720459fee0 --- /dev/null +++ b/examples/with-grafbase/.env.example @@ -0,0 +1,2 @@ +GRAFBASE_API_URL=http://localhost:4000/graphql +GRAFBASE_API_KEY= diff --git a/examples/with-grafbase/.eslintrc.json b/examples/with-grafbase/.eslintrc.json new file mode 100644 index 000000000000000..bffb357a7122523 --- /dev/null +++ b/examples/with-grafbase/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/examples/with-grafbase/.gitignore b/examples/with-grafbase/.gitignore new file mode 100644 index 000000000000000..315d86ad9b20bef --- /dev/null +++ b/examples/with-grafbase/.gitignore @@ -0,0 +1,38 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +.grafbase \ No newline at end of file diff --git a/examples/with-grafbase/.vscode/settings.json b/examples/with-grafbase/.vscode/settings.json new file mode 100644 index 000000000000000..d0679104bdaba20 --- /dev/null +++ b/examples/with-grafbase/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib", + "typescript.enablePromptUseWorkspaceTsdk": true +} \ No newline at end of file diff --git a/examples/with-grafbase/README.md b/examples/with-grafbase/README.md new file mode 100644 index 000000000000000..75a7421540d2b19 --- /dev/null +++ b/examples/with-grafbase/README.md @@ -0,0 +1,66 @@ +# Next.js with Grafbase + +This example shows to use [Grafbase](https://grafbase.com) with Next.js. This example features fetching from a local GraphQL backend powered by the Grafbase CLI, and GraphQL Code Generator for making type-safe queries. + +## Demo + +You can see a demo of this online at [https://nextjs-with-grafbase.vercel.app](https://nextjs-with-grafbase.vercel.app). + +## Deploy + +Deploy this example using [Vercel](https://vercel.com): + +![Deploy to Vercel]() + +You will need to [create an account](https://grafbase.com/sign-up) with Grafbase and connect this example repo via GitHub. You can use the **API URL** and **API Key** provided by Grafbase to populate the environment variables with Vercel on deployment. + +## How to use + +Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example: + +```bash +npx create-next-app --example with-grafbase with-grafbase-app +``` + +```bash +yarn create next-app --example with-grafbase with-grafbase-app +``` + +```bash +pnpm create next-app --example with-grafbase with-grafbase-app +``` + +To run the example locally you need to: + +1. Copy the `.env.example` to `.env` and provide your API URL and API Key. In development the defaults are fine. + +2. Run the [Grafbase CLI](https://grafbase.com/cli) using `npx grafbase@latest dev` + +3. Populate the backend with some `Post` entries using a GraphQL mutation: + +```graphql +mutation { + postCreate( + input: { + title: "I love Next.js!" + slug: "i-love-nextjs" + comments: [{ create: { message: "me too!" } }] + } + ) { + post { + id + slug + } + } +} +``` + +4. Run the app locally and go to [http://localhost:3000](http://localhost:3000) to navigate to each post page! This data is fetched from the local backend. + +5. Optionally run `npm run codegen` to watch for any changes to queries inside of the app and automatically generate types. + +## Learn more + +- [Grafbase Quickstart](https://grafbase.com/docs/quickstart/get-started) — get started with Grafbase, quickly! +- [Create an account](https://grafbase.com/sign-up) — deploy to the edge with Grafbase! +- [Next.js Documentation](https://nextjs.org/docs) — learn more about Next.js \ No newline at end of file diff --git a/examples/with-grafbase/app/globals.css b/examples/with-grafbase/app/globals.css new file mode 100644 index 000000000000000..b5c61c956711f98 --- /dev/null +++ b/examples/with-grafbase/app/globals.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/examples/with-grafbase/app/head.tsx b/examples/with-grafbase/app/head.tsx new file mode 100644 index 000000000000000..ed769ffb74fc136 --- /dev/null +++ b/examples/with-grafbase/app/head.tsx @@ -0,0 +1,7 @@ +const Head = () => ( + <> + Grafbase + Next.js + +) + +export default Head \ No newline at end of file diff --git a/examples/with-grafbase/app/layout.tsx b/examples/with-grafbase/app/layout.tsx new file mode 100644 index 000000000000000..cc0ca42c43b326e --- /dev/null +++ b/examples/with-grafbase/app/layout.tsx @@ -0,0 +1,80 @@ +import './globals.css' + +import Link from 'next/link' + +import { graphql } from '../gql' +import { grafbase } from '../lib/grafbase' + +const GetAllPostsDocument = graphql(/* GraphQL */ ` + query GetAllPosts($first: Int!) { + postCollection(first: $first) { + edges { + node { + id + title + slug + } + } + } + } +`) + +const RootLayout = async ({ children }: { children: React.ReactNode }) => { + const { postCollection } = await grafbase.request(GetAllPostsDocument, { + first: 50 + }) + + return ( + + + Grafbase + Next.js 13 + + +
+ +
+
+
{children}
+
+
+
+ + + ) +} + +export default RootLayout diff --git a/examples/with-grafbase/app/page.tsx b/examples/with-grafbase/app/page.tsx new file mode 100644 index 000000000000000..fb61c3b6b6261b4 --- /dev/null +++ b/examples/with-grafbase/app/page.tsx @@ -0,0 +1,13 @@ +const Page = async () => { + return ( + <> +

Next.js 13 + Grafbase

+

+ Once you've added some posts using the GraphQL Playground, you can + explore each post by clicking the link in the nav. +

+ + ) +} + +export default Page diff --git a/examples/with-grafbase/app/posts/[slug]/page.tsx b/examples/with-grafbase/app/posts/[slug]/page.tsx new file mode 100644 index 000000000000000..b435712aefb9ece --- /dev/null +++ b/examples/with-grafbase/app/posts/[slug]/page.tsx @@ -0,0 +1,34 @@ +import { graphql } from '../../../gql' +import { grafbase } from '../../../lib/grafbase' + +export const revalidate = 3600 + +const GetPostBySlugDocument = graphql(/* GraphQL */ ` + query GetPostBySlug($slug: String!) { + post(by: { slug: $slug }) { + id + title + slug + } + } +`) + +const Page = async ({ params }: { params: { slug: string } }) => { + const { post } = await grafbase.request(GetPostBySlugDocument, { + slug: params.slug + }) + + if (!post) { + // optionally import notFound from next/navigation + return

404: Not Found

+ } + + return ( + <> +

{post.title}

+
{JSON.stringify(post, null, 2)}
+ + ) +} + +export default Page diff --git a/examples/with-grafbase/codegen.ts b/examples/with-grafbase/codegen.ts new file mode 100644 index 000000000000000..5a84a9e3caed607 --- /dev/null +++ b/examples/with-grafbase/codegen.ts @@ -0,0 +1,26 @@ +import { CodegenConfig } from '@graphql-codegen/cli' + +const url = process.env.GRAFBASE_API_URL as string +const xApiKey = process.env.GRAFBASE_API_KEY as string + +const config: CodegenConfig = { + schema: [ + { + [url]: { + headers: { + 'x-api-key': xApiKey + } + } + } + ], + documents: ['app/**/*.tsx', 'app/**/*.ts'], + ignoreNoDocuments: true, + generates: { + './gql/': { + preset: 'client', + plugins: [] + } + } +} + +export default config diff --git a/examples/with-grafbase/gql/fragment-masking.ts b/examples/with-grafbase/gql/fragment-masking.ts new file mode 100644 index 000000000000000..af0fecab42ee5e2 --- /dev/null +++ b/examples/with-grafbase/gql/fragment-masking.ts @@ -0,0 +1,40 @@ +import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; + + +export type FragmentType> = TDocumentType extends DocumentNode< + infer TType, + any +> + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never + : never + : never; + +// return non-nullable if `fragmentType` is non-nullable +export function useFragment( + _documentNode: DocumentNode, + fragmentType: FragmentType> +): TType; +// return nullable if `fragmentType` is nullable +export function useFragment( + _documentNode: DocumentNode, + fragmentType: FragmentType> | null | undefined +): TType | null | undefined; +// return array of non-nullable if `fragmentType` is array of non-nullable +export function useFragment( + _documentNode: DocumentNode, + fragmentType: ReadonlyArray>> +): ReadonlyArray; +// return array of nullable if `fragmentType` is array of nullable +export function useFragment( + _documentNode: DocumentNode, + fragmentType: ReadonlyArray>> | null | undefined +): ReadonlyArray | null | undefined +export function useFragment( + _documentNode: DocumentNode, + fragmentType: FragmentType> | ReadonlyArray>> | null | undefined +): TType | ReadonlyArray | null | undefined { + return fragmentType as any +} diff --git a/examples/with-grafbase/gql/gql.ts b/examples/with-grafbase/gql/gql.ts new file mode 100644 index 000000000000000..8e3ec8b954afdbf --- /dev/null +++ b/examples/with-grafbase/gql/gql.ts @@ -0,0 +1,18 @@ +/* eslint-disable */ +import * as types from './graphql'; +import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; + +const documents = { + "\n query GetAllPosts($first: Int!) {\n postCollection(first: $first) {\n edges {\n node {\n id\n title\n slug\n }\n }\n }\n }\n": types.GetAllPostsDocument, + "\n query GetPostBySlug($slug: String!) {\n post(by: { slug: $slug }) {\n id\n title\n slug\n }\n }\n": types.GetPostBySlugDocument, +}; + +export function graphql(source: "\n query GetAllPosts($first: Int!) {\n postCollection(first: $first) {\n edges {\n node {\n id\n title\n slug\n }\n }\n }\n }\n"): (typeof documents)["\n query GetAllPosts($first: Int!) {\n postCollection(first: $first) {\n edges {\n node {\n id\n title\n slug\n }\n }\n }\n }\n"]; +export function graphql(source: "\n query GetPostBySlug($slug: String!) {\n post(by: { slug: $slug }) {\n id\n title\n slug\n }\n }\n"): (typeof documents)["\n query GetPostBySlug($slug: String!) {\n post(by: { slug: $slug }) {\n id\n title\n slug\n }\n }\n"]; + +export function graphql(source: string): unknown; +export function graphql(source: string) { + return (documents as any)[source] ?? {}; +} + +export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never; \ No newline at end of file diff --git a/examples/with-grafbase/gql/graphql.ts b/examples/with-grafbase/gql/graphql.ts new file mode 100644 index 000000000000000..79686842bc1c232 --- /dev/null +++ b/examples/with-grafbase/gql/graphql.ts @@ -0,0 +1,302 @@ +/* eslint-disable */ +import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +export type Maybe = T | null; +export type InputMaybe = Maybe; +export type Exact = { [K in keyof T]: T[K] }; +export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; +export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: string; + String: string; + Boolean: boolean; + Int: number; + Float: number; + /** + * A date-time string at UTC, such as 2007-12-03T10:15:30Z, is compliant with the date-time format outlined in section 5.6 of the RFC 3339 + * profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. + * + * This scalar is a description of an exact instant on the timeline such as the instant that a user account was created. + * + * # Input Coercion + * + * When expected as an input type, only RFC 3339 compliant date-time strings are accepted. All other input values raise a query error indicating an incorrect type. + * + * # Result Coercion + * + * Where an RFC 3339 compliant date-time string has a time-zone other than UTC, it is shifted to UTC. + * For example, the date-time string 2016-01-01T14:10:20+01:00 is shifted to 2016-01-01T13:10:20Z. + */ + DateTime: any; +}; + +export type Comment = { + __typename?: 'Comment'; + /** when the model was created */ + createdAt: Scalars['DateTime']; + id: Scalars['ID']; + message: Scalars['String']; + post?: Maybe; + /** when the model was updated */ + updatedAt: Scalars['DateTime']; +}; + +export type CommentByInput = { + id?: InputMaybe; +}; + +/** Input to create a new CommentCommentRelatePostPost */ +export type CommentCommentRelatePostPostCreateInput = { + slug: Scalars['String']; + title: Scalars['String']; +}; + +/** Input to create a new CommentCommentRelatePostPost relation */ +export type CommentCommentRelatePostPostCreateRelationInput = { + create?: InputMaybe; + link?: InputMaybe; +}; + +/** Input to update a CommentCommentRelatePostPost relation */ +export type CommentCommentRelatePostPostUpdateRelationInput = { + create?: InputMaybe; + link?: InputMaybe; + unlink?: InputMaybe; +}; + +export type CommentConnection = { + __typename?: 'CommentConnection'; + edges?: Maybe>>; + /** Information to aid in pagination */ + pageInfo: PageInfo; +}; + +/** Input to create a new Comment */ +export type CommentCreateInput = { + message: Scalars['String']; + post?: InputMaybe; +}; + +export type CommentCreatePayload = { + __typename?: 'CommentCreatePayload'; + comment?: Maybe; +}; + +export type CommentDeletePayload = { + __typename?: 'CommentDeletePayload'; + deletedId: Scalars['ID']; +}; + +export type CommentEdge = { + __typename?: 'CommentEdge'; + cursor: Scalars['String']; + node: Comment; +}; + +/** Input to create a new Comment */ +export type CommentUpdateInput = { + message?: InputMaybe; + post?: InputMaybe; +}; + +export type CommentUpdatePayload = { + __typename?: 'CommentUpdatePayload'; + comment?: Maybe; +}; + +export type Mutation = { + __typename?: 'Mutation'; + /** Create a Comment */ + commentCreate?: Maybe; + /** Delete a Comment by ID or unique field */ + commentDelete?: Maybe; + /** Update a Comment */ + commentUpdate?: Maybe; + /** Create a Post */ + postCreate?: Maybe; + /** Delete a Post by ID or unique field */ + postDelete?: Maybe; + /** Update a Post */ + postUpdate?: Maybe; +}; + + +export type MutationCommentCreateArgs = { + input: CommentCreateInput; +}; + + +export type MutationCommentDeleteArgs = { + by: CommentByInput; +}; + + +export type MutationCommentUpdateArgs = { + by: CommentByInput; + input: CommentUpdateInput; +}; + + +export type MutationPostCreateArgs = { + input: PostCreateInput; +}; + + +export type MutationPostDeleteArgs = { + by: PostByInput; +}; + + +export type MutationPostUpdateArgs = { + by: PostByInput; + input: PostUpdateInput; +}; + +export type PageInfo = { + __typename?: 'PageInfo'; + endCursor?: Maybe; + hasNextPage: Scalars['Boolean']; + hasPreviousPage: Scalars['Boolean']; + startCursor?: Maybe; +}; + +export type Post = { + __typename?: 'Post'; + comments?: Maybe; + /** when the model was created */ + createdAt: Scalars['DateTime']; + id: Scalars['ID']; + slug: Scalars['String']; + title: Scalars['String']; + /** when the model was updated */ + updatedAt: Scalars['DateTime']; +}; + + +export type PostCommentsArgs = { + after?: InputMaybe; + before?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; +}; + +export type PostByInput = { + id?: InputMaybe; + slug?: InputMaybe; +}; + +/** Input to create a new PostCommentRelatePostComment */ +export type PostCommentRelatePostCommentCreateInput = { + message: Scalars['String']; +}; + +/** Input to create a new PostCommentRelatePostComment relation */ +export type PostCommentRelatePostCommentCreateRelationInput = { + create?: InputMaybe; + link?: InputMaybe; +}; + +/** Input to update a PostCommentRelatePostComment relation */ +export type PostCommentRelatePostCommentUpdateRelationInput = { + create?: InputMaybe; + link?: InputMaybe; + unlink?: InputMaybe; +}; + +export type PostConnection = { + __typename?: 'PostConnection'; + edges?: Maybe>>; + /** Information to aid in pagination */ + pageInfo: PageInfo; +}; + +/** Input to create a new Post */ +export type PostCreateInput = { + comments?: InputMaybe>>; + slug: Scalars['String']; + title: Scalars['String']; +}; + +export type PostCreatePayload = { + __typename?: 'PostCreatePayload'; + post?: Maybe; +}; + +export type PostDeletePayload = { + __typename?: 'PostDeletePayload'; + deletedId: Scalars['ID']; +}; + +export type PostEdge = { + __typename?: 'PostEdge'; + cursor: Scalars['String']; + node: Post; +}; + +/** Input to create a new Post */ +export type PostUpdateInput = { + comments?: InputMaybe>>; + slug?: InputMaybe; + title?: InputMaybe; +}; + +export type PostUpdatePayload = { + __typename?: 'PostUpdatePayload'; + post?: Maybe; +}; + +export type Query = { + __typename?: 'Query'; + /** Query a single Comment by an ID or a unique field */ + comment?: Maybe; + /** Paginated query to fetch the whole list of `Comment`. */ + commentCollection?: Maybe; + /** Query a single Post by an ID or a unique field */ + post?: Maybe; + /** Paginated query to fetch the whole list of `Post`. */ + postCollection?: Maybe; +}; + + +export type QueryCommentArgs = { + by: CommentByInput; +}; + + +export type QueryCommentCollectionArgs = { + after?: InputMaybe; + before?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; +}; + + +export type QueryPostArgs = { + by: PostByInput; +}; + + +export type QueryPostCollectionArgs = { + after?: InputMaybe; + before?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; +}; + +export type GetAllPostsQueryVariables = Exact<{ + first: Scalars['Int']; +}>; + + +export type GetAllPostsQuery = { __typename?: 'Query', postCollection?: { __typename?: 'PostConnection', edges?: Array<{ __typename?: 'PostEdge', node: { __typename?: 'Post', id: string, title: string, slug: string } } | null> | null } | null }; + +export type GetPostBySlugQueryVariables = Exact<{ + slug: Scalars['String']; +}>; + + +export type GetPostBySlugQuery = { __typename?: 'Query', post?: { __typename?: 'Post', id: string, title: string, slug: string } | null }; + + +export const GetAllPostsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAllPosts"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"first"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"postCollection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]}}]}}]} as unknown as DocumentNode; +export const GetPostBySlugDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetPostBySlug"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"slug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"post"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"by"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"slug"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/examples/with-grafbase/gql/index.ts b/examples/with-grafbase/gql/index.ts new file mode 100644 index 000000000000000..407a470658f82be --- /dev/null +++ b/examples/with-grafbase/gql/index.ts @@ -0,0 +1,2 @@ +export * from "./gql" +export * from "./fragment-masking" \ No newline at end of file diff --git a/examples/with-grafbase/grafbase/schema.graphql b/examples/with-grafbase/grafbase/schema.graphql new file mode 100644 index 000000000000000..4acbcc7e29fe00b --- /dev/null +++ b/examples/with-grafbase/grafbase/schema.graphql @@ -0,0 +1,12 @@ +type Post @model { + id: ID! + title: String! + slug: String! @unique + comments: [Comment] +} + +type Comment @model { + id: ID! + message: String! + post: Post +} diff --git a/examples/with-grafbase/lib/grafbase.ts b/examples/with-grafbase/lib/grafbase.ts new file mode 100644 index 000000000000000..5589809a1c0f9c7 --- /dev/null +++ b/examples/with-grafbase/lib/grafbase.ts @@ -0,0 +1,11 @@ +import { GraphQLClient } from 'graphql-request' +export { gql } from 'graphql-request' + +export const grafbase = new GraphQLClient( + process.env.GRAFBASE_API_URL as string, + { + headers: { + 'x-api-key': process.env.GRAFBASE_API_KEY as string + } + } +) diff --git a/examples/with-grafbase/next.config.js b/examples/with-grafbase/next.config.js new file mode 100644 index 000000000000000..69b0b8735e71e53 --- /dev/null +++ b/examples/with-grafbase/next.config.js @@ -0,0 +1,11 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, + swcMinify: true, + experimental: { + appDir: true + } + +} + +module.exports = nextConfig diff --git a/examples/with-grafbase/package.json b/examples/with-grafbase/package.json new file mode 100644 index 000000000000000..ebb3ec87f2e58e2 --- /dev/null +++ b/examples/with-grafbase/package.json @@ -0,0 +1,34 @@ +{ + "name": "with-grafbase", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "backend": "npx grafbase@latest dev & yarn codegen", + "build": "next build", + "start": "next start", + "lint": "next lint", + "codegen": "graphql-codegen --watch -r dotenv/config" + }, + "dependencies": { + "@types/node": "18.11.9", + "@types/react": "18.0.25", + "@types/react-dom": "18.0.8", + "eslint": "8.27.0", + "eslint-config-next": "13.0.3", + "graphql": "16.6.0", + "graphql-request": "5.0.0", + "next": "13.0.3", + "react": "18.2.0", + "react-dom": "18.2.0", + "typescript": "4.8.4" + }, + "devDependencies": { + "@graphql-codegen/cli": "2.13.12", + "@graphql-codegen/client-preset": "1.1.3", + "@tailwindcss/typography": "0.5.8", + "autoprefixer": "10.4.13", + "postcss": "8.4.19", + "tailwindcss": "3.2.4" + } +} diff --git a/examples/with-grafbase/postcss.config.js b/examples/with-grafbase/postcss.config.js new file mode 100644 index 000000000000000..33ad091d26d8a9d --- /dev/null +++ b/examples/with-grafbase/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/examples/with-grafbase/tailwind.config.js b/examples/with-grafbase/tailwind.config.js new file mode 100644 index 000000000000000..023e8cea3cdcd17 --- /dev/null +++ b/examples/with-grafbase/tailwind.config.js @@ -0,0 +1,10 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + "./app/**/*.{js,ts,jsx,tsx}", + ], + theme: { + extend: {}, + }, + plugins: [require('@tailwindcss/typography')] +} diff --git a/examples/with-grafbase/tsconfig.json b/examples/with-grafbase/tsconfig.json new file mode 100644 index 000000000000000..b25c4f834cb79c7 --- /dev/null +++ b/examples/with-grafbase/tsconfig.json @@ -0,0 +1,36 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ] + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts" + ], + "exclude": [ + "node_modules" + ] +} From 1ed3a6282db45185cd191f45a2cfb24a1b378ea1 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Tue, 15 Nov 2022 10:16:36 +0000 Subject: [PATCH 2/6] meet requirements --- .../{.env.example => .env.local.example} | 0 examples/with-grafbase/.eslintrc.json | 3 --- examples/with-grafbase/README.md | 12 +++++++----- examples/with-grafbase/package.json | 5 +---- 4 files changed, 8 insertions(+), 12 deletions(-) rename examples/with-grafbase/{.env.example => .env.local.example} (100%) delete mode 100644 examples/with-grafbase/.eslintrc.json diff --git a/examples/with-grafbase/.env.example b/examples/with-grafbase/.env.local.example similarity index 100% rename from examples/with-grafbase/.env.example rename to examples/with-grafbase/.env.local.example diff --git a/examples/with-grafbase/.eslintrc.json b/examples/with-grafbase/.eslintrc.json deleted file mode 100644 index bffb357a7122523..000000000000000 --- a/examples/with-grafbase/.eslintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "next/core-web-vitals" -} diff --git a/examples/with-grafbase/README.md b/examples/with-grafbase/README.md index 75a7421540d2b19..9bcde64f7286a59 100644 --- a/examples/with-grafbase/README.md +++ b/examples/with-grafbase/README.md @@ -8,11 +8,13 @@ You can see a demo of this online at [https://nextjs-with-grafbase.vercel.app](h ## Deploy -Deploy this example using [Vercel](https://vercel.com): +First deploy this to Grafbase to get your backend API URL and Key: -![Deploy to Vercel]() +[![Deploy to Grafbase](https://grafbase.com/button)](https://grafbase.com/new/configure?template=Next Example&source=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fwith-grafbase) -You will need to [create an account](https://grafbase.com/sign-up) with Grafbase and connect this example repo via GitHub. You can use the **API URL** and **API Key** provided by Grafbase to populate the environment variables with Vercel on deployment. +Then deploy this example using [Vercel](https://vercel.com): + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fwith-grafbase&env=GRAFBASE_API_URL,GRAFBASE_API_KEY) ## How to use @@ -32,7 +34,7 @@ pnpm create next-app --example with-grafbase with-grafbase-app To run the example locally you need to: -1. Copy the `.env.example` to `.env` and provide your API URL and API Key. In development the defaults are fine. +1. Copy the `.env.local.example` to `.env.local` and provide your API URL and API Key: `cp .env.local.example .env.local` — the defaults will be fine for development mode. 2. Run the [Grafbase CLI](https://grafbase.com/cli) using `npx grafbase@latest dev` @@ -63,4 +65,4 @@ mutation { - [Grafbase Quickstart](https://grafbase.com/docs/quickstart/get-started) — get started with Grafbase, quickly! - [Create an account](https://grafbase.com/sign-up) — deploy to the edge with Grafbase! -- [Next.js Documentation](https://nextjs.org/docs) — learn more about Next.js \ No newline at end of file +- [Next.js Documentation](https://nextjs.org/docs) — learn more about Next.js diff --git a/examples/with-grafbase/package.json b/examples/with-grafbase/package.json index ebb3ec87f2e58e2..ce7b532226dd713 100644 --- a/examples/with-grafbase/package.json +++ b/examples/with-grafbase/package.json @@ -7,18 +7,15 @@ "backend": "npx grafbase@latest dev & yarn codegen", "build": "next build", "start": "next start", - "lint": "next lint", "codegen": "graphql-codegen --watch -r dotenv/config" }, "dependencies": { "@types/node": "18.11.9", "@types/react": "18.0.25", "@types/react-dom": "18.0.8", - "eslint": "8.27.0", - "eslint-config-next": "13.0.3", "graphql": "16.6.0", "graphql-request": "5.0.0", - "next": "13.0.3", + "next": "latest", "react": "18.2.0", "react-dom": "18.2.0", "typescript": "4.8.4" From 650b4d7aef2e4c54bf2bbf684bd196c075945223 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Tue, 15 Nov 2022 12:20:54 +0000 Subject: [PATCH 3/6] remove package name --- examples/with-grafbase/package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/with-grafbase/package.json b/examples/with-grafbase/package.json index ce7b532226dd713..4ada5b1a9baf107 100644 --- a/examples/with-grafbase/package.json +++ b/examples/with-grafbase/package.json @@ -1,6 +1,4 @@ { - "name": "with-grafbase", - "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", From 301bb471d63bbc497dfbdda8ad637d0431812435 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Tue, 15 Nov 2022 12:21:38 +0000 Subject: [PATCH 4/6] chore: prettier --- examples/with-grafbase/.vscode/settings.json | 2 +- examples/with-grafbase/app/head.tsx | 2 +- examples/with-grafbase/app/layout.tsx | 2 +- .../with-grafbase/app/posts/[slug]/page.tsx | 2 +- examples/with-grafbase/codegen.ts | 14 +- .../with-grafbase/gql/fragment-masking.ts | 34 +- examples/with-grafbase/gql/gql.ts | 27 +- examples/with-grafbase/gql/graphql.ts | 498 +++++++++++------- examples/with-grafbase/gql/index.ts | 4 +- examples/with-grafbase/lib/grafbase.ts | 4 +- examples/with-grafbase/next.config.js | 5 +- examples/with-grafbase/tailwind.config.js | 6 +- examples/with-grafbase/tsconfig.json | 17 +- 13 files changed, 378 insertions(+), 239 deletions(-) diff --git a/examples/with-grafbase/.vscode/settings.json b/examples/with-grafbase/.vscode/settings.json index d0679104bdaba20..fae8e3d8a9765a3 100644 --- a/examples/with-grafbase/.vscode/settings.json +++ b/examples/with-grafbase/.vscode/settings.json @@ -1,4 +1,4 @@ { "typescript.tsdk": "node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true -} \ No newline at end of file +} diff --git a/examples/with-grafbase/app/head.tsx b/examples/with-grafbase/app/head.tsx index ed769ffb74fc136..5b847ecacdb2638 100644 --- a/examples/with-grafbase/app/head.tsx +++ b/examples/with-grafbase/app/head.tsx @@ -4,4 +4,4 @@ const Head = () => ( ) -export default Head \ No newline at end of file +export default Head diff --git a/examples/with-grafbase/app/layout.tsx b/examples/with-grafbase/app/layout.tsx index cc0ca42c43b326e..45c19159186122c 100644 --- a/examples/with-grafbase/app/layout.tsx +++ b/examples/with-grafbase/app/layout.tsx @@ -21,7 +21,7 @@ const GetAllPostsDocument = graphql(/* GraphQL */ ` const RootLayout = async ({ children }: { children: React.ReactNode }) => { const { postCollection } = await grafbase.request(GetAllPostsDocument, { - first: 50 + first: 50, }) return ( diff --git a/examples/with-grafbase/app/posts/[slug]/page.tsx b/examples/with-grafbase/app/posts/[slug]/page.tsx index b435712aefb9ece..2443b0f1ef559b0 100644 --- a/examples/with-grafbase/app/posts/[slug]/page.tsx +++ b/examples/with-grafbase/app/posts/[slug]/page.tsx @@ -15,7 +15,7 @@ const GetPostBySlugDocument = graphql(/* GraphQL */ ` const Page = async ({ params }: { params: { slug: string } }) => { const { post } = await grafbase.request(GetPostBySlugDocument, { - slug: params.slug + slug: params.slug, }) if (!post) { diff --git a/examples/with-grafbase/codegen.ts b/examples/with-grafbase/codegen.ts index 5a84a9e3caed607..28164af1fc11093 100644 --- a/examples/with-grafbase/codegen.ts +++ b/examples/with-grafbase/codegen.ts @@ -8,19 +8,19 @@ const config: CodegenConfig = { { [url]: { headers: { - 'x-api-key': xApiKey - } - } - } + 'x-api-key': xApiKey, + }, + }, + }, ], documents: ['app/**/*.tsx', 'app/**/*.ts'], ignoreNoDocuments: true, generates: { './gql/': { preset: 'client', - plugins: [] - } - } + plugins: [], + }, + }, } export default config diff --git a/examples/with-grafbase/gql/fragment-masking.ts b/examples/with-grafbase/gql/fragment-masking.ts index af0fecab42ee5e2..4de725491dd3ce4 100644 --- a/examples/with-grafbase/gql/fragment-masking.ts +++ b/examples/with-grafbase/gql/fragment-masking.ts @@ -1,40 +1,44 @@ -import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core' - -export type FragmentType> = TDocumentType extends DocumentNode< - infer TType, - any -> - ? TType extends { ' $fragmentName'?: infer TKey } - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType> = + TDocumentType extends DocumentNode + ? TType extends { ' $fragmentName'?: infer TKey } + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never : never : never - : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentNode, fragmentType: FragmentType> -): TType; +): TType // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentNode, fragmentType: FragmentType> | null | undefined -): TType | null | undefined; +): TType | null | undefined // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentNode, fragmentType: ReadonlyArray>> -): ReadonlyArray; +): ReadonlyArray // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentNode, - fragmentType: ReadonlyArray>> | null | undefined + fragmentType: + | ReadonlyArray>> + | null + | undefined ): ReadonlyArray | null | undefined export function useFragment( _documentNode: DocumentNode, - fragmentType: FragmentType> | ReadonlyArray>> | null | undefined + fragmentType: + | FragmentType> + | ReadonlyArray>> + | null + | undefined ): TType | ReadonlyArray | null | undefined { return fragmentType as any } diff --git a/examples/with-grafbase/gql/gql.ts b/examples/with-grafbase/gql/gql.ts index 8e3ec8b954afdbf..6bf7a46bc9f8df9 100644 --- a/examples/with-grafbase/gql/gql.ts +++ b/examples/with-grafbase/gql/gql.ts @@ -1,18 +1,25 @@ /* eslint-disable */ -import * as types from './graphql'; -import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import * as types from './graphql' +import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core' const documents = { - "\n query GetAllPosts($first: Int!) {\n postCollection(first: $first) {\n edges {\n node {\n id\n title\n slug\n }\n }\n }\n }\n": types.GetAllPostsDocument, - "\n query GetPostBySlug($slug: String!) {\n post(by: { slug: $slug }) {\n id\n title\n slug\n }\n }\n": types.GetPostBySlugDocument, -}; + '\n query GetAllPosts($first: Int!) {\n postCollection(first: $first) {\n edges {\n node {\n id\n title\n slug\n }\n }\n }\n }\n': + types.GetAllPostsDocument, + '\n query GetPostBySlug($slug: String!) {\n post(by: { slug: $slug }) {\n id\n title\n slug\n }\n }\n': + types.GetPostBySlugDocument, +} -export function graphql(source: "\n query GetAllPosts($first: Int!) {\n postCollection(first: $first) {\n edges {\n node {\n id\n title\n slug\n }\n }\n }\n }\n"): (typeof documents)["\n query GetAllPosts($first: Int!) {\n postCollection(first: $first) {\n edges {\n node {\n id\n title\n slug\n }\n }\n }\n }\n"]; -export function graphql(source: "\n query GetPostBySlug($slug: String!) {\n post(by: { slug: $slug }) {\n id\n title\n slug\n }\n }\n"): (typeof documents)["\n query GetPostBySlug($slug: String!) {\n post(by: { slug: $slug }) {\n id\n title\n slug\n }\n }\n"]; +export function graphql( + source: '\n query GetAllPosts($first: Int!) {\n postCollection(first: $first) {\n edges {\n node {\n id\n title\n slug\n }\n }\n }\n }\n' +): typeof documents['\n query GetAllPosts($first: Int!) {\n postCollection(first: $first) {\n edges {\n node {\n id\n title\n slug\n }\n }\n }\n }\n'] +export function graphql( + source: '\n query GetPostBySlug($slug: String!) {\n post(by: { slug: $slug }) {\n id\n title\n slug\n }\n }\n' +): typeof documents['\n query GetPostBySlug($slug: String!) {\n post(by: { slug: $slug }) {\n id\n title\n slug\n }\n }\n'] -export function graphql(source: string): unknown; +export function graphql(source: string): unknown export function graphql(source: string) { - return (documents as any)[source] ?? {}; + return (documents as any)[source] ?? {} } -export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never; \ No newline at end of file +export type DocumentType> = + TDocumentNode extends DocumentNode ? TType : never diff --git a/examples/with-grafbase/gql/graphql.ts b/examples/with-grafbase/gql/graphql.ts index 79686842bc1c232..97ba10d05a02b6b 100644 --- a/examples/with-grafbase/gql/graphql.ts +++ b/examples/with-grafbase/gql/graphql.ts @@ -1,17 +1,23 @@ /* eslint-disable */ -import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; -export type Maybe = T | null; -export type InputMaybe = Maybe; -export type Exact = { [K in keyof T]: T[K] }; -export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; -export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; +import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core' +export type Maybe = T | null +export type InputMaybe = Maybe +export type Exact = { + [K in keyof T]: T[K] +} +export type MakeOptional = Omit & { + [SubKey in K]?: Maybe +} +export type MakeMaybe = Omit & { + [SubKey in K]: Maybe +} /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { - ID: string; - String: string; - Boolean: boolean; - Int: number; - Float: number; + ID: string + String: string + Boolean: boolean + Int: number + Float: number /** * A date-time string at UTC, such as 2007-12-03T10:15:30Z, is compliant with the date-time format outlined in section 5.6 of the RFC 3339 * profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. @@ -27,276 +33,412 @@ export type Scalars = { * Where an RFC 3339 compliant date-time string has a time-zone other than UTC, it is shifted to UTC. * For example, the date-time string 2016-01-01T14:10:20+01:00 is shifted to 2016-01-01T13:10:20Z. */ - DateTime: any; -}; + DateTime: any +} export type Comment = { - __typename?: 'Comment'; + __typename?: 'Comment' /** when the model was created */ - createdAt: Scalars['DateTime']; - id: Scalars['ID']; - message: Scalars['String']; - post?: Maybe; + createdAt: Scalars['DateTime'] + id: Scalars['ID'] + message: Scalars['String'] + post?: Maybe /** when the model was updated */ - updatedAt: Scalars['DateTime']; -}; + updatedAt: Scalars['DateTime'] +} export type CommentByInput = { - id?: InputMaybe; -}; + id?: InputMaybe +} /** Input to create a new CommentCommentRelatePostPost */ export type CommentCommentRelatePostPostCreateInput = { - slug: Scalars['String']; - title: Scalars['String']; -}; + slug: Scalars['String'] + title: Scalars['String'] +} /** Input to create a new CommentCommentRelatePostPost relation */ export type CommentCommentRelatePostPostCreateRelationInput = { - create?: InputMaybe; - link?: InputMaybe; -}; + create?: InputMaybe + link?: InputMaybe +} /** Input to update a CommentCommentRelatePostPost relation */ export type CommentCommentRelatePostPostUpdateRelationInput = { - create?: InputMaybe; - link?: InputMaybe; - unlink?: InputMaybe; -}; + create?: InputMaybe + link?: InputMaybe + unlink?: InputMaybe +} export type CommentConnection = { - __typename?: 'CommentConnection'; - edges?: Maybe>>; + __typename?: 'CommentConnection' + edges?: Maybe>> /** Information to aid in pagination */ - pageInfo: PageInfo; -}; + pageInfo: PageInfo +} /** Input to create a new Comment */ export type CommentCreateInput = { - message: Scalars['String']; - post?: InputMaybe; -}; + message: Scalars['String'] + post?: InputMaybe +} export type CommentCreatePayload = { - __typename?: 'CommentCreatePayload'; - comment?: Maybe; -}; + __typename?: 'CommentCreatePayload' + comment?: Maybe +} export type CommentDeletePayload = { - __typename?: 'CommentDeletePayload'; - deletedId: Scalars['ID']; -}; + __typename?: 'CommentDeletePayload' + deletedId: Scalars['ID'] +} export type CommentEdge = { - __typename?: 'CommentEdge'; - cursor: Scalars['String']; - node: Comment; -}; + __typename?: 'CommentEdge' + cursor: Scalars['String'] + node: Comment +} /** Input to create a new Comment */ export type CommentUpdateInput = { - message?: InputMaybe; - post?: InputMaybe; -}; + message?: InputMaybe + post?: InputMaybe +} export type CommentUpdatePayload = { - __typename?: 'CommentUpdatePayload'; - comment?: Maybe; -}; + __typename?: 'CommentUpdatePayload' + comment?: Maybe +} export type Mutation = { - __typename?: 'Mutation'; + __typename?: 'Mutation' /** Create a Comment */ - commentCreate?: Maybe; + commentCreate?: Maybe /** Delete a Comment by ID or unique field */ - commentDelete?: Maybe; + commentDelete?: Maybe /** Update a Comment */ - commentUpdate?: Maybe; + commentUpdate?: Maybe /** Create a Post */ - postCreate?: Maybe; + postCreate?: Maybe /** Delete a Post by ID or unique field */ - postDelete?: Maybe; + postDelete?: Maybe /** Update a Post */ - postUpdate?: Maybe; -}; - + postUpdate?: Maybe +} export type MutationCommentCreateArgs = { - input: CommentCreateInput; -}; - + input: CommentCreateInput +} export type MutationCommentDeleteArgs = { - by: CommentByInput; -}; - + by: CommentByInput +} export type MutationCommentUpdateArgs = { - by: CommentByInput; - input: CommentUpdateInput; -}; - + by: CommentByInput + input: CommentUpdateInput +} export type MutationPostCreateArgs = { - input: PostCreateInput; -}; - + input: PostCreateInput +} export type MutationPostDeleteArgs = { - by: PostByInput; -}; - + by: PostByInput +} export type MutationPostUpdateArgs = { - by: PostByInput; - input: PostUpdateInput; -}; + by: PostByInput + input: PostUpdateInput +} export type PageInfo = { - __typename?: 'PageInfo'; - endCursor?: Maybe; - hasNextPage: Scalars['Boolean']; - hasPreviousPage: Scalars['Boolean']; - startCursor?: Maybe; -}; + __typename?: 'PageInfo' + endCursor?: Maybe + hasNextPage: Scalars['Boolean'] + hasPreviousPage: Scalars['Boolean'] + startCursor?: Maybe +} export type Post = { - __typename?: 'Post'; - comments?: Maybe; + __typename?: 'Post' + comments?: Maybe /** when the model was created */ - createdAt: Scalars['DateTime']; - id: Scalars['ID']; - slug: Scalars['String']; - title: Scalars['String']; + createdAt: Scalars['DateTime'] + id: Scalars['ID'] + slug: Scalars['String'] + title: Scalars['String'] /** when the model was updated */ - updatedAt: Scalars['DateTime']; -}; - + updatedAt: Scalars['DateTime'] +} export type PostCommentsArgs = { - after?: InputMaybe; - before?: InputMaybe; - first?: InputMaybe; - last?: InputMaybe; -}; + after?: InputMaybe + before?: InputMaybe + first?: InputMaybe + last?: InputMaybe +} export type PostByInput = { - id?: InputMaybe; - slug?: InputMaybe; -}; + id?: InputMaybe + slug?: InputMaybe +} /** Input to create a new PostCommentRelatePostComment */ export type PostCommentRelatePostCommentCreateInput = { - message: Scalars['String']; -}; + message: Scalars['String'] +} /** Input to create a new PostCommentRelatePostComment relation */ export type PostCommentRelatePostCommentCreateRelationInput = { - create?: InputMaybe; - link?: InputMaybe; -}; + create?: InputMaybe + link?: InputMaybe +} /** Input to update a PostCommentRelatePostComment relation */ export type PostCommentRelatePostCommentUpdateRelationInput = { - create?: InputMaybe; - link?: InputMaybe; - unlink?: InputMaybe; -}; + create?: InputMaybe + link?: InputMaybe + unlink?: InputMaybe +} export type PostConnection = { - __typename?: 'PostConnection'; - edges?: Maybe>>; + __typename?: 'PostConnection' + edges?: Maybe>> /** Information to aid in pagination */ - pageInfo: PageInfo; -}; + pageInfo: PageInfo +} /** Input to create a new Post */ export type PostCreateInput = { - comments?: InputMaybe>>; - slug: Scalars['String']; - title: Scalars['String']; -}; + comments?: InputMaybe< + Array> + > + slug: Scalars['String'] + title: Scalars['String'] +} export type PostCreatePayload = { - __typename?: 'PostCreatePayload'; - post?: Maybe; -}; + __typename?: 'PostCreatePayload' + post?: Maybe +} export type PostDeletePayload = { - __typename?: 'PostDeletePayload'; - deletedId: Scalars['ID']; -}; + __typename?: 'PostDeletePayload' + deletedId: Scalars['ID'] +} export type PostEdge = { - __typename?: 'PostEdge'; - cursor: Scalars['String']; - node: Post; -}; + __typename?: 'PostEdge' + cursor: Scalars['String'] + node: Post +} /** Input to create a new Post */ export type PostUpdateInput = { - comments?: InputMaybe>>; - slug?: InputMaybe; - title?: InputMaybe; -}; + comments?: InputMaybe< + Array> + > + slug?: InputMaybe + title?: InputMaybe +} export type PostUpdatePayload = { - __typename?: 'PostUpdatePayload'; - post?: Maybe; -}; + __typename?: 'PostUpdatePayload' + post?: Maybe +} export type Query = { - __typename?: 'Query'; + __typename?: 'Query' /** Query a single Comment by an ID or a unique field */ - comment?: Maybe; + comment?: Maybe /** Paginated query to fetch the whole list of `Comment`. */ - commentCollection?: Maybe; + commentCollection?: Maybe /** Query a single Post by an ID or a unique field */ - post?: Maybe; + post?: Maybe /** Paginated query to fetch the whole list of `Post`. */ - postCollection?: Maybe; -}; - + postCollection?: Maybe +} export type QueryCommentArgs = { - by: CommentByInput; -}; - + by: CommentByInput +} export type QueryCommentCollectionArgs = { - after?: InputMaybe; - before?: InputMaybe; - first?: InputMaybe; - last?: InputMaybe; -}; - + after?: InputMaybe + before?: InputMaybe + first?: InputMaybe + last?: InputMaybe +} export type QueryPostArgs = { - by: PostByInput; -}; - + by: PostByInput +} export type QueryPostCollectionArgs = { - after?: InputMaybe; - before?: InputMaybe; - first?: InputMaybe; - last?: InputMaybe; -}; + after?: InputMaybe + before?: InputMaybe + first?: InputMaybe + last?: InputMaybe +} export type GetAllPostsQueryVariables = Exact<{ - first: Scalars['Int']; -}>; - - -export type GetAllPostsQuery = { __typename?: 'Query', postCollection?: { __typename?: 'PostConnection', edges?: Array<{ __typename?: 'PostEdge', node: { __typename?: 'Post', id: string, title: string, slug: string } } | null> | null } | null }; + first: Scalars['Int'] +}> + +export type GetAllPostsQuery = { + __typename?: 'Query' + postCollection?: { + __typename?: 'PostConnection' + edges?: Array<{ + __typename?: 'PostEdge' + node: { __typename?: 'Post'; id: string; title: string; slug: string } + } | null> | null + } | null +} export type GetPostBySlugQueryVariables = Exact<{ - slug: Scalars['String']; -}>; - - -export type GetPostBySlugQuery = { __typename?: 'Query', post?: { __typename?: 'Post', id: string, title: string, slug: string } | null }; - - -export const GetAllPostsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAllPosts"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"first"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"postCollection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]}}]}}]} as unknown as DocumentNode; -export const GetPostBySlugDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetPostBySlug"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"slug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"post"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"by"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"slug"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file + slug: Scalars['String'] +}> + +export type GetPostBySlugQuery = { + __typename?: 'Query' + post?: { __typename?: 'Post'; id: string; title: string; slug: string } | null +} + +export const GetAllPostsDocument = { + kind: 'Document', + definitions: [ + { + kind: 'OperationDefinition', + operation: 'query', + name: { kind: 'Name', value: 'GetAllPosts' }, + variableDefinitions: [ + { + kind: 'VariableDefinition', + variable: { + kind: 'Variable', + name: { kind: 'Name', value: 'first' }, + }, + type: { + kind: 'NonNullType', + type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } }, + }, + }, + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'postCollection' }, + arguments: [ + { + kind: 'Argument', + name: { kind: 'Name', value: 'first' }, + value: { + kind: 'Variable', + name: { kind: 'Name', value: 'first' }, + }, + }, + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'edges' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'node' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'id' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'title' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'slug' }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], +} as unknown as DocumentNode +export const GetPostBySlugDocument = { + kind: 'Document', + definitions: [ + { + kind: 'OperationDefinition', + operation: 'query', + name: { kind: 'Name', value: 'GetPostBySlug' }, + variableDefinitions: [ + { + kind: 'VariableDefinition', + variable: { kind: 'Variable', name: { kind: 'Name', value: 'slug' } }, + type: { + kind: 'NonNullType', + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'String' }, + }, + }, + }, + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'post' }, + arguments: [ + { + kind: 'Argument', + name: { kind: 'Name', value: 'by' }, + value: { + kind: 'ObjectValue', + fields: [ + { + kind: 'ObjectField', + name: { kind: 'Name', value: 'slug' }, + value: { + kind: 'Variable', + name: { kind: 'Name', value: 'slug' }, + }, + }, + ], + }, + }, + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, + { kind: 'Field', name: { kind: 'Name', value: 'title' } }, + { kind: 'Field', name: { kind: 'Name', value: 'slug' } }, + ], + }, + }, + ], + }, + }, + ], +} as unknown as DocumentNode diff --git a/examples/with-grafbase/gql/index.ts b/examples/with-grafbase/gql/index.ts index 407a470658f82be..99775ae23cb0791 100644 --- a/examples/with-grafbase/gql/index.ts +++ b/examples/with-grafbase/gql/index.ts @@ -1,2 +1,2 @@ -export * from "./gql" -export * from "./fragment-masking" \ No newline at end of file +export * from './gql' +export * from './fragment-masking' diff --git a/examples/with-grafbase/lib/grafbase.ts b/examples/with-grafbase/lib/grafbase.ts index 5589809a1c0f9c7..d2cf5dc2f1ab26f 100644 --- a/examples/with-grafbase/lib/grafbase.ts +++ b/examples/with-grafbase/lib/grafbase.ts @@ -5,7 +5,7 @@ export const grafbase = new GraphQLClient( process.env.GRAFBASE_API_URL as string, { headers: { - 'x-api-key': process.env.GRAFBASE_API_KEY as string - } + 'x-api-key': process.env.GRAFBASE_API_KEY as string, + }, } ) diff --git a/examples/with-grafbase/next.config.js b/examples/with-grafbase/next.config.js index 69b0b8735e71e53..c73b884cee31f98 100644 --- a/examples/with-grafbase/next.config.js +++ b/examples/with-grafbase/next.config.js @@ -3,9 +3,8 @@ const nextConfig = { reactStrictMode: true, swcMinify: true, experimental: { - appDir: true - } - + appDir: true, + }, } module.exports = nextConfig diff --git a/examples/with-grafbase/tailwind.config.js b/examples/with-grafbase/tailwind.config.js index 023e8cea3cdcd17..d4b5c6122d0ad81 100644 --- a/examples/with-grafbase/tailwind.config.js +++ b/examples/with-grafbase/tailwind.config.js @@ -1,10 +1,8 @@ /** @type {import('tailwindcss').Config} */ module.exports = { - content: [ - "./app/**/*.{js,ts,jsx,tsx}", - ], + content: ['./app/**/*.{js,ts,jsx,tsx}'], theme: { extend: {}, }, - plugins: [require('@tailwindcss/typography')] + plugins: [require('@tailwindcss/typography')], } diff --git a/examples/with-grafbase/tsconfig.json b/examples/with-grafbase/tsconfig.json index b25c4f834cb79c7..6ef5cd577f6ed62 100644 --- a/examples/with-grafbase/tsconfig.json +++ b/examples/with-grafbase/tsconfig.json @@ -1,11 +1,7 @@ { "compilerOptions": { "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -24,13 +20,6 @@ } ] }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts" - ], - "exclude": [ - "node_modules" - ] + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] } From 90b80af0643ce85bcf343d9a62366f2cd24a22e9 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Tue, 15 Nov 2022 12:23:48 +0000 Subject: [PATCH 5/6] update link --- examples/with-grafbase/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/with-grafbase/README.md b/examples/with-grafbase/README.md index 9bcde64f7286a59..4e6ccd8c6a826ef 100644 --- a/examples/with-grafbase/README.md +++ b/examples/with-grafbase/README.md @@ -10,7 +10,7 @@ You can see a demo of this online at [https://nextjs-with-grafbase.vercel.app](h First deploy this to Grafbase to get your backend API URL and Key: -[![Deploy to Grafbase](https://grafbase.com/button)](https://grafbase.com/new/configure?template=Next Example&source=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fwith-grafbase) +[![Deploy to Grafbase](https://grafbase.com/button)](https://grafbase.com/new/configure?template=NextExample&source=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fwith-grafbase) Then deploy this example using [Vercel](https://vercel.com): From 986e230e728c8574f8d265b59bb445c66c319d14 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Tue, 15 Nov 2022 12:35:16 +0000 Subject: [PATCH 6/6] update demo link --- examples/with-grafbase/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/with-grafbase/README.md b/examples/with-grafbase/README.md index 4e6ccd8c6a826ef..e5e1ae94b314a69 100644 --- a/examples/with-grafbase/README.md +++ b/examples/with-grafbase/README.md @@ -4,7 +4,7 @@ This example shows to use [Grafbase](https://grafbase.com) with Next.js. This ex ## Demo -You can see a demo of this online at [https://nextjs-with-grafbase.vercel.app](https://nextjs-with-grafbase.vercel.app). +You can see a demo of this online at [https://grafbase-with-nextjs-rsc.grafbase-vercel.dev](https://grafbase-with-nextjs-rsc.grafbase-vercel.dev). ## Deploy