[
  {
    "path": ".editorconfig",
    "content": "# editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 2\nindent_style = space\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: ci\non:\n  push:\n  pull_request:\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - uses: the-guild-org/shared-config/setup@main\n        with:\n          nodeVersion: 16\n      - run: yarn codegen\n      - run: yarn workspace app run build\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - uses: the-guild-org/shared-config/setup@main\n        with:\n          nodeVersion: 16\n      - run: yarn workspace app run lint\n"
  },
  {
    "path": ".gitignore",
    "content": ".idea\n.DS_Store\n.env\n.env.production\nyarn-error.log\nnode_modules\n"
  },
  {
    "path": ".graphqlrc.yml",
    "content": "schema: ./graphql/schema/schema.graphql\ndocuments: ./app/**/*.{graphql,js,ts,jsx,tsx}\nextensions:\n  codegen:\n    generates:\n      ./app/gql:\n        preset: gql-tag-operations-preset\n    hooks:\n      afterOneFileWrite:\n        - prettier --write\n"
  },
  {
    "path": ".husky/.gitignore",
    "content": "_\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nnpx lint-staged\n"
  },
  {
    "path": ".vscode/extensions.json",
    "content": "{\n  \"recommendations\": [\n    \"esbenp.prettier-vscode\",\n    \"GraphQL.vscode-graphql\",\n    \"bradlc.vscode-tailwindcss\"\n  ]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"editor.formatOnSave\": true,\n  \"editor.defaultFormatter\": \"esbenp.prettier-vscode\"\n}\n"
  },
  {
    "path": "README.md",
    "content": "# Supabase GraphQL Example\n\nA basic HackerNews-like clone where posts can be submitted with url links and then up and down voted.\n\n<img width=\"1000\" alt=\"graphql-hn\" src=\"https://user-images.githubusercontent.com/10214025/160611420-29705df8-3e0a-471e-baef-04a3e2ac5618.png\">\n\n- Example: [supabase-graphql-example.vercel.app](https://supabase-graphql-example.vercel.app/)\n- Features: [supabase-graphql-example.vercel.app/about](https://supabase-graphql-example.vercel.app/about)\n\n## Showcase\n\n### Backend\n\n- CRUD (Query + Mutation Operations)\n- Cursor Based Pagination\n- Authorization / Postgres Row Level Security\n- [Supabase](https://supabase.com) - Create a backend in less than 2 minutes. Start your project with a Postgres Database, Authentication, instant APIs, Realtime subscriptions and Storage.\n- [pg_graphql](https://supabase.com/blog/2021/12/03/pg-graphql) - A native [PostgreSQL extension](https://supabase.github.io/pg_graphql/) adding [GraphQL support](https://graphql.org). The extension keeps schema generation, query parsing, and resolvers all neatly contained on your database server requiring no external services.\n- [Postgres Triggers](https://supabase.com/blog/2021/07/30/supabase-functions-updates) and [Postgres Functions](https://supabase.com/docs/guides/database/functions) - When votes are in, use triggers to invoke a Postgres function that calculates a post score to rank the feed\n- [Postgres Enumerated Types](https://www.postgresql.org/docs/14/datatype-enum.html) - Enums help defined the direction of a vote: UP or DOWN.\n\n### Frontend\n\n- [Next.js](https://nextjs.org) - React Framework\n- [TypeScript](https://www.typescriptlang.org) - TypeScript is a strongly typed programming language that builds on JavaScript, giving you better tooling at any scale.\n- [graphql-code-generator](https://www.graphql-code-generator.com) - Generate code from your GraphQL schema and operations with a simple CLI\n- [gql-tag-operations-preset](https://www.graphql-code-generator.com/plugins/gql-tag-operations-preset) - This code gen preset generates typings for your inline gql function usages, without having to manually specify import statements for the documents\n- [urql](https://formidable.com/open-source/urql/) - A highly customizable and versatile GraphQL client\n- [Gravatar](https://en.gravatar.com) - Default avatar profile images from Gravatar\n\n### Functionality\n\n- Registration\n- Get a ranked feed of posts\n- Create Post\n- Delete Post\n- Create Comment\n- Delete Comment\n- Upvote/Downvote Post\n- View Profile (Account)\n- View Profile (Public)\n- Pagination (Posts, Comments)\n\n## QuickStart\n\n### Setup env vars\n\n- `cp app/.env.example app/.env`\n- Fill in your url and anon key from the Supabase Dashboard: https://app.supabase.io/project/_/settings/api\n\n### Install dependencies, GraphQL codegen, run app\n\n```bash\nyarn\nyarn codegen\nyarn workspace app dev\n```\n\n### Deploy to Vercel\n\nProvide the following settings to deploy a production build to Vercel:\n\n- BUILD COMMAND: `yarn codegen && yarn workspace app build`\n- OUTPUT DIRECTORY: `./app/.next`\n- INSTALL COMMAND: `yarn`\n- DEVELOPMENT COMMAND: `yarn codegen && yarn workspace app dev --port $PORT`\n\n## Development\n\n1. Fetch latest GraphQL Schema\n\n```bash\nyarn codegen:fetch\n```\n\n2. Generate Types and Watch for Changes\n\n```bash\nyarn codegen:watch\n```\n\n3. Run server\n\n```bash\nyarn workspace app dev\n```\n\n### Synchronize the GraphQL schema\n\nNote: You need to call `select graphql.rebuild_schema()` manually to synchronize the GraphQL schema with the SQL schema after altering the SQL schema.\n\n#### Manage Schema with dbmate\n\n1. `brew install dbmate`\n2. Setup `.env` with `DATABASE_URL`\n3. Dump Schema\n\n```\ncd data\ndbmate dump\n```\n\n> Note: If `pgdump` fails due to row locks, a workaround is to grant the `postgres` role superuser permissions with `ALTER USER postgres WITH SUPERUSER`. After dumping the schema, you should reset the permissions using `ALTER USER postgres WITH NOSUPERUSER`. You can run these statements in the Superbase Dashboard SQL Editors.\n\n## Schema (Public)\n\n- Profile belongs to auth.users\n- Post\n- Comment belongs to Post and Profile\n- Vote belongs to Post (can have a direction of UP/DOWN)\n\n- direction enum is \"UP\" or \"DOWN\"\n\n### Constraints\n\n- Post `url` is unique\n- Vote is unique per Profile, Post (ie, you cannot vote more than once -- up or down)\n\nSee: [`./data/db/schema.sql`](./data/db/schema.sql)\n\n> Note: The schema includes the entire Supabase schema with auth, storage, functions, etc.\n\n## Seed Data\n\nA data file for all Supabase Blog posts from the RSS feed can be found in `./data/seed/blog_posts.csv` and can be loaded. Another file for `comments` is available as well.\n\nNote: Assumes a known `profileId` currently.\n\n## GraphQL Schema\n\nSee: [`./graphql/schema/schema.graphql`](./graphql/schema/schema.graphql)\n\n## Example Query\n\nSee: [`./graphql/queries/`](./graphql/queries/)\n\nUse: `https://mvrfvzcivgabojxddwtk.supabase.co/graphql/v1`\n\n> Note: Needs headers\n\n```\n\nContent-Type: application/json\napiKey: <supabase_anon_key>\n\n```\n\n## GraphiQL\n\nGraphiQL is an in-browser IDE for writing, validating, and testing GraphQL queries.\n\nVisit `http://localhost:3000/api/graphiql` for the [Yoga GraphiQL Playground](https://www.graphql-yoga.com/docs/features/graphiql) where you can experiment with queries and mutations.\n\n> Note: Needs headers\n\n```\n\nContent-Type: application/json\napiKey: <supabase_anon_key>\n\n```\n\n> Note: In order for the RLS policies authenticate you, you have to pass an authorization header ([see example](https://github.com/supabase-community/supabase-graphql-example/blob/main/app/lib/urql.tsx#L15)):\n\n```\nauthorization: Bearer <access_token>\n\n```\n\n### Ranked Feed\n\n```gql\nquery {\n  rankedFeed: postCollection(orderBy: [{ voteRank: AscNullsFirst }]) {\n    edges {\n      post: node {\n        id\n        title\n        url\n        upVoteTotal\n        downVoteTotal\n        voteTotal\n        voteDelta\n        score\n        voteRank\n        comments: commentCollection {\n          edges {\n            node {\n              id\n              message\n              profile {\n                id\n                username\n                avatarUrl\n              }\n            }\n          }\n          commentCount: totalCount\n        }\n      }\n    }\n  }\n}\n```\n\n# Row Level Security Matrix (RLS)\n\nYou can query all policies via: `select * from pg_policies`.\n\nSee: [Row Level Security Matrix (RLS)](./data/supabase/rls-policies.md)\n\n## Read More\n\n- [pg_graphql](https://supabase.github.io/pg_graphql)\n- [pg_graphql Configuration](https://supabase.github.io/pg_graphql/configuration)\n\n## Troubleshooting\n\n1. `dbmate` can create `schema_migrations` tables in schemas. To make sure they are not included in your GraphQL Schema:\n\n```sql\nrevoke select on table public.schema_migrations from anon, authenticated;\n```\n\n2. To [enable inflection](https://supabase.github.io/pg_graphql/configuration/#inflection)\n\n```sql\ncomment on schema public is e'@graphql({\"inflect_names\": true})';\n```\n\n3. Try the heartbeat to see if pg_graphql can access requests\n\n```\nselect graphql_public.graphql(\n\tnull,\n\t$$ { heartbeat }$$\n)\n```\n\nReturns:\n\n```json\n{ \"data\": { \"heartbeat\": \"2022-07-28T17:07:07.90513\" } }\n```\n\n4. Is the `public_graphql` schema not exposed properly?\n\nGetting an 406 status or error message like:\n\n```\n{\n    \"message\": \"The schema must be one of the following: public, storage\"\n}\n```\n\nThen be sure to expose the `graphql_public` in `Settings` > `Project settings` > `API`.\n\n> The schema to expose in your API. Tables, views and stored procedures in this schema will get API endpoints.\n\n![image](https://user-images.githubusercontent.com/1051633/181597157-f9a47a5b-bc6a-49d4-b41e-9c1324b5e2a7.png)\n"
  },
  {
    "path": "app/.eslintrc.json",
    "content": "{\n  \"extends\": \"next/core-web-vitals\"\n}\n"
  },
  {
    "path": "app/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# next.js\n/.next/\n/out/\n\n# production\n/build\n\n# misc\n.DS_Store\n*.pem\n\n# debug\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n.pnpm-debug.log*\n\n# local env files\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\n# vercel\n.vercel\n\n# typescript\n*.tsbuildinfo\n"
  },
  {
    "path": "app/README.md",
    "content": "This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).\n\n## Getting Started\n\nFirst, run the development server:\n\n```bash\nnpm run dev\n# or\nyarn dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000) with your browser to see the result.\n\nYou can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.\n\n[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.\n\nThe `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.\n\n## Learn More\n\nTo learn more about Next.js, take a look at the following resources:\n\n- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.\n- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.\n\nYou can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!\n\n## Deploy on Vercel\n\nThe easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.\n\nCheck out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.\n"
  },
  {
    "path": "app/gql/.gitignore",
    "content": "*.ts\n*.tsx\n"
  },
  {
    "path": "app/lib/active-link.tsx",
    "content": "import React from \"react\";\nimport { useRouter } from \"next/router\";\nimport Link from \"next/link\";\n\n/**\n * @source https://nextjs.org/docs/api-reference/next/link\n * @source https://github.com/vercel/next.js/tree/canary/examples/active-class-name\n */\nexport function ActiveLink({\n  children,\n  activeClassName,\n  ...props\n}: {\n  children: React.ReactNode;\n  activeClassName: string;\n  href: string;\n  as?: string;\n}) {\n  const { asPath, isReady } = useRouter();\n\n  const child = React.Children.only(children) as React.DetailedReactHTMLElement<\n    any,\n    HTMLElement\n  >;\n  const childClassName = child.props?.className || \"\";\n  const [className, setClassName] = React.useState(childClassName);\n\n  React.useEffect(() => {\n    // Check if the router fields are updated client-side\n    if (isReady) {\n      // Dynamic route will be matched via props.as\n      // Static route will be matched via props.href\n      const linkPathname = new URL(props.as || props.href, location.href)\n        .pathname;\n\n      // Using URL().pathname to get rid of query and hash\n      const activePathname = new URL(asPath, location.href).pathname;\n\n      const newClassName =\n        linkPathname === activePathname\n          ? `${childClassName} ${activeClassName}`.trim()\n          : childClassName;\n\n      if (newClassName !== className) {\n        setClassName(newClassName);\n      }\n    }\n  }, [\n    asPath,\n    isReady,\n    props.as,\n    props.href,\n    childClassName,\n    activeClassName,\n    setClassName,\n    className,\n  ]);\n\n  return (\n    <Link {...props}>\n      {React.cloneElement(child, {\n        className: className || null,\n      })}\n    </Link>\n  );\n}\n"
  },
  {
    "path": "app/lib/comment-item.tsx",
    "content": "import React from \"react\";\nimport Link from \"next/link\";\nimport { useRouter } from \"next/router\";\n\nimport { useMutation } from \"urql\";\n\nimport { Auth } from \"@supabase/ui\";\nimport { TrashIcon } from \"@heroicons/react/outline\";\nimport { CalendarIcon, UserIcon } from \"./icons\";\nimport { DocumentType, gql } from \"../gql\";\nimport { timeAgo } from \"./time-ago\";\n\nconst CommentItem_CommentFragment = gql(/* GraphQL */ `\n  fragment CommentItem_CommentFragment on Comment {\n    id\n    message\n    createdAt\n    post {\n      id\n      title\n    }\n    profile {\n      id\n      username\n      avatarUrl\n    }\n  }\n`);\n\nconst CommentItem_DeleteCommentFragment = gql(/* GraphQL */ `\n  mutation CommentItem_DeleteComment($commentId: BigInt!) {\n    deleteFromCommentCollection(atMost: 1, filter: { id: { eq: $commentId } }) {\n      affectedCount\n    }\n  }\n`);\n\nexport function CommentItem(props: {\n  comment: DocumentType<typeof CommentItem_CommentFragment>;\n}) {\n  const router = useRouter();\n  const { user } = Auth.useUser();\n  const [deleteCommentMutation, deleteComment] = useMutation(\n    CommentItem_DeleteCommentFragment\n  );\n  const createdAt = React.useMemo(\n    () => timeAgo.format(new Date(props.comment.createdAt)),\n    [props.comment.createdAt]\n  );\n\n  React.useEffect(() => {\n    if (deleteCommentMutation.data) {\n      router.reload();\n    }\n  }, [deleteCommentMutation.data]);\n  return (\n    <div className=\"flex space-x-3 py-4\">\n      <img\n        className=\"h-6 w-6 rounded-full\"\n        src={props.comment.profile?.avatarUrl ?? undefined}\n        alt=\"\"\n      />\n      <div className=\"flex-1 space-y-1\">\n        <div className=\"flex items-center justify-between\">\n          <h3 className=\"text-sm font-medium\">\n            <Link href={`/profile/${props.comment.profile?.id}`}>\n              <a className=\"text-gray-800 hover:text-green-500\">\n                {props.comment.profile?.username}\n              </a>\n            </Link>\n          </h3>\n          <p className=\"text-sm text-gray-500\">\n            <Link href={`/item/${props.comment.post?.id}`}>\n              <a className=\"text-gray-800 hover:text-green-500 inline-flex items-center text-sm\">\n                <CalendarIcon className=\"w-4 h-4 mr-1\" />\n                {createdAt}\n              </a>\n            </Link>\n          </p>\n        </div>\n        <p className=\"text-sm text-gray-500\">\n          {props.comment.message}\n          {user?.id && user.id === props.comment.profile?.id ? (\n            <button\n              type=\"button\"\n              className=\"inline-flex items-center ml-2 p-1 border border-transparent rounded-full shadow-sm text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500\"\n              onClick={() => {\n                deleteComment({\n                  commentId: props.comment.id,\n                });\n              }}\n            >\n              <TrashIcon className=\"h-2 w-2\" />\n            </button>\n          ) : null}\n        </p>\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "app/lib/container.tsx",
    "content": "import React from \"react\";\n\nexport function Container(props: { children: React.ReactNode }) {\n  return <main className=\"px-0 py-2\">{props.children}</main>;\n}\n"
  },
  {
    "path": "app/lib/feed-item.tsx",
    "content": "import { Auth } from \"@supabase/ui\";\nimport Link from \"next/link\";\nimport { useRouter } from \"next/router\";\nimport React from \"react\";\nimport { useMutation } from \"urql\";\nimport { Modal } from \"@supabase/ui\";\n\nimport { DocumentType, gql } from \"../gql\";\nimport {\n  CalendarIcon,\n  ChevronDownIcon,\n  ChevronUpIcon,\n  CommentIcon,\n  PointIcon,\n  TrashIcon,\n  UserIcon,\n} from \"./icons\";\nimport { timeAgo } from \"./time-ago\";\n\nconst VoteButtons_PostFragment = gql(/* GraphQL */ `\n  fragment VoteButtons_PostFragment on Post {\n    id\n    upVoteByViewer: voteCollection(\n      filter: { profileId: { eq: $profileId }, direction: { eq: \"UP\" } }\n    ) {\n      totalCount\n    }\n    downVoteByViewer: voteCollection(\n      filter: { profileId: { eq: $profileId }, direction: { eq: \"DOWN\" } }\n    ) {\n      totalCount\n    }\n  }\n`);\n\nconst VoteButtons_DeleteVoteMutation = gql(/* GraphQL */ `\n  mutation VoteButtons_DeleteVoteMutation($postId: BigInt!, $profileId: UUID!) {\n    deleteFromVoteCollection(\n      filter: { postId: { eq: $postId }, profileId: { eq: $profileId } }\n    ) {\n      __typename\n    }\n  }\n`);\n\nconst VoteButtons_VoteMutation = gql(/* GraphQL */ `\n  mutation VoteButtons_VoteMutation(\n    $postId: BigInt!\n    $profileId: UUID!\n    $voteDirection: String!\n  ) {\n    insertIntoVoteCollection(\n      objects: [\n        { postId: $postId, profileId: $profileId, direction: $voteDirection }\n      ]\n    ) {\n      __typename\n      affectedCount\n      records {\n        id\n        direction\n      }\n    }\n  }\n`);\n\nfunction VoteButtons(props: {\n  post: DocumentType<typeof VoteButtons_PostFragment>;\n}) {\n  const router = useRouter();\n  const { user } = Auth.useUser();\n  const [, deleteVote] = useMutation(VoteButtons_DeleteVoteMutation);\n  const [voteMutation, vote] = useMutation(VoteButtons_VoteMutation);\n\n  React.useEffect(() => {\n    if (voteMutation.data) {\n      router.reload();\n    }\n  }, [voteMutation.data]);\n\n  return (\n    <div className=\"flex flex-col self-center mr-3 pb-8\">\n      <button\n        onClick={async () => {\n          if (!user) {\n            router.push(\"/login\");\n          } else if (props.post.upVoteByViewer?.totalCount === 0) {\n            await deleteVote({\n              postId: props.post.id,\n              profileId: user.id,\n            });\n            vote({\n              postId: props.post.id,\n              profileId: user.id,\n              voteDirection: \"UP\",\n            });\n          }\n        }}\n      >\n        <ChevronUpIcon\n          strokeWidth={props.post.upVoteByViewer?.totalCount !== 0 ? \"4\" : \"2\"}\n        />\n      </button>\n      <button\n        onClick={async () => {\n          if (!user) {\n            router.push(\"/login\");\n          } else if (props.post.downVoteByViewer?.totalCount === 0) {\n            await deleteVote({\n              postId: props.post.id,\n              profileId: user.id,\n            });\n            vote({\n              postId: props.post.id,\n              profileId: user.id,\n              voteDirection: \"DOWN\",\n            });\n          }\n        }}\n      >\n        <ChevronDownIcon\n          strokeWidth={\n            props.post.downVoteByViewer?.totalCount !== 0 ? \"4\" : \"2\"\n          }\n        />\n      </button>\n    </div>\n  );\n}\n\nconst FeedItem_PostFragment = gql(/* GraphQL */ `\n  fragment FeedItem_PostFragment on Post {\n    id\n    title\n    url\n    voteTotal\n    createdAt\n    commentCollection {\n      totalCount\n    }\n    profile {\n      id\n      username\n      avatarUrl\n    }\n    ...VoteButtons_PostFragment\n    ...DeleteButton_PostFragment\n  }\n`);\n\nexport function FeedItem(props: {\n  post: DocumentType<typeof FeedItem_PostFragment>;\n}) {\n  const { user } = Auth.useUser();\n  const createdAt = React.useMemo(\n    () => timeAgo.format(new Date(props.post.createdAt)),\n    [props.post.createdAt]\n  );\n  return (\n    <div className=\"py-1 flex flex-wrap md:flex-nowrap mb-8 border-gray-100 border-b-2\">\n      <VoteButtons post={props.post} />\n      <div className=\"flex-1 md:flex-grow\">\n        <Link href={props.post.url}>\n          <a>\n            <h2 className=\"text-2xl font-medium text-gray-900 hover:text-green-500 title-font mb-2\">\n              {props.post.title}\n            </h2>\n          </a>\n        </Link>\n\n        <div className=\"flex items-center flex-wrap pb-4 border-gray-100 mt-auto w-full\">\n          <span className=\"text-gray-400 mr-3 inline-flex items-center  text-sm pr-3 py-1 border-r-2 border-gray-200\">\n            <PointIcon className=\"w-4 h-4 mr-1\" />\n            {props.post.voteTotal}{\" \"}\n            {props.post.voteTotal === 1 ? \"point\" : \"points\"}\n          </span>\n          <Link href={`/item/${props.post.id}`}>\n            <a className=\"text-gray-400 hover:text-green-400 mr-3 inline-flex items-center text-sm pr-3 py-1 border-r-2 border-gray-200\">\n              <CommentIcon className=\"w-4 h-4 mr-1\" />\n              {props.post.commentCollection?.totalCount}{\" \"}\n              {props.post.commentCollection?.totalCount === 1\n                ? \"comment\"\n                : \"comments\"}\n            </a>\n          </Link>\n          <Link href={`/profile/${props.post.profile?.id}`}>\n            <a className=\"text-gray-400 hover:text-green-400 mr-3 inline-flex items-center text-sm pr-3 py-1 border-r-2 border-gray-200\">\n              <img\n                className=\"inline-block h-4 w-4 rounded-full w-4 h-4 mr-1\"\n                src={props.post.profile?.avatarUrl ?? \"\"}\n              />\n              {props.post.profile?.username}\n            </a>\n          </Link>\n          <Link href={`/item/${props.post.id}`}>\n            <a className=\"text-gray-400 hover:text-green-400 inline-flex items-center text-sm\">\n              <CalendarIcon className=\"w-4 h-4 mr-1\" />\n              {createdAt}\n            </a>\n          </Link>\n          {user?.id && props.post.profile?.id === user?.id ? (\n            <DeleteButton post={props.post} />\n          ) : null}\n        </div>\n      </div>\n    </div>\n  );\n}\n\nconst DeleteButton_DeletePostMutation = gql(/* GraphQL */ `\n  mutation DeleteButton_DeletePostMutation($postId: BigInt!) {\n    deleteFromPostCollection(atMost: 1, filter: { id: { eq: $postId } }) {\n      affectedCount\n    }\n  }\n`);\n\nconst DeleteButton_PostFragment = gql(/* GraphQL */ `\n  fragment DeleteButton_PostFragment on Post {\n    id\n  }\n`);\n\nconst DeleteButton = (props: {\n  post: DocumentType<typeof DeleteButton_PostFragment>;\n}) => {\n  const router = useRouter();\n  const [show, setShow] = React.useState(false);\n  const [deletePostMutation, deletePost] = useMutation(\n    DeleteButton_DeletePostMutation\n  );\n\n  React.useEffect(() => {\n    if (deletePostMutation.data) {\n      router.push(\"/\");\n    }\n  }, [deletePostMutation.data, deletePostMutation.error]);\n\n  return (\n    <>\n      <button\n        className=\"text-gray-400 hover:text-green-400 inline-flex items-center text-sm pl-3 ml-3 border-l-2 border-gray-200\"\n        onClick={() => setShow(true)}\n      >\n        <TrashIcon className=\"w-4 h-4 mr-1\" />\n        Delete\n      </button>\n      <Modal\n        title=\"Do you want to delete your post?\"\n        visible={show}\n        onCancel={() => setShow(false)}\n        onConfirm={() => {\n          deletePost({\n            postId: props.post.id,\n          });\n        }}\n      >\n        Deleting your post can not be reverted\n      </Modal>\n    </>\n  );\n};\n"
  },
  {
    "path": "app/lib/footer.tsx",
    "content": "import Image from \"next/image\";\nimport Link from \"next/link\";\n\nexport function Footer() {\n  const navigation = {\n    main: [{ name: \"🤔 How did we build this app?\", href: \"/about\" }],\n    social: [\n      {\n        name: \"Twitter\",\n        href: \"https://twitter.com/supabase\",\n        icon: (props: any) => (\n          <svg fill=\"currentColor\" viewBox=\"0 0 24 24\" {...props}>\n            <path d=\"M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84\" />\n          </svg>\n        ),\n      },\n      {\n        name: \"GitHub\",\n        href: \"https://github.com/supabase-community/supabase-graphql-example\",\n        icon: (props: any) => (\n          <svg fill=\"currentColor\" viewBox=\"0 0 24 24\" {...props}>\n            <path\n              fillRule=\"evenodd\"\n              d=\"M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z\"\n              clipRule=\"evenodd\"\n            />\n          </svg>\n        ),\n      },\n    ],\n  };\n\n  return (\n    <footer className=\"bg-white\">\n      <div className=\"max-w-7xl mx-auto py-4 px-4 overflow-hidden sm:px-6 lg:px-8\">\n        <div className=\"bg-white\">\n          <div className=\"max-w-7xl mx-auto py-4 px-4 sm:px-6 lg:px-8\">\n            <div className=\"grid grid-cols-2 gap-8 md:grid-cols-2 lg:grid-cols-2\">\n              <div className=\"col-span-1 flex justify-center md:col-span-2 lg:col-span-1\">\n                <a href=\"https://www.supabase.com\">\n                  <img\n                    className=\"h-12\"\n                    src=\"/supabase-logo-wordmark--light.svg\"\n                    alt=\"Supabase\"\n                  />\n                </a>\n              </div>\n              <div className=\"col-span-1 flex justify-center md:col-span-2 lg:col-span-1\">\n                <a href=\"https://www.the-guild.dev\">\n                  <img\n                    className=\"h-12\"\n                    src=\"/the-guild-full-dark.svg\"\n                    alt=\"The Guild\"\n                  />\n                </a>\n              </div>\n            </div>\n          </div>\n        </div>\n        <nav\n          className=\"-mx-5 -my-2 flex flex-wrap justify-center\"\n          aria-label=\"Footer\"\n        >\n          {navigation.main.map((item) => (\n            <div key={item.name} className=\"px-5 py-2\">\n              <Link href={item.href}>\n                <a className=\"text-base text-gray-500 hover:text-gray-900\">\n                  {item.name}\n                </a>\n              </Link>\n            </div>\n          ))}\n        </nav>\n        <div className=\"mt-8 flex justify-center space-x-6\">\n          {navigation.social.map((item) => (\n            <a\n              key={item.name}\n              href={item.href}\n              className=\"text-gray-400 hover:text-gray-500\"\n            >\n              <span className=\"sr-only\">{item.name}</span>\n              <item.icon className=\"h-6 w-6\" aria-hidden=\"true\" />\n            </a>\n          ))}\n        </div>\n      </div>\n    </footer>\n  );\n}\n"
  },
  {
    "path": "app/lib/icons.tsx",
    "content": "import React from \"react\";\n\nexport function CalendarIcon(props: { className?: string }) {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth={2}\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      {...props}\n    >\n      <rect x={3} y={4} width={18} height={18} rx={2} ry={2} />\n      <path d=\"M16 2v4M8 2v4M3 10h18\" />\n    </svg>\n  );\n}\n\nexport function TrashIcon(props: { className?: string }) {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth={2}\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      {...props}\n    >\n      <path d=\"M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\n    </svg>\n  );\n}\n\nexport function CommentIcon(props: { className?: string }) {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      stroke=\"currentColor\"\n      strokeWidth=\"2\"\n      fill=\"none\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      {...props}\n    >\n      <path d=\"M21 11.5a8.38 8.38 0 01-.9 3.8 8.5 8.5 0 01-7.6 4.7 8.38 8.38 0 01-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 01-.9-3.8 8.5 8.5 0 014.7-7.6 8.38 8.38 0 013.8-.9h.5a8.48 8.48 0 018 8v.5z\"></path>\n    </svg>\n  );\n}\n\nexport function PointIcon(props: { className?: string }) {\n  return (\n    <svg viewBox=\"0 0 24 24\" stroke=\"currentColor\" fill=\"none\" {...props}>\n      <path\n        strokeLinecap=\"round\"\n        strokeLinejoin=\"round\"\n        strokeWidth=\"2\"\n        d=\"M13 10V3L4 14h7v7l9-11h-7z\"\n      ></path>\n    </svg>\n  );\n}\n\nexport function UserIcon(props: { className?: string }) {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      className=\"w-4 h-4 mr-1\"\n      stroke=\"currentColor\"\n      strokeWidth=\"2\"\n      fill=\"none\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      {...props}\n    >\n      <path d=\"M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2\" />\n      <circle cx={12} cy={7} r={4} />\n    </svg>\n  );\n}\n\nexport function SupabaseIcon(props: { className?: string; height: number }) {\n  return (\n    <svg fill=\"none\" viewBox=\"0 0 109 113\" {...props}>\n      <path\n        d=\"M63.708 110.284c-2.86 3.601-8.658 1.628-8.727-2.97l-1.007-67.251h45.22c8.19 0 12.758 9.46 7.665 15.874l-43.151 54.347Z\"\n        fill=\"url(#a)\"\n      />\n      <path\n        d=\"M63.708 110.284c-2.86 3.601-8.658 1.628-8.727-2.97l-1.007-67.251h45.22c8.19 0 12.758 9.46 7.665 15.874l-43.151 54.347Z\"\n        fill=\"url(#b)\"\n        fillOpacity={0.2}\n      />\n      <path\n        d=\"M45.317 2.071c2.86-3.601 8.657-1.628 8.726 2.97l.442 67.251H9.83c-8.19 0-12.759-9.46-7.665-15.875L45.317 2.072Z\"\n        fill=\"#3ECF8E\"\n      />\n      <defs>\n        <linearGradient\n          id=\"a\"\n          x1={53.974}\n          y1={54.974}\n          x2={94.163}\n          y2={71.829}\n          gradientUnits=\"userSpaceOnUse\"\n        >\n          <stop stopColor=\"#249361\" />\n          <stop offset={1} stopColor=\"#3ECF8E\" />\n        </linearGradient>\n        <linearGradient\n          id=\"b\"\n          x1={36.156}\n          y1={30.578}\n          x2={54.484}\n          y2={65.081}\n          gradientUnits=\"userSpaceOnUse\"\n        >\n          <stop />\n          <stop offset={1} stopOpacity={0} />\n        </linearGradient>\n      </defs>\n    </svg>\n  );\n}\n\nexport function ChevronUpIcon(props: {\n  className?: string;\n  strokeWidth?: string;\n}) {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      className=\"w-4 h-4 mr-1\"\n      stroke=\"currentColor\"\n      strokeWidth=\"2\"\n      fill=\"none\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      {...props}\n    >\n      <path d=\"m18 15-6-6-6 6\" />\n    </svg>\n  );\n}\n\nexport function ChevronDownIcon(props: {\n  className?: string;\n  strokeWidth?: string;\n}) {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      className=\"w-4 h-4 mr-1\"\n      stroke=\"currentColor\"\n      strokeWidth=\"2\"\n      fill=\"none\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      {...props}\n    >\n      <path d=\"m6 9 6 6 6-6\" />\n    </svg>\n  );\n}\n"
  },
  {
    "path": "app/lib/loading.tsx",
    "content": "import React from \"react\";\nimport { LightningBoltIcon } from \"@heroicons/react/solid\";\n\nexport function Loading() {\n  return (\n    <div className=\"grid place-items-center h-80\">\n      <LightningBoltIcon className=\"animate-bounce w-12 h-12 text-green-400\" />\n    </div>\n  );\n}\n"
  },
  {
    "path": "app/lib/main-section.tsx",
    "content": "import React from \"react\";\n\nexport function MainSection(props: { children: React.ReactNode }) {\n  return (\n    <main className=\"min-h-screen px-4 py-0 flex-1 flex flex-column max-w-screen-md mx-auto\">\n      {props.children}\n    </main>\n  );\n}\n"
  },
  {
    "path": "app/lib/navigation.tsx",
    "content": "import { Auth } from \"@supabase/ui\";\nimport Link from \"next/link\";\nimport React from \"react\";\nimport { ActiveLink } from \"./active-link\";\nimport { SupabaseIcon } from \"./icons\";\n\nexport function Navigation() {\n  const user = Auth.useUser();\n  return (\n    <header className=\"text-gray-600 body-font max-w-screen-md mx-auto\">\n      <div className=\"container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center\">\n        <Link href=\"/\">\n          <a className=\"flex title-font font-medium items-center text-gray-900 mb-4 md:mb-0\">\n            <SupabaseIcon height={24} />\n            <span className=\"ml-3 text-xl\">supanews</span>\n          </a>\n        </Link>\n        <nav className=\"md:mr-auto md:ml-4 md:py-1 md:pl-4 md:border-l md:border-gray-400\tflex flex-wrap items-center text-base justify-center\">\n          <ActiveLink href=\"/\" activeClassName=\"text-black\">\n            <a className=\"mr-5 hover:text-gray-900 text-gray-400\">feed</a>\n          </ActiveLink>\n          <ActiveLink href=\"/newest\" activeClassName=\"text-black\">\n            <a className=\"mr-5 hover:text-gray-900 text-gray-400\">new</a>\n          </ActiveLink>\n          <ActiveLink href=\"/comments\" activeClassName=\"text-black\">\n            <a className=\"mr-5 hover:text-gray-900 text-gray-400\">comments</a>\n          </ActiveLink>\n          <ActiveLink href=\"/submit\" activeClassName=\"text-black\">\n            <a className=\"mr-5 hover:text-gray-900 text-gray-400\">submit</a>\n          </ActiveLink>\n          <ActiveLink href=\"/about\" activeClassName=\"text-black\">\n            <a className=\"mr-5 hover:text-gray-900 text-gray-400\">about</a>\n          </ActiveLink>\n        </nav>\n        {user.user === null ? (\n          <Link href=\"/login\">\n            <a className=\"inline-flex items-center mt-4 md:mt-0 md:mr-5 text-gray-400 hover:text-gray-900\">\n              login\n            </a>\n          </Link>\n        ) : (\n          <>\n            <ActiveLink href=\"/account\" activeClassName=\"text-black\">\n              <a className=\"inline-flex items-center mt-4 md:mt-0 md:mr-5 text-gray-400 hover:text-gray-900\">\n                account\n              </a>\n            </ActiveLink>\n            <Link href=\"/logout\">\n              <a className=\"inline-flex items-center mt-4 md:mt-0 text-gray-400 hover:text-gray-900\">\n                logout\n              </a>\n            </Link>\n          </>\n        )}\n      </div>\n    </header>\n  );\n}\n"
  },
  {
    "path": "app/lib/noop-uuid.ts",
    "content": "/**\n * Noop UUID for GraphQL operations that require an UUID\n */\nexport const noopUUID = \"00000000-0000-0000-0000-000000000000\";\n"
  },
  {
    "path": "app/lib/supabase.tsx",
    "content": "import React from \"react\";\nimport { createClient, SupabaseClient } from \"@supabase/supabase-js\";\nimport { Auth } from \"@supabase/ui\";\n\nconst SupabaseClientContext = React.createContext<SupabaseClient | null>(null);\n\nexport function SupabaseProvider(props: { children: React.ReactNode }) {\n  const [client] = React.useState(() =>\n    createClient(\n      process.env.NEXT_PUBLIC_SUPABASE_URL ?? \"http://127.0.0.1:6969\",\n      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY ?? \"noop\"\n    )\n  );\n\n  return (\n    <SupabaseClientContext.Provider value={client}>\n      <Auth.UserContextProvider supabaseClient={client}>\n        {props.children}\n      </Auth.UserContextProvider>\n    </SupabaseClientContext.Provider>\n  );\n}\n\nexport function useSupabaseClient(): SupabaseClient {\n  const client = React.useContext(SupabaseClientContext);\n  if (client === null) {\n    throw new Error(\n      \"Supabase client not provided via context.\\n\" +\n        \"Did you forget to wrap your component tree with SupabaseProvider?\"\n    );\n  }\n  return client;\n}\n"
  },
  {
    "path": "app/lib/time-ago.ts",
    "content": "import TimeAgo from \"javascript-time-ago\";\nimport en from \"javascript-time-ago/locale/en.json\";\n\nTimeAgo.addDefaultLocale(en);\n\nexport const timeAgo = new TimeAgo(\"en-US\");\n"
  },
  {
    "path": "app/lib/urql.tsx",
    "content": "import React from \"react\";\nimport { createClient, Provider } from \"urql\";\nimport { useSupabaseClient } from \"./supabase\";\n\nexport function UrqlProvider(props: { children: React.ReactNode }) {\n  const supabaseClient = useSupabaseClient();\n\n  function getHeaders(): Record<string, string> {\n    const headers: Record<string, string> = {\n      apikey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,\n    };\n    const authorization = supabaseClient.auth.session()?.access_token;\n\n    if (authorization) {\n      headers[\"authorization\"] = `Bearer ${authorization}`;\n    }\n\n    return headers;\n  }\n\n  const [client] = React.useState(function createUrqlClient() {\n    return createClient({\n      url: `${process.env.NEXT_PUBLIC_SUPABASE_URL!}/graphql/v1`,\n      fetchOptions: function createFetchOptions() {\n        return { headers: getHeaders() };\n      },\n    });\n  });\n  return <Provider value={client}>{props.children}</Provider>;\n}\n"
  },
  {
    "path": "app/lib/use-paginated-query.ts",
    "content": "import React from \"react\";\nimport { useQuery, UseQueryArgs, UseQueryResponse } from \"urql\";\n\n/**\n * Urql only supports \"merge/infinite\" pagination by adoptinh the GraphCache (a global normalized cache),\n * which certainly is an overkill for this demo.\n *\n * This hook wraps `useQuery` from urql and adds a light-weight merge previous and current result API.\n */\nexport function usePaginatedQuery<Data = any, Variables = object>(\n  args: UseQueryArgs<Variables, Data> & {\n    /**\n     * Merge the old result with the new result.\n     */\n    mergeResult: (oldData: Data, newData: Data) => Data;\n  }\n): UseQueryResponse<Data, Variables> {\n  const [query, queryFn] = useQuery(args);\n\n  const { data, ...rest } = query;\n\n  const mergeRef = React.useRef({ current: data, last: data });\n\n  if (\n    data &&\n    mergeRef.current.current &&\n    query.data !== mergeRef.current.last\n  ) {\n    mergeRef.current.current = args.mergeResult(mergeRef.current.current, data);\n  }\n\n  if (data != null && mergeRef.current.current == null) {\n    mergeRef.current.current = data;\n  }\n\n  mergeRef.current.last = query.data;\n\n  return [\n    {\n      ...rest,\n      data: mergeRef.current.current,\n    },\n    queryFn,\n  ];\n}\n"
  },
  {
    "path": "app/next-env.d.ts",
    "content": "/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\n\n// NOTE: This file should not be edited\n// see https://nextjs.org/docs/basic-features/typescript for more information.\n"
  },
  {
    "path": "app/next.config.js",
    "content": "/** @type {import('next').NextConfig} */\nconst nextConfig = {\n  reactStrictMode: true,\n};\n\nmodule.exports = nextConfig;\n"
  },
  {
    "path": "app/package.json",
    "content": "{\n  \"name\": \"app\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"build\": \"next build\",\n    \"start\": \"next start\",\n    \"lint\": \"next lint\"\n  },\n  \"dependencies\": {\n    \"@graphql-yoga/render-graphiql\": \"2.13.12\",\n    \"@heroicons/react\": \"1.0.6\",\n    \"@supabase/supabase-js\": \"1.35.7\",\n    \"@supabase/ui\": \"0.36.5\",\n    \"autoprefixer\": \"10.4.12\",\n    \"graphql\": \"16.6.0\",\n    \"javascript-time-ago\": \"2.5.7\",\n    \"next\": \"12.3.1\",\n    \"postcss\": \"8.4.17\",\n    \"react\": \"17.0.2\",\n    \"react-dom\": \"17.0.2\",\n    \"tailwindcss\": \"3.1.8\",\n    \"urql\": \"2.2.3\"\n  },\n  \"devDependencies\": {\n    \"@types/javascript-time-ago\": \"2.0.3\",\n    \"@types/node\": \"17.0.45\",\n    \"@types/react\": \"17.0.50\",\n    \"eslint\": \"8.24.0\",\n    \"eslint-config-next\": \"12.3.1\",\n    \"typescript\": \"4.6.2\"\n  }\n}\n"
  },
  {
    "path": "app/pages/_app.tsx",
    "content": "import \"../styles/globals.css\";\nimport type { AppProps } from \"next/app\";\nimport { UrqlProvider } from \"../lib/urql\";\nimport { SupabaseProvider } from \"../lib/supabase\";\nimport { Navigation } from \"../lib/navigation\";\nimport { Footer } from \"../lib/footer\";\n\nfunction MyApp({ Component, pageProps }: AppProps) {\n  return (\n    <SupabaseProvider>\n      <UrqlProvider>\n        <Navigation />\n        <Component {...pageProps} />\n        <Footer />\n      </UrqlProvider>\n    </SupabaseProvider>\n  );\n}\n\nexport default MyApp;\n"
  },
  {
    "path": "app/pages/about.tsx",
    "content": "import React from \"react\";\nimport type { NextPage } from \"next\";\nimport Head from \"next/head\";\nimport Link from \"next/link\";\n\nimport {\n  CodeIcon,\n  CogIcon,\n  CollectionIcon,\n  ColorSwatchIcon,\n  DatabaseIcon,\n  GlobeAltIcon,\n  LightningBoltIcon,\n  ShieldCheckIcon,\n  TemplateIcon,\n} from \"@heroicons/react/outline\";\n\nimport { Container } from \"../lib/container\";\n\nconst About: NextPage = () => {\n  const features = [\n    {\n      name: \"PG GraphQL\",\n      description: \"Adds GraphQL support to your PostgreSQL database.\",\n      icon: DatabaseIcon,\n      href: \"https://supabase.github.io/pg_graphql/\",\n    },\n    {\n      name: \"GraphQL Code Generator\",\n      description:\n        \"Generate code from your GraphQL schema and operations with a simple CLI.\",\n      icon: CodeIcon,\n      href: \"https://www.graphql-code-generator.com\",\n    },\n    {\n      name: \"GraphQL Config\",\n      description:\n        \"One configuration for development environment with your GraphQL Schema.\",\n      icon: CogIcon,\n      href: \"https://www.graphql-config.com\",\n    },\n    {\n      name: \"Supabase\",\n      description:\n        \"Supabase has all the backend services you need to build a product with GraphQL.\",\n      icon: LightningBoltIcon,\n      href: \"https://www.supabase.com\",\n    },\n    {\n      name: \"Supabase Auth\",\n      description:\n        \"Supabase Auth provides user management with row level security.\",\n      icon: ShieldCheckIcon,\n      href: \"https://supabase.com/auth\",\n    },\n    {\n      name: \"Supabase UI\",\n      description:\n        \"An open-source UI component library inspired by Tailwind and AntDesign.\",\n      icon: CollectionIcon,\n      href: \"https://ui.supabase.io\",\n    },\n    {\n      name: \"GraphiQL\",\n      description:\n        \"GraphiQL is an in-browser IDE for writing, validating, and testing GraphQL queries.\",\n      icon: TemplateIcon,\n      href: \"https://www.graphql-yoga.com/docs/features/graphiql\",\n    },\n    {\n      name: \"urql\",\n      description:\n        \"urql is a highly customizable and versatile GraphQL client.\",\n      icon: GlobeAltIcon,\n      href: \"https://formidable.com/open-source/urql/\",\n    },\n    {\n      name: \"Tailwind CSS\",\n      description:\n        \"A utility-first CSS framework to rapidly build modern websites.\",\n      icon: ColorSwatchIcon,\n      href: \"https://tailwindcss.com\",\n    },\n  ];\n\n  const faqs = [\n    {\n      id: 1,\n      question: \"GraphQL Query and Mutation Operations\",\n      answer:\n        \"The data on this page is fetched from the GraphQL layer auto-generated via pg_graphql.\",\n    },\n    {\n      id: 2,\n      question: \"Pagination\",\n      answer:\n        \"pg_graphql generates standardized pagination types and fields as defined by the GraphQL Cursor Connections Specification.\",\n    },\n    {\n      id: 3,\n      question: \"GraphQL Code Generation\",\n      answer:\n        \"GraphQL Code Generator introspects your GraphQL schema and operations and generates the types for full backend to frontend type-safety.\",\n    },\n    {\n      id: 4,\n      question: \"GraphQL Fragments\",\n      answer:\n        \"Components use GraphQL fragments to share logic between multiple queries and mutations.\",\n    },\n    {\n      id: 5,\n      question: \"pg_graphql Postgres Extension\",\n      answer:\n        \"pg_graphql generates a GraphQL API based on the Postgres schema.\",\n    },\n    {\n      id: 6,\n      question: \"Total Counts\",\n      answer:\n        \"Use pg_graphql's totalCount comment-based GraphQL Directive to count of the rows that match the query's filters.\",\n    },\n    {\n      id: 7,\n      question: \"Schema Inflection\",\n      answer:\n        \"Use pg_graphql's inflect_names comment-based GraphQL Directive to convert from snake_case to PascalCase for type names, and snake_case to camelCase for field names to match Javascript conventions when generating your GraphQL schema.\",\n    },\n    {\n      id: 8,\n      question: \"Supabase Postgres\",\n      answer:\n        \"Every Supabase project is a dedicated PostgreSQL database, trusted by millions of developers. It provide some of the most common extensions with a one-click install.\",\n    },\n    {\n      id: 9,\n      question: \"Supabase Auth\",\n      answer:\n        \"Authorization cannot get any easier. Every Supabase project comes with a complete User Management system that works without any additional tools.\",\n    },\n    {\n      id: 10,\n      question: \"Postgres RLS\",\n      answer:\n        \"Row level security on the Postgres layer ensures that viewers can only access what they are allowed to access and can only create records when authenticated.\",\n    },\n    {\n      id: 11,\n      question: \"Postgres Functions\",\n      answer:\n        \"Built-in support for SQL functions. These functions live inside your database, and they can be used with the Supabase API or invoked by a Postgres Trigger.\",\n    },\n    {\n      id: 12,\n      question: \"Postgres Triggers\",\n      answer:\n        \"Execute any SQL code after inserting, updating, or deleting data. We recalculate the feed scores by invoking a function each time someone votes (or change their vote).\",\n    },\n  ];\n\n  return (\n    <Container>\n      <Head>\n        <title>supanews | About</title>\n        <meta\n          name=\"description\"\n          content=\"Everything you need to develop a GraphQL app.\"\n        />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n      </Head>\n      <div className=\"relative bg-white py-4 sm:py-8 lg:py-12\">\n        <div className=\"mx-auto max-w-md px-4 text-center sm:max-w-3xl sm:px-6 lg:px-8 lg:max-w-7xl\">\n          <h2 className=\"text-base font-semibold tracking-wider text-green-600 uppercase\">\n            GraphQL + Postgres + Tooling\n          </h2>\n          <p className=\"mt-2 text-3xl font-extrabold text-gray-900 tracking-tight sm:text-4xl\">\n            Everything you need to develop a GraphQL app\n          </p>\n          <p className=\"mt-5 max-w-prose mx-auto text-xl text-gray-500\">\n            Build your next GraphQL powered application like this one ... faster\n            and easier with open source tools from{\" \"}\n            <a className=\"text-gray-800\" href=\"https://www.supabase.com\">\n              Supabase\n            </a>\n            ,{\" \"}\n            <a className=\"text-gray-800\" href=\"https://www.the-guild.dev\">\n              The Guild\n            </a>{\" \"}\n            and more.\n          </p>\n          <div className=\"mt-12\">\n            <div className=\"grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3\">\n              {features.map((feature) => (\n                <div key={feature.name} className=\"pt-6\">\n                  <div className=\"flow-root bg-gray-50 rounded-lg px-6 pb-8\">\n                    <Link href={feature.href}>\n                      <a>\n                        <div className=\"-mt-6\">\n                          <div>\n                            <span className=\"inline-flex items-center justify-center p-3 bg-gradient-to-r from-teal-500 to-green-600 rounded-md shadow-lg\">\n                              <feature.icon\n                                className=\"h-6 w-6 text-white\"\n                                aria-hidden=\"true\"\n                              />\n                            </span>\n                          </div>\n                          <h3 className=\"mt-8 text-lg font-medium text-gray-900 tracking-tight\">\n                            {feature.name}\n                          </h3>\n                          <p className=\"mt-5 text-base text-gray-500\">\n                            {feature.description}\n                          </p>\n                        </div>\n                      </a>\n                    </Link>\n                  </div>\n                </div>\n              ))}\n            </div>\n          </div>\n        </div>\n\n        <div className=\"bg-white\">\n          <div className=\"max-w-7xl mx-auto py-16 px-4 sm:py-24 sm:px-6 lg:px-8\">\n            <h2 className=\"text-3xl font-extrabold text-gray-900 text-center\">\n              Technologies Used\n            </h2>\n            <div className=\"mt-12\">\n              <dl className=\"space-y-10 md:space-y-0 md:grid md:grid-cols-2 md:gap-x-8 md:gap-y-12 lg:grid-cols-3\">\n                {faqs.map((faq) => (\n                  <div key={faq.id}>\n                    <dt className=\"text-lg leading-6 font-medium text-gray-900\">\n                      {faq.question}\n                    </dt>\n                    <dd className=\"mt-2 text-base text-gray-500\">\n                      {faq.answer}\n                    </dd>\n                  </div>\n                ))}\n              </dl>\n            </div>\n          </div>\n        </div>\n      </div>\n    </Container>\n  );\n};\n\nexport default About;\n"
  },
  {
    "path": "app/pages/account.tsx",
    "content": "import React from \"react\";\nimport { NextPage } from \"next\";\nimport { useRouter } from \"next/router\";\nimport { Auth, Button } from \"@supabase/ui\";\nimport { CombinedError, useMutation, useQuery } from \"urql\";\nimport { Input } from \"@supabase/ui\";\nimport { DocumentType, gql } from \"../gql\";\nimport { Container } from \"../lib/container\";\nimport { Loading } from \"../lib/loading\";\nimport { MainSection } from \"../lib/main-section\";\n\nconst UserProfileQuery = gql(/* GraphQL */ `\n  query UserProfileQuery($profileId: UUID!) {\n    profileCollection(filter: { id: { eq: $profileId } }) {\n      edges {\n        node {\n          ...AccountProfileFragment\n        }\n      }\n    }\n  }\n`);\n\nconst Account: NextPage = () => {\n  const session = Auth.useUser();\n  const [profileQuery] = useQuery({\n    query: UserProfileQuery,\n    variables: { profileId: session.user?.id },\n    pause: session.user === null,\n  });\n  const router = useRouter();\n\n  const profile = profileQuery.data?.profileCollection?.edges?.[0].node;\n\n  React.useEffect(() => {\n    if (session.user === null || (profileQuery.data && profile === null)) {\n      router.replace(\"/login\");\n    }\n  }, [session.user, profile, profileQuery.data]);\n\n  if (profile) {\n    return <AccountForm profile={profile} />;\n  }\n\n  return (\n    <div className=\"w-full\">{profileQuery.fetching ? <Loading /> : null}</div>\n  );\n\n  return null;\n};\n\nconst ProfileFragment = gql(/* GraphQL */ `\n  fragment AccountProfileFragment on Profile {\n    id\n    username\n    website\n    bio\n  }\n`);\n\nconst UpdateProfileMutation = gql(/* GraphQL */ `\n  mutation updateProfile(\n    $userId: UUID!\n    $newUsername: String!\n    $newWebsite: String!\n    $newBio: String!\n  ) {\n    updateProfileCollection(\n      filter: { id: { eq: $userId } }\n      set: { username: $newUsername, website: $newWebsite, bio: $newBio }\n    ) {\n      affectedCount\n      records {\n        id\n        username\n        website\n      }\n    }\n  }\n`);\n\nfunction extractExpectedGraphQLErrors(\n  error: CombinedError | undefined\n): null | string {\n  if (error === undefined) {\n    return null;\n  }\n\n  for (const graphQLError of error.graphQLErrors) {\n    if (graphQLError.message.includes(\"usernamelength\")) {\n      return \"Username must have a minimum length of 3 characters.\";\n    }\n    if (graphQLError.message.includes(\"Profile_username_key\")) {\n      return \"The name is already taken.\";\n    }\n  }\n\n  return null;\n}\n\nfunction AccountForm(props: { profile: DocumentType<typeof ProfileFragment> }) {\n  const [username, setUsername] = React.useState(props.profile.username ?? \"\");\n  const [website, setWebsite] = React.useState(props.profile.website ?? \"\");\n  const [bio, setBio] = React.useState(props.profile.bio ?? \"\");\n\n  const [updateProfileMutation, updateProfile] = useMutation(\n    UpdateProfileMutation\n  );\n\n  const errorState = extractExpectedGraphQLErrors(updateProfileMutation.error);\n\n  return (\n    <Container>\n      <MainSection>\n        <section className=\"container px-5 py-24 mx-auto max-w-md\">\n          <h1 className=\"font-semibold text-xl tracking-tight mb-5\">Account</h1>\n          <div className=\"mb-4\">\n            <label htmlFor=\"username\" className=\"block mb-2\">\n              Name\n            </label>\n            <Input\n              id=\"username\"\n              type=\"text\"\n              value={username}\n              onChange={(e) => setUsername(e.target.value)}\n            />\n          </div>\n          <div className=\"mb-4\">\n            <label htmlFor=\"website\" className=\"block mb-2\">\n              Website\n            </label>\n            <Input\n              id=\"website\"\n              type=\"website\"\n              value={website}\n              onChange={(e) => setWebsite(e.target.value)}\n            />\n          </div>\n\n          <div className=\"mb-4\">\n            <label htmlFor=\"bio\" className=\"block mb-2\">\n              Bio\n            </label>\n            <textarea\n              id=\"bio\"\n              className=\"w-full border-solid  border-2 border-gray-100 rounded-sm\"\n              value={bio}\n              onChange={(e) => setBio(e.target.value)}\n            />\n          </div>\n\n          <div>\n            <Button\n              onClick={() =>\n                updateProfile({\n                  userId: props.profile.id,\n                  newUsername: username,\n                  newWebsite: website,\n                  newBio: bio,\n                })\n              }\n              disabled={updateProfileMutation.fetching}\n            >\n              {updateProfileMutation.fetching ? \"Loading ...\" : \"Update\"}\n            </Button>\n          </div>\n\n          <div>{errorState}</div>\n        </section>\n      </MainSection>\n    </Container>\n  );\n}\n\nexport default Account;\n"
  },
  {
    "path": "app/pages/api/graphiql.ts",
    "content": "import { renderGraphiQL } from \"@graphql-yoga/render-graphiql\";\nimport { NextApiRequest, NextApiResponse } from \"next\";\n\nexport const config = {\n  api: {\n    bodyParser: false,\n    externalResolver: true,\n  },\n};\n\nexport default async (req: NextApiRequest, res: NextApiResponse) => {\n  res.status(200).end(\n    renderGraphiQL({\n      endpoint: process.env.NEXT_PUBLIC_SUPABASE_URL + \"/graphql/v1\",\n      headers: JSON.stringify({\n        apikey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,\n      }),\n      credentials: \"omit\",\n    })\n  );\n};\n"
  },
  {
    "path": "app/pages/comments.tsx",
    "content": "import { Button } from \"@supabase/ui\";\nimport type { NextPage } from \"next\";\nimport Head from \"next/head\";\nimport Image from \"next/image\";\nimport React from \"react\";\nimport { useQuery } from \"urql\";\nimport { gql } from \"../gql\";\nimport { CommentItem } from \"../lib/comment-item\";\nimport { Container } from \"../lib/container\";\nimport { Loading } from \"../lib/loading\";\nimport { MainSection } from \"../lib/main-section\";\nimport { usePaginatedQuery } from \"../lib/use-paginated-query\";\n\nconst CommentsRouteQuery = gql(/* GraphQL */ `\n  query CommentsRouteQuery($after: Cursor) {\n    comments: commentCollection(\n      orderBy: [{ createdAt: DescNullsFirst }]\n      first: 15\n      after: $after\n    ) {\n      pageInfo {\n        hasNextPage\n        endCursor\n      }\n      edges {\n        cursor\n        node {\n          id\n          ...CommentItem_CommentFragment\n        }\n      }\n    }\n  }\n`);\n\nconst Comments: NextPage = () => {\n  const [lastCursor, setLastCursor] = React.useState<string | undefined>(\n    undefined\n  );\n  const [commentsQuery] = usePaginatedQuery({\n    query: CommentsRouteQuery,\n    variables: {\n      after: lastCursor,\n    },\n    mergeResult(oldData, newData) {\n      return {\n        ...oldData,\n        ...newData,\n        comments: {\n          ...oldData.comments!,\n          ...newData.comments!,\n          edges: [...oldData.comments!.edges, ...newData.comments!.edges],\n        },\n      };\n    },\n  });\n\n  return (\n    <Container>\n      <MainSection>\n        <Head>\n          <title>supanews | Comments</title>\n          <meta name=\"description\" content=\"New comments\" />\n          <link rel=\"icon\" href=\"/favicon.ico\" />\n        </Head>\n\n        <section className=\"text-gray-600 body-font overflow-hidden w-full\">\n          <div className=\"container px-3 py-24 mx-auto\">\n            <div className=\"-my-8 divide-y-2 divide-gray-100\">\n              {commentsQuery?.data?.comments?.edges.map((edge) => (\n                <CommentItem comment={edge.node!} key={edge.cursor} />\n              ))}\n            </div>\n            {commentsQuery.fetching ? <Loading /> : null}\n          </div>\n          {commentsQuery.data?.comments?.pageInfo.hasNextPage ? (\n            <div className=\"flex justify-center content-center\">\n              <Button\n                onClick={() =>\n                  setLastCursor(\n                    commentsQuery.data?.comments?.pageInfo.endCursor ??\n                      undefined\n                  )\n                }\n              >\n                Load more.\n              </Button>\n            </div>\n          ) : null}\n        </section>\n      </MainSection>\n    </Container>\n  );\n};\n\nexport default Comments;\n"
  },
  {
    "path": "app/pages/index.tsx",
    "content": "import { Auth, Button } from \"@supabase/ui\";\nimport type { NextPage } from \"next\";\nimport Head from \"next/head\";\nimport React from \"react\";\nimport { gql } from \"../gql\";\nimport { Container } from \"../lib/container\";\nimport { FeedItem } from \"../lib/feed-item\";\nimport { Loading } from \"../lib/loading\";\nimport { MainSection } from \"../lib/main-section\";\nimport { noopUUID } from \"../lib/noop-uuid\";\nimport { usePaginatedQuery } from \"../lib/use-paginated-query\";\n\nconst IndexRouteQuery = gql(/* GraphQL */ `\n  query IndexRouteQuery($profileId: UUID!, $after: Cursor) {\n    feed: postCollection(\n      orderBy: [{ voteRank: AscNullsFirst }]\n      first: 15\n      after: $after\n    ) {\n      pageInfo {\n        hasNextPage\n        endCursor\n      }\n      edges {\n        cursor\n        node {\n          id\n          ...FeedItem_PostFragment\n        }\n      }\n    }\n  }\n`);\n\nconst Home: NextPage = () => {\n  const { user } = Auth.useUser();\n  const [lastCursor, setLastCursor] = React.useState<string | undefined>(\n    undefined\n  );\n  const [indexQuery] = usePaginatedQuery({\n    query: IndexRouteQuery,\n    variables: {\n      profileId: user?.id ?? noopUUID,\n      after: lastCursor,\n    },\n    mergeResult(oldData, newData) {\n      return {\n        ...oldData,\n        ...newData,\n        feed: {\n          ...oldData.feed!,\n          ...newData.feed!,\n          edges: [...oldData.feed!.edges, ...newData.feed!.edges],\n        },\n      };\n    },\n  });\n\n  return (\n    <Container>\n      <Head>\n        <title>supanews | Feed</title>\n        <meta name=\"description\" content=\"What is hot?\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n      </Head>\n\n      <MainSection>\n        <section className=\"text-gray-600 body-font overflow-hidden w-full\">\n          <div className=\"container px-3 py-24 mx-auto\">\n            <div className=\"-my-8\">\n              {indexQuery?.data?.feed?.edges.map((edge) => (\n                <FeedItem post={edge.node!} key={edge.cursor} />\n              ))}\n              {indexQuery.fetching ? <Loading /> : null}\n            </div>\n          </div>\n          {indexQuery.data?.feed?.pageInfo.hasNextPage ? (\n            <div className=\"flex justify-center content-center\">\n              <Button\n                onClick={() => {\n                  setLastCursor(\n                    indexQuery.data?.feed?.pageInfo.endCursor ?? undefined\n                  );\n                }}\n              >\n                Load more.\n              </Button>\n            </div>\n          ) : null}\n        </section>\n      </MainSection>\n    </Container>\n  );\n};\n\nexport default Home;\n"
  },
  {
    "path": "app/pages/item/[postId].tsx",
    "content": "import { Auth, Button } from \"@supabase/ui\";\nimport React from \"react\";\nimport type { NextPage } from \"next\";\nimport Head from \"next/head\";\nimport { useRouter } from \"next/router\";\nimport { useMutation, useQuery } from \"urql\";\nimport { gql } from \"../../gql\";\nimport { CommentItem } from \"../../lib/comment-item\";\nimport { Container } from \"../../lib/container\";\nimport { FeedItem } from \"../../lib/feed-item\";\nimport { Loading } from \"../../lib/loading\";\nimport { MainSection } from \"../../lib/main-section\";\nimport { noopUUID } from \"../../lib/noop-uuid\";\n\nconst ItemRouteQuery = gql(/* GraphQL */ `\n  query ItemRouteQuery($postId: BigInt!, $profileId: UUID!) {\n    post: postCollection(filter: { id: { eq: $postId } }, first: 1) {\n      edges {\n        cursor\n        node {\n          id\n          ...FeedItem_PostFragment\n          comments: commentCollection(\n            first: 15\n            orderBy: [{ createdAt: DescNullsLast }]\n          ) {\n            edges {\n              cursor\n              node {\n                id\n                ...CommentItem_CommentFragment\n              }\n            }\n            pageInfo {\n              hasNextPage\n            }\n          }\n        }\n      }\n    }\n  }\n`);\n\nconst PostCommentMutation = gql(/* GraphQL */ `\n  mutation postComment($profileId: UUID!, $message: String!, $postId: BigInt) {\n    insertIntoCommentCollection(\n      objects: [{ profileId: $profileId, message: $message, postId: $postId }]\n    ) {\n      affectedCount\n    }\n  }\n`);\n\nfunction PostCommentForm(props: { postId: string }) {\n  const [postCommentMutation, postComment] = useMutation(PostCommentMutation);\n  const [message, setMessage] = React.useState(\"\");\n  const { user } = Auth.useUser();\n  const router = useRouter();\n\n  React.useEffect(() => {\n    if (postCommentMutation.data) {\n      router.reload();\n    }\n  }, [postCommentMutation.data]);\n\n  return (\n    <form>\n      <div className=\"mb-2 font-bold\">Write comment</div>\n      <textarea\n        className=\"w-full border-solid  border-2 border-gray-100 rounded-sm\"\n        value={message}\n        onChange={(ev) => setMessage(ev.target.value)}\n      />\n      <Button\n        onClick={() => {\n          postComment({\n            profileId: user?.id!,\n            message,\n            postId: props.postId,\n          });\n        }}\n      >\n        add comment\n      </Button>\n    </form>\n  );\n}\n\nconst Item: NextPage = () => {\n  const { user } = Auth.useUser();\n  const router = useRouter();\n  const { postId } = router.query;\n  const [itemRouteQuery] = useQuery({\n    query: ItemRouteQuery,\n    variables: {\n      postId,\n      profileId: user?.id ?? noopUUID,\n    },\n  });\n\n  const post = itemRouteQuery?.data?.post?.edges?.[0];\n\n  return (\n    <Container>\n      <MainSection>\n        <div className=\"h-screen w-full\">\n          {itemRouteQuery.fetching ? <Loading /> : null}\n\n          {post?.node == null ? null : (\n            <>\n              <Head>\n                <title>supanews | {post.node?.title}</title>\n                <meta name=\"description\" content={post.node?.url} />\n              </Head>\n              <section className=\"text-gray-600 body-font overflow-hidden w-full\">\n                <div className=\"container px-5 py-24 mx-auto\">\n                  <FeedItem post={post.node} key={post.cursor} />\n\n                  <div className=\"max-w-md\">\n                    {user && <PostCommentForm postId={post.node.id} />}\n\n                    <div className=\"mt-10\">\n                      {post.node?.comments?.edges.map((edge) => (\n                        <CommentItem comment={edge.node!} key={edge.cursor} />\n                      ))}\n                    </div>\n                  </div>\n                </div>\n              </section>\n            </>\n          )}\n        </div>\n      </MainSection>\n    </Container>\n  );\n};\n\nexport default Item;\n"
  },
  {
    "path": "app/pages/login.tsx",
    "content": "import React from \"react\";\nimport type { NextPage } from \"next\";\nimport Head from \"next/head\";\nimport { Auth } from \"@supabase/ui\";\nimport { useSupabaseClient } from \"../lib/supabase\";\nimport { useRouter } from \"next/router\";\nimport { Container } from \"../lib/container\";\nimport { MainSection } from \"../lib/main-section\";\n\nconst LogIn: NextPage = () => {\n  const { user } = Auth.useUser();\n  const supabaseClient = useSupabaseClient();\n  const router = useRouter();\n\n  React.useEffect(() => {\n    if (user !== null) {\n      router.replace(\"/account\");\n    }\n  }, []);\n\n  if (user) {\n    return null;\n  }\n\n  return (\n    <Container>\n      <Head>\n        <title>supanews | Login</title>\n        <meta name=\"description\" content=\"Sign in to submit posts and vote.\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n      </Head>\n      <MainSection>\n        <div className=\"m-width-md mx-auto\">\n          <h1 className=\"font-semibold text-xl tracking-tight mb-5\">Login</h1>\n\n          <Auth supabaseClient={supabaseClient} providers={[\"github\"]} />\n        </div>\n      </MainSection>\n    </Container>\n  );\n};\n\nexport default LogIn;\n"
  },
  {
    "path": "app/pages/logout.tsx",
    "content": "import React from \"react\";\nimport type { NextPage } from \"next\";\nimport { Auth } from \"@supabase/ui\";\nimport { useSupabaseClient } from \"../lib/supabase\";\nimport { useRouter } from \"next/router\";\n\nconst LogOut: NextPage = () => {\n  const supabaseClient = useSupabaseClient();\n  const router = useRouter();\n\n  React.useEffect(() => {\n    supabaseClient.auth.signOut().then(() => router.replace(\"/\"));\n  }, []);\n  return null;\n};\n\nexport default LogOut;\n"
  },
  {
    "path": "app/pages/newest.tsx",
    "content": "import { Auth, Button } from \"@supabase/ui\";\nimport type { NextPage } from \"next\";\nimport Head from \"next/head\";\nimport React from \"react\";\nimport { gql } from \"../gql\";\nimport { Container } from \"../lib/container\";\nimport { FeedItem } from \"../lib/feed-item\";\nimport { Loading } from \"../lib/loading\";\nimport { MainSection } from \"../lib/main-section\";\nimport { noopUUID } from \"../lib/noop-uuid\";\nimport { usePaginatedQuery } from \"../lib/use-paginated-query\";\n\nconst NewestRouteQuery = gql(/* GraphQL */ `\n  query NewestRouteQuery($profileId: UUID!, $after: Cursor) {\n    feed: postCollection(\n      orderBy: [{ createdAt: DescNullsFirst }]\n      first: 15\n      after: $after\n    ) {\n      pageInfo {\n        hasNextPage\n        endCursor\n      }\n      edges {\n        cursor\n        node {\n          id\n          ...FeedItem_PostFragment\n        }\n      }\n    }\n  }\n`);\n\nconst Newest: NextPage = () => {\n  const { user } = Auth.useUser();\n  const [lastCursor, setLastCursor] = React.useState<string | undefined>(\n    undefined\n  );\n  const [newestQuery] = usePaginatedQuery({\n    query: NewestRouteQuery,\n    variables: {\n      profileId: user?.id ?? noopUUID,\n      after: lastCursor,\n    },\n    mergeResult(oldData, newData) {\n      return {\n        ...oldData,\n        ...newData,\n        feed: {\n          ...oldData.feed!,\n          ...newData.feed!,\n          edges: [...oldData.feed!.edges, ...newData.feed!.edges],\n        },\n      };\n    },\n  });\n\n  return (\n    <Container>\n      <Head>\n        <title>supanews | Newest</title>\n        <meta name=\"description\" content=\"What is hot?\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n      </Head>\n\n      <MainSection>\n        <section className=\"text-gray-600 body-font overflow-hidden w-full\">\n          <div className=\"container px-5 py-24 mx-auto\">\n            <div className=\"-my-8\">\n              {newestQuery?.data?.feed?.edges.map((edge) => (\n                <FeedItem post={edge.node!} key={edge.cursor} />\n              ))}\n            </div>\n            {newestQuery.fetching ? <Loading /> : null}\n          </div>\n          {newestQuery.data?.feed?.pageInfo.hasNextPage ? (\n            <div className=\"flex justify-center content-center\">\n              <Button\n                onClick={() => {\n                  setLastCursor(\n                    newestQuery.data?.feed?.pageInfo.endCursor ?? undefined\n                  );\n                }}\n              >\n                Load more.\n              </Button>\n            </div>\n          ) : null}\n        </section>\n      </MainSection>\n    </Container>\n  );\n};\n\nexport default Newest;\n"
  },
  {
    "path": "app/pages/profile/[profileId].tsx",
    "content": "import type { NextPage } from \"next\";\nimport Head from \"next/head\";\nimport { useRouter } from \"next/router\";\nimport { useQuery } from \"urql\";\nimport { gql } from \"../../gql\";\nimport { CommentItem } from \"../../lib/comment-item\";\nimport { Container } from \"../../lib/container\";\nimport { FeedItem } from \"../../lib/feed-item\";\nimport { Loading } from \"../../lib/loading\";\nimport { MainSection } from \"../../lib/main-section\";\n\nconst ProfileRouteQuery = gql(/* GraphQL */ `\n  query ProfileRouteQuery($profileId: UUID!) {\n    profileCollection(filter: { id: { eq: $profileId } }) {\n      edges {\n        node {\n          id\n          username\n          bio\n          avatarUrl\n          website\n          latestPosts: postCollection(\n            orderBy: [{ createdAt: DescNullsFirst }]\n            first: 15\n          ) {\n            pageInfo {\n              hasNextPage\n            }\n            edges {\n              cursor\n              node {\n                id\n                ...FeedItem_PostFragment\n              }\n            }\n          }\n          latestComments: commentCollection(\n            orderBy: [{ createdAt: DescNullsFirst }]\n            first: 15\n          ) {\n            pageInfo {\n              hasNextPage\n            }\n            edges {\n              cursor\n              node {\n                id\n                ...CommentItem_CommentFragment\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n`);\n\nconst Profile: NextPage = () => {\n  const router = useRouter();\n  const { profileId } = router.query;\n  const [profileQuery] = useQuery({\n    query: ProfileRouteQuery,\n    variables: {\n      profileId,\n    },\n  });\n\n  const profile = profileQuery.data?.profileCollection?.edges?.[0].node;\n\n  return (\n    <Container>\n      <Head>\n        <title>supanews | {profile?.username}</title>\n        <meta name=\"description\" content=\"What is hot?\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n      </Head>\n\n      <MainSection>\n        <div className=\"w-full\">\n          {profileQuery.fetching ? <Loading /> : null}\n          {profile == null ? null : (\n            <section className=\"text-gray-600 body-font overflow-hidden\">\n              <div className=\"container px-5 py-24 pt-10 mx-auto\">\n                <h1 className=\"font-semibold text-xl tracking-tight mb-5\">\n                  Profile\n                </h1>{\" \"}\n                <div>\n                  <span className=\"inline-block font-bold pr-2 w-20\">User</span>{\" \"}\n                  {profile.username}\n                </div>\n                <div>\n                  <span className=\"inline-block font-bold pr-2 w-20\">\n                    Avatar\n                  </span>{\" \"}\n                  <img\n                    className=\"inline-block h-6 w-6 rounded-full\"\n                    src={profile.avatarUrl ?? \"\"}\n                  />\n                </div>\n                <div>\n                  <span className=\"inline-block font-bold pr-2 w-20\">\n                    Website\n                  </span>{\" \"}\n                  {profile.website}\n                </div>\n                <div className=\"mb-10\">\n                  <span className=\"inline-block font-bold pr-2 w-20\">Bio</span>{\" \"}\n                  {profile.bio}\n                </div>\n                <h1 className=\"font-semibold text-xl tracking-tight mb-5\">\n                  Latest Posts\n                </h1>\n                <div>\n                  {profile.latestPosts?.edges.map((edge) => (\n                    <FeedItem post={edge.node!} key={edge.cursor} />\n                  ))}\n                </div>\n                <h1 className=\"font-semibold text-xl tracking-tight mb-5\">\n                  Latest Comments\n                </h1>\n                {profile.latestComments?.edges.map((edge) => (\n                  <CommentItem comment={edge.node!} key={edge.cursor} />\n                ))}\n              </div>\n            </section>\n          )}\n        </div>\n      </MainSection>\n    </Container>\n  );\n};\n\nexport default Profile;\n"
  },
  {
    "path": "app/pages/submit.tsx",
    "content": "import React from \"react\";\nimport { NextPage } from \"next\";\nimport Head from \"next/head\";\nimport { useRouter } from \"next/router\";\nimport { Auth, Input, Button } from \"@supabase/ui\";\nimport { gql } from \"../gql\";\nimport { CombinedError, useMutation } from \"urql\";\nimport { Container } from \"../lib/container\";\nimport { MainSection } from \"../lib/main-section\";\n\nconst CreatePostMutation = gql(/* GraphQL */ `\n  mutation createPostMutation($input: PostInsertInput!) {\n    insertIntoPostCollection(objects: [$input]) {\n      affectedCount\n      records {\n        id\n      }\n    }\n  }\n`);\n\nfunction extractExpectedGraphQLErrors(\n  error: CombinedError | undefined\n): null | string {\n  if (error === undefined) {\n    return null;\n  }\n\n  for (const graphQLError of error.graphQLErrors) {\n    if (graphQLError.message.includes(\"Post_url_key\")) {\n      return \"This news has already been submitted.\";\n    }\n  }\n\n  return null;\n}\n\nconst Submit: NextPage = () => {\n  const session = Auth.useUser();\n  const router = useRouter();\n  const [createPostMutation, createPost] = useMutation(CreatePostMutation);\n  const [title, setTitle] = React.useState(\"\");\n  const [url, setUrl] = React.useState(\"\");\n\n  React.useEffect(() => {\n    if (session.user === null) {\n      router.replace(\"/login\");\n    }\n  }, []);\n\n  React.useEffect(() => {\n    if (createPostMutation.fetching === false && createPostMutation.data) {\n      router.push(\n        `/item/${createPostMutation.data.insertIntoPostCollection?.records[0].id}`\n      );\n    }\n  }, [createPostMutation.fetching]);\n\n  if (session.user == null) {\n    return null;\n  }\n\n  const error = extractExpectedGraphQLErrors(createPostMutation.error);\n\n  return (\n    <Container>\n      <Head>\n        <title>supanews | Submit New Item</title>\n        <meta name=\"description\" content=\"What is hot?\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n      </Head>\n      <MainSection>\n        <form className=\"container px-5 py-24 mx-auto max-w-md\">\n          <h1 className=\"font-semibold text-xl tracking-tight mb-5\">Submit</h1>\n          <div className=\"mb-4\">\n            <Input\n              placeholder=\"Title\"\n              value={title}\n              onChange={(ev) => setTitle(ev.target.value)}\n            />\n          </div>\n          <div className=\"mb-4\">\n            <Input\n              placeholder=\"URL\"\n              value={url}\n              onChange={(ev) => setUrl(ev.target.value)}\n            />\n          </div>\n          <div className=\"mb-4 min-h-1\">{error}</div>\n          {createPostMutation.fetching ? (\n            <Button type=\"outline\">Loading...</Button>\n          ) : (\n            <Button\n              onClick={() => {\n                createPost({\n                  input: {\n                    url,\n                    title,\n                    profileId: session.user!.id,\n                    score: 1,\n                  },\n                });\n              }}\n            >\n              Submit\n            </Button>\n          )}\n        </form>\n      </MainSection>\n    </Container>\n  );\n};\n\nexport default Submit;\n"
  },
  {
    "path": "app/postcss.config.js",
    "content": "module.exports = {\n  plugins: {\n    tailwindcss: {},\n    autoprefixer: {},\n  },\n};\n"
  },
  {
    "path": "app/styles/globals.css",
    "content": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n"
  },
  {
    "path": "app/tailwind.config.js",
    "content": "module.exports = {\n  content: [\"./pages/**/*.{js,ts,jsx,tsx}\", \"./lib/**/*.{js,ts,jsx,tsx}\"],\n  theme: {\n    extend: {},\n  },\n  plugins: [],\n};\n"
  },
  {
    "path": "app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"preserve\",\n    \"incremental\": true\n  },\n  \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "data/db/backup.sql",
    "content": "SET statement_timeout = 0;\nSET lock_timeout = 0;\nSET idle_in_transaction_session_timeout = 0;\nSET client_encoding = 'UTF8';\nSET standard_conforming_strings = on;\nSELECT pg_catalog.set_config('search_path', '', false);\nSET check_function_bodies = false;\nSET xmloption = content;\nSET client_min_messages = warning;\nSET row_security = off;\n\n--\n-- Name: auth; Type: SCHEMA; Schema: -; Owner: -\n--\n\nCREATE SCHEMA auth;\n\n\n--\n-- Name: extensions; Type: SCHEMA; Schema: -; Owner: -\n--\n\nCREATE SCHEMA extensions;\n\n\n--\n-- Name: pg_graphql; Type: EXTENSION; Schema: -; Owner: -\n--\n\nCREATE EXTENSION IF NOT EXISTS pg_graphql WITH SCHEMA public;\n\n\n--\n-- Name: EXTENSION pg_graphql; Type: COMMENT; Schema: -; Owner: -\n--\n\nCOMMENT ON EXTENSION pg_graphql IS 'GraphQL support';\n\n\n--\n-- Name: pg_net; Type: EXTENSION; Schema: -; Owner: -\n--\n\nCREATE EXTENSION IF NOT EXISTS pg_net WITH SCHEMA extensions;\n\n\n--\n-- Name: EXTENSION pg_net; Type: COMMENT; Schema: -; Owner: -\n--\n\nCOMMENT ON EXTENSION pg_net IS 'Async HTTP';\n\n\n--\n-- Name: pgbouncer; Type: SCHEMA; Schema: -; Owner: -\n--\n\nCREATE SCHEMA pgbouncer;\n\n\n--\n-- Name: realtime; Type: SCHEMA; Schema: -; Owner: -\n--\n\nCREATE SCHEMA realtime;\n\n\n--\n-- Name: storage; Type: SCHEMA; Schema: -; Owner: -\n--\n\nCREATE SCHEMA storage;\n\n\n--\n-- Name: supabase_functions; Type: SCHEMA; Schema: -; Owner: -\n--\n\nCREATE SCHEMA supabase_functions;\n\n\n--\n-- Name: pg_stat_statements; Type: EXTENSION; Schema: -; Owner: -\n--\n\nCREATE EXTENSION IF NOT EXISTS pg_stat_statements WITH SCHEMA extensions;\n\n\n--\n-- Name: EXTENSION pg_stat_statements; Type: COMMENT; Schema: -; Owner: -\n--\n\nCOMMENT ON EXTENSION pg_stat_statements IS 'track planning and execution statistics of all SQL statements executed';\n\n\n--\n-- Name: pgcrypto; Type: EXTENSION; Schema: -; Owner: -\n--\n\nCREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA extensions;\n\n\n--\n-- Name: EXTENSION pgcrypto; Type: COMMENT; Schema: -; Owner: -\n--\n\nCOMMENT ON EXTENSION pgcrypto IS 'cryptographic functions';\n\n\n--\n-- Name: pgjwt; Type: EXTENSION; Schema: -; Owner: -\n--\n\nCREATE EXTENSION IF NOT EXISTS pgjwt WITH SCHEMA extensions;\n\n\n--\n-- Name: EXTENSION pgjwt; Type: COMMENT; Schema: -; Owner: -\n--\n\nCOMMENT ON EXTENSION pgjwt IS 'JSON Web Token API for Postgresql';\n\n\n--\n-- Name: uuid-ossp; Type: EXTENSION; Schema: -; Owner: -\n--\n\nCREATE EXTENSION IF NOT EXISTS \"uuid-ossp\" WITH SCHEMA extensions;\n\n\n--\n-- Name: EXTENSION \"uuid-ossp\"; Type: COMMENT; Schema: -; Owner: -\n--\n\nCOMMENT ON EXTENSION \"uuid-ossp\" IS 'generate universally unique identifiers (UUIDs)';\n\n\n--\n-- Name: direction; Type: TYPE; Schema: public; Owner: -\n--\n\nCREATE TYPE public.direction AS ENUM (\n    'UP',\n    'DOWN'\n);\n\n\n--\n-- Name: action; Type: TYPE; Schema: realtime; Owner: -\n--\n\nCREATE TYPE realtime.action AS ENUM (\n    'INSERT',\n    'UPDATE',\n    'DELETE',\n    'TRUNCATE',\n    'ERROR'\n);\n\n\n--\n-- Name: equality_op; Type: TYPE; Schema: realtime; Owner: -\n--\n\nCREATE TYPE realtime.equality_op AS ENUM (\n    'eq',\n    'neq',\n    'lt',\n    'lte',\n    'gt',\n    'gte'\n);\n\n\n--\n-- Name: user_defined_filter; Type: TYPE; Schema: realtime; Owner: -\n--\n\nCREATE TYPE realtime.user_defined_filter AS (\n\tcolumn_name text,\n\top realtime.equality_op,\n\tvalue text\n);\n\n\n--\n-- Name: wal_column; Type: TYPE; Schema: realtime; Owner: -\n--\n\nCREATE TYPE realtime.wal_column AS (\n\tname text,\n\ttype text,\n\tvalue jsonb,\n\tis_pkey boolean,\n\tis_selectable boolean\n);\n\n\n--\n-- Name: wal_rls; Type: TYPE; Schema: realtime; Owner: -\n--\n\nCREATE TYPE realtime.wal_rls AS (\n\twal jsonb,\n\tis_rls_enabled boolean,\n\tsubscription_ids uuid[],\n\terrors text[]\n);\n\n\n--\n-- Name: email(); Type: FUNCTION; Schema: auth; Owner: -\n--\n\nCREATE FUNCTION auth.email() RETURNS text\n    LANGUAGE sql STABLE\n    AS $$\n  select\n  \tcoalesce(\n\t\tnullif(current_setting('request.jwt.claim.email', true), ''),\n\t\t(nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'email')\n\t)::text\n$$;\n\n\n--\n-- Name: role(); Type: FUNCTION; Schema: auth; Owner: -\n--\n\nCREATE FUNCTION auth.role() RETURNS text\n    LANGUAGE sql STABLE\n    AS $$\n  select\n  \tcoalesce(\n\t\tnullif(current_setting('request.jwt.claim.role', true), ''),\n\t\t(nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'role')\n\t)::text\n$$;\n\n\n--\n-- Name: uid(); Type: FUNCTION; Schema: auth; Owner: -\n--\n\nCREATE FUNCTION auth.uid() RETURNS uuid\n    LANGUAGE sql STABLE\n    AS $$\n  select\n  \tcoalesce(\n\t\tnullif(current_setting('request.jwt.claim.sub', true), ''),\n\t\t(nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'sub')\n\t)::uuid\n$$;\n\n\n--\n-- Name: grant_pg_cron_access(); Type: FUNCTION; Schema: extensions; Owner: -\n--\n\nCREATE FUNCTION extensions.grant_pg_cron_access() RETURNS event_trigger\n    LANGUAGE plpgsql\n    AS $$\nDECLARE\n  schema_is_cron bool;\nBEGIN\n  schema_is_cron = (\n    SELECT n.nspname = 'cron'\n    FROM pg_event_trigger_ddl_commands() AS ev\n    LEFT JOIN pg_catalog.pg_namespace AS n\n      ON ev.objid = n.oid\n  );\n\n  IF schema_is_cron\n  THEN\n    grant usage on schema cron to postgres with grant option;\n\n    alter default privileges in schema cron grant all on tables to postgres with grant option;\n    alter default privileges in schema cron grant all on functions to postgres with grant option;\n    alter default privileges in schema cron grant all on sequences to postgres with grant option;\n\n    alter default privileges for user supabase_admin in schema cron grant all\n        on sequences to postgres with grant option;\n    alter default privileges for user supabase_admin in schema cron grant all\n        on tables to postgres with grant option;\n    alter default privileges for user supabase_admin in schema cron grant all\n        on functions to postgres with grant option;\n\n    grant all privileges on all tables in schema cron to postgres with grant option;\n\n  END IF;\n\nEND;\n$$;\n\n\n--\n-- Name: FUNCTION grant_pg_cron_access(); Type: COMMENT; Schema: extensions; Owner: -\n--\n\nCOMMENT ON FUNCTION extensions.grant_pg_cron_access() IS 'Grants access to pg_cron';\n\n\n--\n-- Name: grant_pg_net_access(); Type: FUNCTION; Schema: extensions; Owner: -\n--\n\nCREATE FUNCTION extensions.grant_pg_net_access() RETURNS event_trigger\n    LANGUAGE plpgsql\n    AS $$\n    BEGIN\n      IF EXISTS (\n        SELECT 1\n        FROM pg_event_trigger_ddl_commands() AS ev\n        JOIN pg_extension AS ext\n        ON ev.objid = ext.oid\n        WHERE ext.extname = 'pg_net'\n      )\n      THEN\n        GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role;\n\n        ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;\n        ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;\n        ALTER function net.http_collect_response(request_id bigint, async boolean) SECURITY DEFINER;\n\n        ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;\n        ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;\n        ALTER function net.http_collect_response(request_id bigint, async boolean) SET search_path = net;\n\n        REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;\n        REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;\n        REVOKE ALL ON FUNCTION net.http_collect_response(request_id bigint, async boolean) FROM PUBLIC;\n\n        GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;\n        GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;\n        GRANT EXECUTE ON FUNCTION net.http_collect_response(request_id bigint, async boolean) TO supabase_functions_admin, postgres, anon, authenticated, service_role;\n      END IF;\n    END;\n    $$;\n\n\n--\n-- Name: FUNCTION grant_pg_net_access(); Type: COMMENT; Schema: extensions; Owner: -\n--\n\nCOMMENT ON FUNCTION extensions.grant_pg_net_access() IS 'Grants access to pg_net';\n\n\n--\n-- Name: notify_api_restart(); Type: FUNCTION; Schema: extensions; Owner: -\n--\n\nCREATE FUNCTION extensions.notify_api_restart() RETURNS event_trigger\n    LANGUAGE plpgsql\n    AS $$\nBEGIN\n    NOTIFY pgrst, 'reload schema';\nEND;\n$$;\n\n\n--\n-- Name: FUNCTION notify_api_restart(); Type: COMMENT; Schema: extensions; Owner: -\n--\n\nCOMMENT ON FUNCTION extensions.notify_api_restart() IS 'Sends a notification to the API to restart. If your database schema has changed, this is required so that Supabase can rebuild the relationships.';\n\n\n--\n-- Name: pgrst_ddl_watch(); Type: FUNCTION; Schema: extensions; Owner: -\n--\n\nCREATE FUNCTION extensions.pgrst_ddl_watch() RETURNS event_trigger\n    LANGUAGE plpgsql\n    AS $$\nDECLARE\n  cmd record;\nBEGIN\n  FOR cmd IN SELECT * FROM pg_event_trigger_ddl_commands()\n  LOOP\n    IF cmd.command_tag IN (\n      'CREATE SCHEMA', 'ALTER SCHEMA'\n    , 'CREATE TABLE', 'CREATE TABLE AS', 'SELECT INTO', 'ALTER TABLE'\n    , 'CREATE FOREIGN TABLE', 'ALTER FOREIGN TABLE'\n    , 'CREATE VIEW', 'ALTER VIEW'\n    , 'CREATE MATERIALIZED VIEW', 'ALTER MATERIALIZED VIEW'\n    , 'CREATE FUNCTION', 'ALTER FUNCTION'\n    , 'CREATE TRIGGER'\n    , 'CREATE TYPE', 'ALTER TYPE'\n    , 'CREATE RULE'\n    , 'COMMENT'\n    )\n    -- don't notify in case of CREATE TEMP table or other objects created on pg_temp\n    AND cmd.schema_name is distinct from 'pg_temp'\n    THEN\n      NOTIFY pgrst, 'reload schema';\n    END IF;\n  END LOOP;\nEND; $$;\n\n\n--\n-- Name: pgrst_drop_watch(); Type: FUNCTION; Schema: extensions; Owner: -\n--\n\nCREATE FUNCTION extensions.pgrst_drop_watch() RETURNS event_trigger\n    LANGUAGE plpgsql\n    AS $$\nDECLARE\n  obj record;\nBEGIN\n  FOR obj IN SELECT * FROM pg_event_trigger_dropped_objects()\n  LOOP\n    IF obj.object_type IN (\n      'schema'\n    , 'table'\n    , 'foreign table'\n    , 'view'\n    , 'materialized view'\n    , 'function'\n    , 'trigger'\n    , 'type'\n    , 'rule'\n    )\n    AND obj.is_temporary IS false -- no pg_temp objects\n    THEN\n      NOTIFY pgrst, 'reload schema';\n    END IF;\n  END LOOP;\nEND; $$;\n\n\n--\n-- Name: get_auth(text); Type: FUNCTION; Schema: pgbouncer; Owner: -\n--\n\nCREATE FUNCTION pgbouncer.get_auth(p_usename text) RETURNS TABLE(username text, password text)\n    LANGUAGE plpgsql SECURITY DEFINER\n    AS $$\nBEGIN\n    RAISE WARNING 'PgBouncer auth request: %', p_usename;\n\n    RETURN QUERY\n    SELECT usename::TEXT, passwd::TEXT FROM pg_catalog.pg_shadow\n    WHERE usename = p_usename;\nEND;\n$$;\n\n\n--\n-- Name: graphql(text, text, jsonb, jsonb); Type: FUNCTION; Schema: public; Owner: -\n--\n\nCREATE FUNCTION public.graphql(\"operationName\" text DEFAULT NULL::text, query text DEFAULT NULL::text, variables jsonb DEFAULT NULL::jsonb, extensions jsonb DEFAULT NULL::jsonb) RETURNS jsonb\n    LANGUAGE sql\n    AS $$\n    select graphql.resolve(query, coalesce(variables, '{}'));\n$$;\n\n\n--\n-- Name: handle_new_user(); Type: FUNCTION; Schema: public; Owner: -\n--\n\nCREATE FUNCTION public.handle_new_user() RETURNS trigger\n    LANGUAGE plpgsql SECURITY DEFINER\n    AS $$\nbegin\n  insert into public.\"Profile\" (id, \"avatarUrl\", username)\n  values (new.id, 'https://www.gravatar.com/avatar/' || md5(new.email) || '?d=mp', split_part(new.email, '@', 1) || '-' || floor(random() * 10000));\n  return new;\nend;\n$$;\n\n\n--\n-- Name: update_vote_counts(); Type: FUNCTION; Schema: public; Owner: -\n--\n\nCREATE FUNCTION public.update_vote_counts() RETURNS trigger\n    LANGUAGE plpgsql SECURITY DEFINER\n    AS $$\nBEGIN\n\nWITH r AS (\nSELECT\n\tcoalesce(\"Vote\".\"postId\", \"Post\".id) AS \"postId\",\n\tcount(1) \"voteTotal\",\n\tcount(1) FILTER (WHERE direction = 'UP') \"upVoteTotal\",\n\tcount(1) FILTER (WHERE direction = 'DOWN') \"downVoteTotal\",\n\tcoalesce(sum(\n\t\t\tCASE WHEN direction = 'UP' THEN\n\t\t\t\t1\n\t\t\tWHEN direction = 'DOWN' THEN\n\t\t\t\t- 1\n\t\t\tELSE\n\t\t\t\t0\n\t\t\tEND), 0) \"voteDelta\",\n\tsum(\n\t\tCASE WHEN direction = 'UP' THEN\n\t\t\t1\n\t\tWHEN direction = 'DOWN' THEN\n\t\t\t- 1\n\t\tELSE\n\t\t\t0\n\t\tEND) - 1 / (DATE_PART('hour', now() - max(\"Vote\".\"createdAt\")) + 2) ^ 1.8 AS \"score\",\n\trank() OVER (ORDER BY coalesce(sum( CASE WHEN direction = 'UP' THEN\n\t\t\t1\n\t\tWHEN direction = 'DOWN' THEN\n\t\t\t- 1\n\t\tELSE\n\t\t\t0\n\t\tEND) - 1 / (DATE_PART('hour', now() - max(\"Vote\".\"createdAt\")) + 2) ^ 1.8, '-infinity')\n\t\tDESC,\n\t\t\"Post\".\"createdAt\" DESC,\n\t\t\"Post\".title ASC) \"voteRank\"\nFROM\n\t\"Vote\"\n\tRIGHT JOIN \"Post\" ON \"Vote\".\"postId\" = \"Post\".id\nGROUP BY\n\t\"Post\".id,\n\t\"Vote\".\"postId\"\n)\n\nUPDATE\n\tpublic. \"Post\"\nSET\n\t\"upVoteTotal\" = r. \"upVoteTotal\",\n\t\"downVoteTotal\" = r. \"downVoteTotal\",\n\t\"voteTotal\" = r. \"voteTotal\",\n  \"voteDelta\" = r. \"voteDelta\",\n\t\"voteRank\" = r. \"voteRank\",\n  \"score\" = r. \"score\"\nFROM\n\tr\nWHERE\n\tr.\"postId\" = public. \"Post\".id;\n\nRETURN new;\nEND;\n$$;\n\n\n--\n-- Name: apply_rls(jsonb, integer); Type: FUNCTION; Schema: realtime; Owner: -\n--\n\nCREATE FUNCTION realtime.apply_rls(wal jsonb, max_record_bytes integer DEFAULT (1024 * 1024)) RETURNS SETOF realtime.wal_rls\n    LANGUAGE plpgsql\n    AS $$\n      declare\n        -- Regclass of the table e.g. public.notes\n        entity_ regclass = (quote_ident(wal ->> 'schema') || '.' || quote_ident(wal ->> 'table'))::regclass;\n\n        -- I, U, D, T: insert, update ...\n        action realtime.action = (\n          case wal ->> 'action'\n            when 'I' then 'INSERT'\n            when 'U' then 'UPDATE'\n            when 'D' then 'DELETE'\n            else 'ERROR'\n          end\n        );\n\n        -- Is row level security enabled for the table\n        is_rls_enabled bool = relrowsecurity from pg_class where oid = entity_;\n\n        subscriptions realtime.subscription[] = array_agg(subs)\n          from\n            realtime.subscription subs\n          where\n            subs.entity = entity_;\n\n        -- Subscription vars\n        roles regrole[] = array_agg(distinct us.claims_role)\n          from\n            unnest(subscriptions) us;\n\n        working_role regrole;\n        claimed_role regrole;\n        claims jsonb;\n\n        subscription_id uuid;\n        subscription_has_access bool;\n        visible_to_subscription_ids uuid[] = '{}';\n\n        -- structured info for wal's columns\n        columns realtime.wal_column[];\n        -- previous identity values for update/delete\n        old_columns realtime.wal_column[];\n\n        error_record_exceeds_max_size boolean = octet_length(wal::text) > max_record_bytes;\n\n        -- Primary jsonb output for record\n        output jsonb;\n\n      begin\n        perform set_config('role', null, true);\n\n        columns =\n          array_agg(\n            (\n              x->>'name',\n              x->>'type',\n              realtime.cast((x->'value') #>> '{}', (x->>'type')::regtype),\n              (pks ->> 'name') is not null,\n              true\n            )::realtime.wal_column\n          )\n          from\n            jsonb_array_elements(wal -> 'columns') x\n            left join jsonb_array_elements(wal -> 'pk') pks\n              on (x ->> 'name') = (pks ->> 'name');\n\n        old_columns =\n          array_agg(\n            (\n              x->>'name',\n              x->>'type',\n              realtime.cast((x->'value') #>> '{}', (x->>'type')::regtype),\n              (pks ->> 'name') is not null,\n              true\n            )::realtime.wal_column\n          )\n          from\n            jsonb_array_elements(wal -> 'identity') x\n            left join jsonb_array_elements(wal -> 'pk') pks\n              on (x ->> 'name') = (pks ->> 'name');\n\n        for working_role in select * from unnest(roles) loop\n\n          -- Update `is_selectable` for columns and old_columns\n          columns =\n            array_agg(\n              (\n                c.name,\n                c.type,\n                c.value,\n                c.is_pkey,\n                pg_catalog.has_column_privilege(working_role, entity_, c.name, 'SELECT')\n              )::realtime.wal_column\n            )\n            from\n              unnest(columns) c;\n\n          old_columns =\n            array_agg(\n              (\n                c.name,\n                c.type,\n                c.value,\n                c.is_pkey,\n                pg_catalog.has_column_privilege(working_role, entity_, c.name, 'SELECT')\n              )::realtime.wal_column\n            )\n            from\n              unnest(old_columns) c;\n\n          if action <> 'DELETE' and count(1) = 0 from unnest(columns) c where c.is_pkey then\n            return next (\n              null,\n              is_rls_enabled,\n              -- subscriptions is already filtered by entity\n              (select array_agg(s.subscription_id) from unnest(subscriptions) as s where claims_role = working_role),\n              array['Error 400: Bad Request, no primary key']\n            )::realtime.wal_rls;\n\n          -- The claims role does not have SELECT permission to the primary key of entity\n          elsif action <> 'DELETE' and sum(c.is_selectable::int) <> count(1) from unnest(columns) c where c.is_pkey then\n            return next (\n              null,\n              is_rls_enabled,\n              (select array_agg(s.subscription_id) from unnest(subscriptions) as s where claims_role = working_role),\n              array['Error 401: Unauthorized']\n            )::realtime.wal_rls;\n\n          else\n            output = jsonb_build_object(\n              'schema', wal ->> 'schema',\n              'table', wal ->> 'table',\n              'type', action,\n              'commit_timestamp', to_char(\n                (wal ->> 'timestamp')::timestamptz,\n                'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"'\n              ),\n              'columns', (\n                select\n                  jsonb_agg(\n                    jsonb_build_object(\n                      'name', pa.attname,\n                      'type', pt.typname\n                    )\n                    order by pa.attnum asc\n                  )\n                    from\n                      pg_attribute pa\n                      join pg_type pt\n                        on pa.atttypid = pt.oid\n                    where\n                      attrelid = entity_\n                      and attnum > 0\n                      and pg_catalog.has_column_privilege(working_role, entity_, pa.attname, 'SELECT')\n              )\n            )\n            -- Add \"record\" key for insert and update\n            || case\n                when error_record_exceeds_max_size then jsonb_build_object('record', '{}'::jsonb)\n                when action in ('INSERT', 'UPDATE') then\n                  jsonb_build_object(\n                    'record',\n                    (select jsonb_object_agg((c).name, (c).value) from unnest(columns) c where (c).is_selectable)\n                  )\n                else '{}'::jsonb\n            end\n            -- Add \"old_record\" key for update and delete\n            || case\n                when error_record_exceeds_max_size then jsonb_build_object('old_record', '{}'::jsonb)\n                when action in ('UPDATE', 'DELETE') then\n                  jsonb_build_object(\n                    'old_record',\n                    (select jsonb_object_agg((c).name, (c).value) from unnest(old_columns) c where (c).is_selectable)\n                  )\n                else '{}'::jsonb\n            end;\n\n            -- Create the prepared statement\n            if is_rls_enabled and action <> 'DELETE' then\n              if (select 1 from pg_prepared_statements where name = 'walrus_rls_stmt' limit 1) > 0 then\n                deallocate walrus_rls_stmt;\n              end if;\n              execute realtime.build_prepared_statement_sql('walrus_rls_stmt', entity_, columns);\n            end if;\n\n            visible_to_subscription_ids = '{}';\n\n            for subscription_id, claims in (\n                select\n                  subs.subscription_id,\n                  subs.claims\n                from\n                  unnest(subscriptions) subs\n                where\n                  subs.entity = entity_\n                  and subs.claims_role = working_role\n                  and realtime.is_visible_through_filters(columns, subs.filters)\n              ) loop\n\n              if not is_rls_enabled or action = 'DELETE' then\n                visible_to_subscription_ids = visible_to_subscription_ids || subscription_id;\n              else\n                -- Check if RLS allows the role to see the record\n                perform\n                  set_config('role', working_role::text, true),\n                  set_config('request.jwt.claims', claims::text, true);\n\n                execute 'execute walrus_rls_stmt' into subscription_has_access;\n\n                if subscription_has_access then\n                  visible_to_subscription_ids = visible_to_subscription_ids || subscription_id;\n                end if;\n              end if;\n            end loop;\n\n            perform set_config('role', null, true);\n\n            return next (\n              output,\n              is_rls_enabled,\n              visible_to_subscription_ids,\n              case\n                when error_record_exceeds_max_size then array['Error 413: Payload Too Large']\n                else '{}'\n              end\n            )::realtime.wal_rls;\n\n          end if;\n        end loop;\n\n        perform set_config('role', null, true);\n      end;\n      $$;\n\n\n--\n-- Name: build_prepared_statement_sql(text, regclass, realtime.wal_column[]); Type: FUNCTION; Schema: realtime; Owner: -\n--\n\nCREATE FUNCTION realtime.build_prepared_statement_sql(prepared_statement_name text, entity regclass, columns realtime.wal_column[]) RETURNS text\n    LANGUAGE sql\n    AS $$\n    /*\n    Builds a sql string that, if executed, creates a prepared statement to\n    tests retrive a row from *entity* by its primary key columns.\n\n    Example\n      select realtime.build_prepared_statment_sql('public.notes', '{\"id\"}'::text[], '{\"bigint\"}'::text[])\n    */\n      select\n    'prepare ' || prepared_statement_name || ' as\n      select\n        exists(\n          select\n            1\n          from\n            ' || entity || '\n          where\n            ' || string_agg(quote_ident(pkc.name) || '=' || quote_nullable(pkc.value #>> '{}') , ' and ') || '\n        )'\n      from\n        unnest(columns) pkc\n      where\n        pkc.is_pkey\n      group by\n        entity\n    $$;\n\n\n--\n-- Name: cast(text, regtype); Type: FUNCTION; Schema: realtime; Owner: -\n--\n\nCREATE FUNCTION realtime.\"cast\"(val text, type_ regtype) RETURNS jsonb\n    LANGUAGE plpgsql IMMUTABLE\n    AS $$\n    declare\n      res jsonb;\n    begin\n      execute format('select to_jsonb(%L::'|| type_::text || ')', val)  into res;\n      return res;\n    end\n    $$;\n\n\n--\n-- Name: check_equality_op(realtime.equality_op, regtype, text, text); Type: FUNCTION; Schema: realtime; Owner: -\n--\n\nCREATE FUNCTION realtime.check_equality_op(op realtime.equality_op, type_ regtype, val_1 text, val_2 text) RETURNS boolean\n    LANGUAGE plpgsql IMMUTABLE\n    AS $$\n    /*\n    Casts *val_1* and *val_2* as type *type_* and check the *op* condition for truthiness\n    */\n    declare\n      op_symbol text = (\n        case\n          when op = 'eq' then '='\n          when op = 'neq' then '!='\n          when op = 'lt' then '<'\n          when op = 'lte' then '<='\n          when op = 'gt' then '>'\n          when op = 'gte' then '>='\n          else 'UNKNOWN OP'\n        end\n      );\n      res boolean;\n    begin\n      execute format('select %L::'|| type_::text || ' ' || op_symbol || ' %L::'|| type_::text, val_1, val_2) into res;\n      return res;\n    end;\n    $$;\n\n\n--\n-- Name: is_visible_through_filters(realtime.wal_column[], realtime.user_defined_filter[]); Type: FUNCTION; Schema: realtime; Owner: -\n--\n\nCREATE FUNCTION realtime.is_visible_through_filters(columns realtime.wal_column[], filters realtime.user_defined_filter[]) RETURNS boolean\n    LANGUAGE sql IMMUTABLE\n    AS $$\n    /*\n    Should the record be visible (true) or filtered out (false) after *filters* are applied\n    */\n    select\n      -- Default to allowed when no filters present\n      coalesce(\n        sum(\n          realtime.check_equality_op(\n            op:=f.op,\n            type_:=col.type::regtype,\n            -- cast jsonb to text\n            val_1:=col.value #>> '{}',\n            val_2:=f.value\n          )::int\n        ) = count(1),\n        true\n      )\n    from\n      unnest(filters) f\n      join unnest(columns) col\n          on f.column_name = col.name;\n    $$;\n\n\n--\n-- Name: quote_wal2json(regclass); Type: FUNCTION; Schema: realtime; Owner: -\n--\n\nCREATE FUNCTION realtime.quote_wal2json(entity regclass) RETURNS text\n    LANGUAGE sql IMMUTABLE STRICT\n    AS $$\n      select\n        (\n          select string_agg('' || ch,'')\n          from unnest(string_to_array(nsp.nspname::text, null)) with ordinality x(ch, idx)\n          where\n            not (x.idx = 1 and x.ch = '\"')\n            and not (\n              x.idx = array_length(string_to_array(nsp.nspname::text, null), 1)\n              and x.ch = '\"'\n            )\n        )\n        || '.'\n        || (\n          select string_agg('' || ch,'')\n          from unnest(string_to_array(pc.relname::text, null)) with ordinality x(ch, idx)\n          where\n            not (x.idx = 1 and x.ch = '\"')\n            and not (\n              x.idx = array_length(string_to_array(nsp.nspname::text, null), 1)\n              and x.ch = '\"'\n            )\n          )\n      from\n        pg_class pc\n        join pg_namespace nsp\n          on pc.relnamespace = nsp.oid\n      where\n        pc.oid = entity\n    $$;\n\n\n--\n-- Name: subscription_check_filters(); Type: FUNCTION; Schema: realtime; Owner: -\n--\n\nCREATE FUNCTION realtime.subscription_check_filters() RETURNS trigger\n    LANGUAGE plpgsql\n    AS $$\n    /*\n    Validates that the user defined filters for a subscription:\n    - refer to valid columns that the claimed role may access\n    - values are coercable to the correct column type\n    */\n    declare\n      col_names text[] = coalesce(\n        array_agg(c.column_name order by c.ordinal_position),\n        '{}'::text[]\n      )\n      from\n        information_schema.columns c\n      where\n        format('%I.%I', c.table_schema, c.table_name)::regclass = new.entity\n        and pg_catalog.has_column_privilege(\n          (new.claims ->> 'role'),\n          format('%I.%I', c.table_schema, c.table_name)::regclass,\n          c.column_name,\n          'SELECT'\n        );\n      filter realtime.user_defined_filter;\n      col_type regtype;\n    begin\n      for filter in select * from unnest(new.filters) loop\n        -- Filtered column is valid\n        if not filter.column_name = any(col_names) then\n          raise exception 'invalid column for filter %', filter.column_name;\n        end if;\n\n        -- Type is sanitized and safe for string interpolation\n        col_type = (\n          select atttypid::regtype\n          from pg_catalog.pg_attribute\n          where attrelid = new.entity\n            and attname = filter.column_name\n        );\n        if col_type is null then\n          raise exception 'failed to lookup type for column %', filter.column_name;\n        end if;\n        -- raises an exception if value is not coercable to type\n        perform realtime.cast(filter.value, col_type);\n      end loop;\n\n      -- Apply consistent order to filters so the unique constraint on\n      -- (subscription_id, entity, filters) can't be tricked by a different filter order\n      new.filters = coalesce(\n        array_agg(f order by f.column_name, f.op, f.value),\n        '{}'\n      ) from unnest(new.filters) f;\n\n    return new;\n  end;\n  $$;\n\n\n--\n-- Name: to_regrole(text); Type: FUNCTION; Schema: realtime; Owner: -\n--\n\nCREATE FUNCTION realtime.to_regrole(role_name text) RETURNS regrole\n    LANGUAGE sql IMMUTABLE\n    AS $$ select role_name::regrole $$;\n\n\n--\n-- Name: extension(text); Type: FUNCTION; Schema: storage; Owner: -\n--\n\nCREATE FUNCTION storage.extension(name text) RETURNS text\n    LANGUAGE plpgsql\n    AS $$\nDECLARE\n_parts text[];\n_filename text;\nBEGIN\n\tselect string_to_array(name, '/') into _parts;\n\tselect _parts[array_length(_parts,1)] into _filename;\n\t-- @todo return the last part instead of 2\n\treturn split_part(_filename, '.', 2);\nEND\n$$;\n\n\n--\n-- Name: filename(text); Type: FUNCTION; Schema: storage; Owner: -\n--\n\nCREATE FUNCTION storage.filename(name text) RETURNS text\n    LANGUAGE plpgsql\n    AS $$\nDECLARE\n_parts text[];\nBEGIN\n\tselect string_to_array(name, '/') into _parts;\n\treturn _parts[array_length(_parts,1)];\nEND\n$$;\n\n\n--\n-- Name: foldername(text); Type: FUNCTION; Schema: storage; Owner: -\n--\n\nCREATE FUNCTION storage.foldername(name text) RETURNS text[]\n    LANGUAGE plpgsql\n    AS $$\nDECLARE\n_parts text[];\nBEGIN\n\tselect string_to_array(name, '/') into _parts;\n\treturn _parts[1:array_length(_parts,1)-1];\nEND\n$$;\n\n\n--\n-- Name: get_size_by_bucket(); Type: FUNCTION; Schema: storage; Owner: -\n--\n\nCREATE FUNCTION storage.get_size_by_bucket() RETURNS TABLE(size bigint, bucket_id text)\n    LANGUAGE plpgsql\n    AS $$\nBEGIN\n    return query\n        select sum((metadata->>'size')::int) as size, obj.bucket_id\n        from \"storage\".objects as obj\n        group by obj.bucket_id;\nEND\n$$;\n\n\n--\n-- Name: search(text, text, integer, integer, integer); Type: FUNCTION; Schema: storage; Owner: -\n--\n\nCREATE FUNCTION storage.search(prefix text, bucketname text, limits integer DEFAULT 100, levels integer DEFAULT 1, offsets integer DEFAULT 0) RETURNS TABLE(name text, id uuid, updated_at timestamp with time zone, created_at timestamp with time zone, last_accessed_at timestamp with time zone, metadata jsonb)\n    LANGUAGE plpgsql\n    AS $$\nBEGIN\n\treturn query\n\t\twith files_folders as (\n\t\t\tselect path_tokens[levels] as folder\n\t\t\tfrom storage.objects\n\t\t\twhere objects.name ilike prefix || '%'\n\t\t\tand bucket_id = bucketname\n\t\t\tGROUP by folder\n\t\t\tlimit limits\n\t\t\toffset offsets\n\t\t)\n\t\tselect files_folders.folder as name, objects.id, objects.updated_at, objects.created_at, objects.last_accessed_at, objects.metadata from files_folders\n\t\tleft join storage.objects\n\t\ton prefix || files_folders.folder = objects.name and objects.bucket_id=bucketname;\nEND\n$$;\n\n\n--\n-- Name: http_request(); Type: FUNCTION; Schema: supabase_functions; Owner: -\n--\n\nCREATE FUNCTION supabase_functions.http_request() RETURNS trigger\n    LANGUAGE plpgsql SECURITY DEFINER\n    SET search_path TO 'supabase_functions'\n    AS $$\n      DECLARE\n        request_id bigint;\n        payload jsonb;\n        url text := TG_ARGV[0]::text;\n        method text := TG_ARGV[1]::text;\n        headers jsonb DEFAULT '{}'::jsonb;\n        params jsonb DEFAULT '{}'::jsonb;\n        timeout_ms integer DEFAULT 1000;\n      BEGIN\n        IF url IS NULL OR url = 'null' THEN\n          RAISE EXCEPTION 'url argument is missing';\n        END IF;\n\n        IF method IS NULL OR method = 'null' THEN\n          RAISE EXCEPTION 'method argument is missing';\n        END IF;\n\n        IF TG_ARGV[2] IS NULL OR TG_ARGV[2] = 'null' THEN\n          headers = '{\"Content-Type\": \"application/json\"}'::jsonb;\n        ELSE\n          headers = TG_ARGV[2]::jsonb;\n        END IF;\n\n        IF TG_ARGV[3] IS NULL OR TG_ARGV[3] = 'null' THEN\n          params = '{}'::jsonb;\n        ELSE\n          params = TG_ARGV[3]::jsonb;\n        END IF;\n\n        IF TG_ARGV[4] IS NULL OR TG_ARGV[4] = 'null' THEN\n          timeout_ms = 1000;\n        ELSE\n          timeout_ms = TG_ARGV[4]::integer;\n        END IF;\n\n        CASE\n          WHEN method = 'GET' THEN\n            SELECT http_get INTO request_id FROM net.http_get(\n              url,\n              params,\n              headers,\n              timeout_ms\n            );\n          WHEN method = 'POST' THEN\n            payload = jsonb_build_object(\n              'old_record', OLD,\n              'record', NEW,\n              'type', TG_OP,\n              'table', TG_TABLE_NAME,\n              'schema', TG_TABLE_SCHEMA\n            );\n\n            SELECT http_post INTO request_id FROM net.http_post(\n              url,\n              payload,\n              params,\n              headers,\n              timeout_ms\n            );\n          ELSE\n            RAISE EXCEPTION 'method argument % is invalid', method;\n        END CASE;\n\n        INSERT INTO supabase_functions.hooks\n          (hook_table_id, hook_name, request_id)\n        VALUES\n          (TG_RELID, TG_NAME, request_id);\n\n        RETURN NEW;\n      END\n    $$;\n\n\nSET default_tablespace = '';\n\nSET default_table_access_method = heap;\n\n--\n-- Name: audit_log_entries; Type: TABLE; Schema: auth; Owner: -\n--\n\nCREATE TABLE auth.audit_log_entries (\n    instance_id uuid,\n    id uuid NOT NULL,\n    payload json,\n    created_at timestamp with time zone\n);\n\n\n--\n-- Name: TABLE audit_log_entries; Type: COMMENT; Schema: auth; Owner: -\n--\n\nCOMMENT ON TABLE auth.audit_log_entries IS 'Auth: Audit trail for user actions.';\n\n\n--\n-- Name: identities; Type: TABLE; Schema: auth; Owner: -\n--\n\nCREATE TABLE auth.identities (\n    id text NOT NULL,\n    user_id uuid NOT NULL,\n    identity_data jsonb NOT NULL,\n    provider text NOT NULL,\n    last_sign_in_at timestamp with time zone,\n    created_at timestamp with time zone,\n    updated_at timestamp with time zone\n);\n\n\n--\n-- Name: TABLE identities; Type: COMMENT; Schema: auth; Owner: -\n--\n\nCOMMENT ON TABLE auth.identities IS 'Auth: Stores identities associated to a user.';\n\n\n--\n-- Name: instances; Type: TABLE; Schema: auth; Owner: -\n--\n\nCREATE TABLE auth.instances (\n    id uuid NOT NULL,\n    uuid uuid,\n    raw_base_config text,\n    created_at timestamp with time zone,\n    updated_at timestamp with time zone\n);\n\n\n--\n-- Name: TABLE instances; Type: COMMENT; Schema: auth; Owner: -\n--\n\nCOMMENT ON TABLE auth.instances IS 'Auth: Manages users across multiple sites.';\n\n\n--\n-- Name: refresh_tokens; Type: TABLE; Schema: auth; Owner: -\n--\n\nCREATE TABLE auth.refresh_tokens (\n    instance_id uuid,\n    id bigint NOT NULL,\n    token character varying(255),\n    user_id character varying(255),\n    revoked boolean,\n    created_at timestamp with time zone,\n    updated_at timestamp with time zone,\n    parent character varying(255)\n);\n\n\n--\n-- Name: TABLE refresh_tokens; Type: COMMENT; Schema: auth; Owner: -\n--\n\nCOMMENT ON TABLE auth.refresh_tokens IS 'Auth: Store of tokens used to refresh JWT tokens once they expire.';\n\n\n--\n-- Name: refresh_tokens_id_seq; Type: SEQUENCE; Schema: auth; Owner: -\n--\n\nCREATE SEQUENCE auth.refresh_tokens_id_seq\n    START WITH 1\n    INCREMENT BY 1\n    NO MINVALUE\n    NO MAXVALUE\n    CACHE 1;\n\n\n--\n-- Name: refresh_tokens_id_seq; Type: SEQUENCE OWNED BY; Schema: auth; Owner: -\n--\n\nALTER SEQUENCE auth.refresh_tokens_id_seq OWNED BY auth.refresh_tokens.id;\n\n\n--\n-- Name: schema_migrations; Type: TABLE; Schema: auth; Owner: -\n--\n\nCREATE TABLE auth.schema_migrations (\n    version character varying(255) NOT NULL\n);\n\n\n--\n-- Name: TABLE schema_migrations; Type: COMMENT; Schema: auth; Owner: -\n--\n\nCOMMENT ON TABLE auth.schema_migrations IS 'Auth: Manages updates to the auth system.';\n\n\n--\n-- Name: users; Type: TABLE; Schema: auth; Owner: -\n--\n\nCREATE TABLE auth.users (\n    instance_id uuid,\n    id uuid NOT NULL,\n    aud character varying(255),\n    role character varying(255),\n    email character varying(255),\n    encrypted_password character varying(255),\n    email_confirmed_at timestamp with time zone,\n    invited_at timestamp with time zone,\n    confirmation_token character varying(255),\n    confirmation_sent_at timestamp with time zone,\n    recovery_token character varying(255),\n    recovery_sent_at timestamp with time zone,\n    email_change_token_new character varying(255),\n    email_change character varying(255),\n    email_change_sent_at timestamp with time zone,\n    last_sign_in_at timestamp with time zone,\n    raw_app_meta_data jsonb,\n    raw_user_meta_data jsonb,\n    is_super_admin boolean,\n    created_at timestamp with time zone,\n    updated_at timestamp with time zone,\n    phone character varying(15) DEFAULT NULL::character varying,\n    phone_confirmed_at timestamp with time zone,\n    phone_change character varying(15) DEFAULT ''::character varying,\n    phone_change_token character varying(255) DEFAULT ''::character varying,\n    phone_change_sent_at timestamp with time zone,\n    confirmed_at timestamp with time zone GENERATED ALWAYS AS (LEAST(email_confirmed_at, phone_confirmed_at)) STORED,\n    email_change_token_current character varying(255) DEFAULT ''::character varying,\n    email_change_confirm_status smallint DEFAULT 0,\n    banned_until timestamp with time zone,\n    CONSTRAINT users_email_change_confirm_status_check CHECK (((email_change_confirm_status >= 0) AND (email_change_confirm_status <= 2)))\n);\n\n\n--\n-- Name: TABLE users; Type: COMMENT; Schema: auth; Owner: -\n--\n\nCOMMENT ON TABLE auth.users IS 'Auth: Stores user login data within a secure schema.';\n\n\n--\n-- Name: Comment; Type: TABLE; Schema: public; Owner: -\n--\n\nCREATE TABLE public.\"Comment\" (\n    id bigint NOT NULL,\n    \"createdAt\" timestamp with time zone DEFAULT now(),\n    \"updatedAt\" timestamp with time zone,\n    message text NOT NULL,\n    \"profileId\" uuid NOT NULL,\n    \"postId\" bigint NOT NULL\n);\n\n\n--\n-- Name: TABLE \"Comment\"; Type: COMMENT; Schema: public; Owner: -\n--\n\nCOMMENT ON TABLE public.\"Comment\" IS '@graphql({\"totalCount\": {\"enabled\": true}})';\n\n\n--\n-- Name: Comment_id_seq; Type: SEQUENCE; Schema: public; Owner: -\n--\n\nALTER TABLE public.\"Comment\" ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY (\n    SEQUENCE NAME public.\"Comment_id_seq\"\n    START WITH 1\n    INCREMENT BY 1\n    NO MINVALUE\n    NO MAXVALUE\n    CACHE 1\n);\n\n\n--\n-- Name: Vote; Type: TABLE; Schema: public; Owner: -\n--\n\nCREATE TABLE public.\"Vote\" (\n    id bigint NOT NULL,\n    \"createdAt\" timestamp with time zone DEFAULT now(),\n    \"updatedAt\" timestamp with time zone,\n    \"profileId\" uuid NOT NULL,\n    \"postId\" bigint NOT NULL,\n    direction public.direction NOT NULL\n);\n\n\n--\n-- Name: TABLE \"Vote\"; Type: COMMENT; Schema: public; Owner: -\n--\n\nCOMMENT ON TABLE public.\"Vote\" IS '@graphql({\"totalCount\": {\"enabled\": true}})';\n\n\n--\n-- Name: DownVote_id_seq; Type: SEQUENCE; Schema: public; Owner: -\n--\n\nALTER TABLE public.\"Vote\" ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY (\n    SEQUENCE NAME public.\"DownVote_id_seq\"\n    START WITH 1\n    INCREMENT BY 1\n    NO MINVALUE\n    NO MAXVALUE\n    CACHE 1\n);\n\n\n--\n-- Name: Post; Type: TABLE; Schema: public; Owner: -\n--\n\nCREATE TABLE public.\"Post\" (\n    id bigint NOT NULL,\n    \"createdAt\" timestamp with time zone DEFAULT now() NOT NULL,\n    \"updatedAt\" timestamp with time zone,\n    title text NOT NULL,\n    url text NOT NULL,\n    \"profileId\" uuid NOT NULL,\n    \"upVoteTotal\" integer DEFAULT 0 NOT NULL,\n    \"downVoteTotal\" integer DEFAULT 0 NOT NULL,\n    \"voteTotal\" integer DEFAULT 0 NOT NULL,\n    \"voteRank\" integer DEFAULT 1 NOT NULL,\n    score real DEFAULT '0'::real,\n    \"voteDelta\" integer DEFAULT 0 NOT NULL,\n    CONSTRAINT post_title_length CHECK ((char_length(title) > 0)),\n    CONSTRAINT post_url_length CHECK ((char_length(url) > 0))\n);\n\n\n--\n-- Name: TABLE \"Post\"; Type: COMMENT; Schema: public; Owner: -\n--\n\nCOMMENT ON TABLE public.\"Post\" IS '@graphql({\"totalCount\": {\"enabled\": true}})';\n\n\n--\n-- Name: Post_id_seq; Type: SEQUENCE; Schema: public; Owner: -\n--\n\nALTER TABLE public.\"Post\" ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY (\n    SEQUENCE NAME public.\"Post_id_seq\"\n    START WITH 1\n    INCREMENT BY 1\n    NO MINVALUE\n    NO MAXVALUE\n    CACHE 1\n);\n\n\n--\n-- Name: Profile; Type: TABLE; Schema: public; Owner: -\n--\n\nCREATE TABLE public.\"Profile\" (\n    id uuid NOT NULL,\n    updatedat timestamp with time zone,\n    username text,\n    \"avatarUrl\" text,\n    website text,\n    bio text,\n    CONSTRAINT usernamelength CHECK ((char_length(username) >= 3))\n);\n\n\n--\n-- Name: TABLE \"Profile\"; Type: COMMENT; Schema: public; Owner: -\n--\n\nCOMMENT ON TABLE public.\"Profile\" IS '@graphql({\"totalCount\": {\"enabled\": true}})';\n\n\n--\n-- Name: schema_migrations; Type: TABLE; Schema: public; Owner: -\n--\n\nCREATE TABLE public.schema_migrations (\n    version character varying(255) NOT NULL\n);\n\n\n--\n-- Name: schema_migrations; Type: TABLE; Schema: realtime; Owner: -\n--\n\nCREATE TABLE realtime.schema_migrations (\n    version bigint NOT NULL,\n    inserted_at timestamp(0) without time zone\n);\n\n\n--\n-- Name: subscription; Type: TABLE; Schema: realtime; Owner: -\n--\n\nCREATE TABLE realtime.subscription (\n    id bigint NOT NULL,\n    subscription_id uuid NOT NULL,\n    entity regclass NOT NULL,\n    filters realtime.user_defined_filter[] DEFAULT '{}'::realtime.user_defined_filter[] NOT NULL,\n    claims jsonb NOT NULL,\n    claims_role regrole GENERATED ALWAYS AS (realtime.to_regrole((claims ->> 'role'::text))) STORED NOT NULL,\n    created_at timestamp without time zone DEFAULT timezone('utc'::text, now()) NOT NULL\n);\n\n\n--\n-- Name: subscription_id_seq; Type: SEQUENCE; Schema: realtime; Owner: -\n--\n\nALTER TABLE realtime.subscription ALTER COLUMN id ADD GENERATED ALWAYS AS IDENTITY (\n    SEQUENCE NAME realtime.subscription_id_seq\n    START WITH 1\n    INCREMENT BY 1\n    NO MINVALUE\n    NO MAXVALUE\n    CACHE 1\n);\n\n\n--\n-- Name: buckets; Type: TABLE; Schema: storage; Owner: -\n--\n\nCREATE TABLE storage.buckets (\n    id text NOT NULL,\n    name text NOT NULL,\n    owner uuid,\n    created_at timestamp with time zone DEFAULT now(),\n    updated_at timestamp with time zone DEFAULT now(),\n    public boolean DEFAULT false\n);\n\n\n--\n-- Name: migrations; Type: TABLE; Schema: storage; Owner: -\n--\n\nCREATE TABLE storage.migrations (\n    id integer NOT NULL,\n    name character varying(100) NOT NULL,\n    hash character varying(40) NOT NULL,\n    executed_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP\n);\n\n\n--\n-- Name: objects; Type: TABLE; Schema: storage; Owner: -\n--\n\nCREATE TABLE storage.objects (\n    id uuid DEFAULT extensions.uuid_generate_v4() NOT NULL,\n    bucket_id text,\n    name text,\n    owner uuid,\n    created_at timestamp with time zone DEFAULT now(),\n    updated_at timestamp with time zone DEFAULT now(),\n    last_accessed_at timestamp with time zone DEFAULT now(),\n    metadata jsonb\n);\n\n\n--\n-- Name: hooks; Type: TABLE; Schema: supabase_functions; Owner: -\n--\n\nCREATE TABLE supabase_functions.hooks (\n    id bigint NOT NULL,\n    hook_table_id integer NOT NULL,\n    hook_name text NOT NULL,\n    created_at timestamp with time zone DEFAULT now() NOT NULL,\n    request_id bigint\n);\n\n\n--\n-- Name: TABLE hooks; Type: COMMENT; Schema: supabase_functions; Owner: -\n--\n\nCOMMENT ON TABLE supabase_functions.hooks IS 'Supabase Functions Hooks: Audit trail for triggered hooks.';\n\n\n--\n-- Name: hooks_id_seq; Type: SEQUENCE; Schema: supabase_functions; Owner: -\n--\n\nCREATE SEQUENCE supabase_functions.hooks_id_seq\n    START WITH 1\n    INCREMENT BY 1\n    NO MINVALUE\n    NO MAXVALUE\n    CACHE 1;\n\n\n--\n-- Name: hooks_id_seq; Type: SEQUENCE OWNED BY; Schema: supabase_functions; Owner: -\n--\n\nALTER SEQUENCE supabase_functions.hooks_id_seq OWNED BY supabase_functions.hooks.id;\n\n\n--\n-- Name: migrations; Type: TABLE; Schema: supabase_functions; Owner: -\n--\n\nCREATE TABLE supabase_functions.migrations (\n    version text NOT NULL,\n    inserted_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\n\n--\n-- Name: refresh_tokens id; Type: DEFAULT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.refresh_tokens ALTER COLUMN id SET DEFAULT nextval('auth.refresh_tokens_id_seq'::regclass);\n\n\n--\n-- Name: hooks id; Type: DEFAULT; Schema: supabase_functions; Owner: -\n--\n\nALTER TABLE ONLY supabase_functions.hooks ALTER COLUMN id SET DEFAULT nextval('supabase_functions.hooks_id_seq'::regclass);\n\n\n--\n-- Name: audit_log_entries audit_log_entries_pkey; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.audit_log_entries\n    ADD CONSTRAINT audit_log_entries_pkey PRIMARY KEY (id);\n\n\n--\n-- Name: identities identities_pkey; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.identities\n    ADD CONSTRAINT identities_pkey PRIMARY KEY (provider, id);\n\n\n--\n-- Name: instances instances_pkey; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.instances\n    ADD CONSTRAINT instances_pkey PRIMARY KEY (id);\n\n\n--\n-- Name: refresh_tokens refresh_tokens_pkey; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.refresh_tokens\n    ADD CONSTRAINT refresh_tokens_pkey PRIMARY KEY (id);\n\n\n--\n-- Name: refresh_tokens refresh_tokens_token_unique; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.refresh_tokens\n    ADD CONSTRAINT refresh_tokens_token_unique UNIQUE (token);\n\n\n--\n-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.schema_migrations\n    ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version);\n\n\n--\n-- Name: users users_email_key; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.users\n    ADD CONSTRAINT users_email_key UNIQUE (email);\n\n\n--\n-- Name: users users_phone_key; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.users\n    ADD CONSTRAINT users_phone_key UNIQUE (phone);\n\n\n--\n-- Name: users users_pkey; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.users\n    ADD CONSTRAINT users_pkey PRIMARY KEY (id);\n\n\n--\n-- Name: Comment Comment_pkey; Type: CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Comment\"\n    ADD CONSTRAINT \"Comment_pkey\" PRIMARY KEY (id);\n\n\n--\n-- Name: Vote DownVote_pkey; Type: CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Vote\"\n    ADD CONSTRAINT \"DownVote_pkey\" PRIMARY KEY (id);\n\n\n--\n-- Name: Post Post_pkey; Type: CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Post\"\n    ADD CONSTRAINT \"Post_pkey\" PRIMARY KEY (id);\n\n\n--\n-- Name: Post Post_url_key; Type: CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Post\"\n    ADD CONSTRAINT \"Post_url_key\" UNIQUE (url);\n\n\n--\n-- Name: Profile Profile_pkey; Type: CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Profile\"\n    ADD CONSTRAINT \"Profile_pkey\" PRIMARY KEY (id);\n\n\n--\n-- Name: Profile Profile_username_key; Type: CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Profile\"\n    ADD CONSTRAINT \"Profile_username_key\" UNIQUE (username);\n\n\n--\n-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.schema_migrations\n    ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version);\n\n\n--\n-- Name: subscription pk_subscription; Type: CONSTRAINT; Schema: realtime; Owner: -\n--\n\nALTER TABLE ONLY realtime.subscription\n    ADD CONSTRAINT pk_subscription PRIMARY KEY (id);\n\n\n--\n-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: realtime; Owner: -\n--\n\nALTER TABLE ONLY realtime.schema_migrations\n    ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version);\n\n\n--\n-- Name: buckets buckets_pkey; Type: CONSTRAINT; Schema: storage; Owner: -\n--\n\nALTER TABLE ONLY storage.buckets\n    ADD CONSTRAINT buckets_pkey PRIMARY KEY (id);\n\n\n--\n-- Name: migrations migrations_name_key; Type: CONSTRAINT; Schema: storage; Owner: -\n--\n\nALTER TABLE ONLY storage.migrations\n    ADD CONSTRAINT migrations_name_key UNIQUE (name);\n\n\n--\n-- Name: migrations migrations_pkey; Type: CONSTRAINT; Schema: storage; Owner: -\n--\n\nALTER TABLE ONLY storage.migrations\n    ADD CONSTRAINT migrations_pkey PRIMARY KEY (id);\n\n\n--\n-- Name: objects objects_pkey; Type: CONSTRAINT; Schema: storage; Owner: -\n--\n\nALTER TABLE ONLY storage.objects\n    ADD CONSTRAINT objects_pkey PRIMARY KEY (id);\n\n\n--\n-- Name: hooks hooks_pkey; Type: CONSTRAINT; Schema: supabase_functions; Owner: -\n--\n\nALTER TABLE ONLY supabase_functions.hooks\n    ADD CONSTRAINT hooks_pkey PRIMARY KEY (id);\n\n\n--\n-- Name: migrations migrations_pkey; Type: CONSTRAINT; Schema: supabase_functions; Owner: -\n--\n\nALTER TABLE ONLY supabase_functions.migrations\n    ADD CONSTRAINT migrations_pkey PRIMARY KEY (version);\n\n\n--\n-- Name: audit_logs_instance_id_idx; Type: INDEX; Schema: auth; Owner: -\n--\n\nCREATE INDEX audit_logs_instance_id_idx ON auth.audit_log_entries USING btree (instance_id);\n\n\n--\n-- Name: identities_user_id_idx; Type: INDEX; Schema: auth; Owner: -\n--\n\nCREATE INDEX identities_user_id_idx ON auth.identities USING btree (user_id);\n\n\n--\n-- Name: refresh_tokens_instance_id_idx; Type: INDEX; Schema: auth; Owner: -\n--\n\nCREATE INDEX refresh_tokens_instance_id_idx ON auth.refresh_tokens USING btree (instance_id);\n\n\n--\n-- Name: refresh_tokens_instance_id_user_id_idx; Type: INDEX; Schema: auth; Owner: -\n--\n\nCREATE INDEX refresh_tokens_instance_id_user_id_idx ON auth.refresh_tokens USING btree (instance_id, user_id);\n\n\n--\n-- Name: refresh_tokens_parent_idx; Type: INDEX; Schema: auth; Owner: -\n--\n\nCREATE INDEX refresh_tokens_parent_idx ON auth.refresh_tokens USING btree (parent);\n\n\n--\n-- Name: refresh_tokens_token_idx; Type: INDEX; Schema: auth; Owner: -\n--\n\nCREATE INDEX refresh_tokens_token_idx ON auth.refresh_tokens USING btree (token);\n\n\n--\n-- Name: users_instance_id_email_idx; Type: INDEX; Schema: auth; Owner: -\n--\n\nCREATE INDEX users_instance_id_email_idx ON auth.users USING btree (instance_id, lower((email)::text));\n\n\n--\n-- Name: users_instance_id_idx; Type: INDEX; Schema: auth; Owner: -\n--\n\nCREATE INDEX users_instance_id_idx ON auth.users USING btree (instance_id);\n\n\n--\n-- Name: idx_one_vote_per_post; Type: INDEX; Schema: public; Owner: -\n--\n\nCREATE UNIQUE INDEX idx_one_vote_per_post ON public.\"Vote\" USING btree (\"profileId\", \"postId\");\n\n\n--\n-- Name: idx_unique_post_url; Type: INDEX; Schema: public; Owner: -\n--\n\nCREATE UNIQUE INDEX idx_unique_post_url ON public.\"Post\" USING btree (url);\n\n\n--\n-- Name: ix_realtime_subscription_entity; Type: INDEX; Schema: realtime; Owner: -\n--\n\nCREATE INDEX ix_realtime_subscription_entity ON realtime.subscription USING hash (entity);\n\n\n--\n-- Name: subscription_subscription_id_entity_filters_key; Type: INDEX; Schema: realtime; Owner: -\n--\n\nCREATE UNIQUE INDEX subscription_subscription_id_entity_filters_key ON realtime.subscription USING btree (subscription_id, entity, filters);\n\n\n--\n-- Name: bname; Type: INDEX; Schema: storage; Owner: -\n--\n\nCREATE UNIQUE INDEX bname ON storage.buckets USING btree (name);\n\n\n--\n-- Name: bucketid_objname; Type: INDEX; Schema: storage; Owner: -\n--\n\nCREATE UNIQUE INDEX bucketid_objname ON storage.objects USING btree (bucket_id, name);\n\n\n--\n-- Name: name_prefix_search; Type: INDEX; Schema: storage; Owner: -\n--\n\nCREATE INDEX name_prefix_search ON storage.objects USING btree (name text_pattern_ops);\n\n\n--\n-- Name: supabase_functions_hooks_h_table_id_h_name_idx; Type: INDEX; Schema: supabase_functions; Owner: -\n--\n\nCREATE INDEX supabase_functions_hooks_h_table_id_h_name_idx ON supabase_functions.hooks USING btree (hook_table_id, hook_name);\n\n\n--\n-- Name: supabase_functions_hooks_request_id_idx; Type: INDEX; Schema: supabase_functions; Owner: -\n--\n\nCREATE INDEX supabase_functions_hooks_request_id_idx ON supabase_functions.hooks USING btree (request_id);\n\n\n--\n-- Name: users on_auth_user_created; Type: TRIGGER; Schema: auth; Owner: -\n--\n\nCREATE TRIGGER on_auth_user_created AFTER INSERT ON auth.users FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();\n\n\n--\n-- Name: Vote on_vote_created; Type: TRIGGER; Schema: public; Owner: -\n--\n\nCREATE TRIGGER on_vote_created AFTER INSERT ON public.\"Vote\" FOR EACH ROW EXECUTE FUNCTION public.update_vote_counts();\n\n\n--\n-- Name: Vote on_vote_deleted; Type: TRIGGER; Schema: public; Owner: -\n--\n\nCREATE TRIGGER on_vote_deleted AFTER DELETE ON public.\"Vote\" FOR EACH ROW EXECUTE FUNCTION public.update_vote_counts();\n\n\n--\n-- Name: subscription tr_check_filters; Type: TRIGGER; Schema: realtime; Owner: -\n--\n\nCREATE TRIGGER tr_check_filters BEFORE INSERT OR UPDATE ON realtime.subscription FOR EACH ROW EXECUTE FUNCTION realtime.subscription_check_filters();\n\n\n--\n-- Name: identities identities_user_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.identities\n    ADD CONSTRAINT identities_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE;\n\n\n--\n-- Name: refresh_tokens refresh_tokens_parent_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.refresh_tokens\n    ADD CONSTRAINT refresh_tokens_parent_fkey FOREIGN KEY (parent) REFERENCES auth.refresh_tokens(token);\n\n\n--\n-- Name: Comment Comment_postId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Comment\"\n    ADD CONSTRAINT \"Comment_postId_fkey\" FOREIGN KEY (\"postId\") REFERENCES public.\"Post\"(id) ON DELETE CASCADE;\n\n\n--\n-- Name: Comment Comment_profileId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Comment\"\n    ADD CONSTRAINT \"Comment_profileId_fkey\" FOREIGN KEY (\"profileId\") REFERENCES public.\"Profile\"(id);\n\n\n--\n-- Name: Vote DownVote_profileId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Vote\"\n    ADD CONSTRAINT \"DownVote_profileId_fkey\" FOREIGN KEY (\"profileId\") REFERENCES public.\"Profile\"(id);\n\n\n--\n-- Name: Post Post_profileId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Post\"\n    ADD CONSTRAINT \"Post_profileId_fkey\" FOREIGN KEY (\"profileId\") REFERENCES public.\"Profile\"(id);\n\n\n--\n-- Name: Profile Profile_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Profile\"\n    ADD CONSTRAINT \"Profile_id_fkey\" FOREIGN KEY (id) REFERENCES auth.users(id);\n\n\n--\n-- Name: Vote Vote_postId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Vote\"\n    ADD CONSTRAINT \"Vote_postId_fkey\" FOREIGN KEY (\"postId\") REFERENCES public.\"Post\"(id) ON DELETE CASCADE;\n\n\n--\n-- Name: buckets buckets_owner_fkey; Type: FK CONSTRAINT; Schema: storage; Owner: -\n--\n\nALTER TABLE ONLY storage.buckets\n    ADD CONSTRAINT buckets_owner_fkey FOREIGN KEY (owner) REFERENCES auth.users(id);\n\n\n--\n-- Name: objects objects_bucketId_fkey; Type: FK CONSTRAINT; Schema: storage; Owner: -\n--\n\nALTER TABLE ONLY storage.objects\n    ADD CONSTRAINT \"objects_bucketId_fkey\" FOREIGN KEY (bucket_id) REFERENCES storage.buckets(id);\n\n\n--\n-- Name: objects objects_owner_fkey; Type: FK CONSTRAINT; Schema: storage; Owner: -\n--\n\nALTER TABLE ONLY storage.objects\n    ADD CONSTRAINT objects_owner_fkey FOREIGN KEY (owner) REFERENCES auth.users(id);\n\n\n--\n-- Name: hooks hooks_request_id_fkey; Type: FK CONSTRAINT; Schema: supabase_functions; Owner: -\n--\n\nALTER TABLE ONLY supabase_functions.hooks\n    ADD CONSTRAINT hooks_request_id_fkey FOREIGN KEY (request_id) REFERENCES net.http_request_queue(id) ON DELETE CASCADE;\n\n\n--\n-- Name: Post All users can view posts; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"All users can view posts\" ON public.\"Post\" FOR SELECT USING (true);\n\n\n--\n-- Name: Comment; Type: ROW SECURITY; Schema: public; Owner: -\n--\n\nALTER TABLE public.\"Comment\" ENABLE ROW LEVEL SECURITY;\n\n--\n-- Name: Comment Everyone can view comments; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Everyone can view comments\" ON public.\"Comment\" FOR SELECT USING (true);\n\n\n--\n-- Name: Vote Everyone can view votes; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Everyone can view votes\" ON public.\"Vote\" FOR SELECT USING (true);\n\n\n--\n-- Name: Comment Only authenticated users can comment; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Only authenticated users can comment\" ON public.\"Comment\" FOR INSERT WITH CHECK ((auth.role() = 'authenticated'::text));\n\n\n--\n-- Name: Post Only authenticated users can create posts; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Only authenticated users can create posts\" ON public.\"Post\" FOR INSERT WITH CHECK ((auth.role() = 'authenticated'::text));\n\n\n--\n-- Name: Vote Only authenticated users can vote; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Only authenticated users can vote\" ON public.\"Vote\" FOR INSERT WITH CHECK ((auth.role() = 'authenticated'::text));\n\n\n--\n-- Name: Post; Type: ROW SECURITY; Schema: public; Owner: -\n--\n\nALTER TABLE public.\"Post\" ENABLE ROW LEVEL SECURITY;\n\n--\n-- Name: Profile; Type: ROW SECURITY; Schema: public; Owner: -\n--\n\nALTER TABLE public.\"Profile\" ENABLE ROW LEVEL SECURITY;\n\n--\n-- Name: Profile Public profiles are viewable by everyone.; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Public profiles are viewable by everyone.\" ON public.\"Profile\" FOR SELECT USING (true);\n\n\n--\n-- Name: Comment User can edit their own comments; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"User can edit their own comments\" ON public.\"Comment\" FOR UPDATE USING ((auth.uid() = \"profileId\")) WITH CHECK ((auth.uid() = \"profileId\"));\n\n\n--\n-- Name: Vote Users can change their vote; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Users can change their vote\" ON public.\"Vote\" FOR UPDATE USING ((auth.uid() = \"profileId\")) WITH CHECK ((auth.uid() = \"profileId\"));\n\n\n--\n-- Name: Comment Users can delete their own comments; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Users can delete their own comments\" ON public.\"Comment\" FOR DELETE USING ((auth.uid() = \"profileId\"));\n\n\n--\n-- Name: Post Users can delete their own posts; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Users can delete their own posts\" ON public.\"Post\" FOR DELETE USING ((auth.uid() = \"profileId\"));\n\n\n--\n-- Name: Vote Users can delete their own votes; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Users can delete their own votes\" ON public.\"Vote\" FOR DELETE USING ((auth.uid() = \"profileId\"));\n\n\n--\n-- Name: Post Users can edit their own posts; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Users can edit their own posts\" ON public.\"Post\" FOR UPDATE USING ((auth.uid() = \"profileId\")) WITH CHECK ((auth.uid() = \"profileId\"));\n\n\n--\n-- Name: Profile Users can insert their own profile.; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Users can insert their own profile.\" ON public.\"Profile\" FOR INSERT WITH CHECK ((auth.uid() = id));\n\n\n--\n-- Name: Profile Users can update own profile.; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Users can update own profile.\" ON public.\"Profile\" FOR UPDATE USING ((auth.uid() = id));\n\n\n--\n-- Name: Vote; Type: ROW SECURITY; Schema: public; Owner: -\n--\n\nALTER TABLE public.\"Vote\" ENABLE ROW LEVEL SECURITY;\n\n--\n-- Name: schema_migrations; Type: ROW SECURITY; Schema: public; Owner: -\n--\n\nALTER TABLE public.schema_migrations ENABLE ROW LEVEL SECURITY;\n\n--\n-- Name: objects Anyone can update an avatar.; Type: POLICY; Schema: storage; Owner: -\n--\n\nCREATE POLICY \"Anyone can update an avatar.\" ON storage.objects FOR UPDATE WITH CHECK ((bucket_id = 'avatars'::text));\n\n\n--\n-- Name: objects Anyone can upload an avatar.; Type: POLICY; Schema: storage; Owner: -\n--\n\nCREATE POLICY \"Anyone can upload an avatar.\" ON storage.objects FOR INSERT WITH CHECK ((bucket_id = 'avatars'::text));\n\n\n--\n-- Name: objects Avatar images are publicly accessible.; Type: POLICY; Schema: storage; Owner: -\n--\n\nCREATE POLICY \"Avatar images are publicly accessible.\" ON storage.objects FOR SELECT USING ((bucket_id = 'avatars'::text));\n\n\n--\n-- Name: buckets; Type: ROW SECURITY; Schema: storage; Owner: -\n--\n\nALTER TABLE storage.buckets ENABLE ROW LEVEL SECURITY;\n\n--\n-- Name: migrations; Type: ROW SECURITY; Schema: storage; Owner: -\n--\n\nALTER TABLE storage.migrations ENABLE ROW LEVEL SECURITY;\n\n--\n-- Name: objects; Type: ROW SECURITY; Schema: storage; Owner: -\n--\n\nALTER TABLE storage.objects ENABLE ROW LEVEL SECURITY;\n\n--\n-- Name: supabase_realtime; Type: PUBLICATION; Schema: -; Owner: -\n--\n\nCREATE PUBLICATION supabase_realtime WITH (publish = 'insert, update, delete, truncate');\n\n\n--\n-- Name: supabase_realtime Profile; Type: PUBLICATION TABLE; Schema: public; Owner: -\n--\n\nALTER PUBLICATION supabase_realtime ADD TABLE ONLY public.\"Profile\";\n\n\n--\n-- Name: issue_pg_cron_access; Type: EVENT TRIGGER; Schema: -; Owner: -\n--\n\nCREATE EVENT TRIGGER issue_pg_cron_access ON ddl_command_end\n         WHEN TAG IN ('CREATE SCHEMA')\n   EXECUTE FUNCTION extensions.grant_pg_cron_access();\n\n\n--\n-- Name: issue_pg_net_access; Type: EVENT TRIGGER; Schema: -; Owner: -\n--\n\nCREATE EVENT TRIGGER issue_pg_net_access ON ddl_command_end\n         WHEN TAG IN ('CREATE EXTENSION')\n   EXECUTE FUNCTION extensions.grant_pg_net_access();\n\n\n--\n-- Name: pgrst_ddl_watch; Type: EVENT TRIGGER; Schema: -; Owner: -\n--\n\nCREATE EVENT TRIGGER pgrst_ddl_watch ON ddl_command_end\n   EXECUTE FUNCTION extensions.pgrst_ddl_watch();\n\n\n--\n-- Name: pgrst_drop_watch; Type: EVENT TRIGGER; Schema: -; Owner: -\n--\n\nCREATE EVENT TRIGGER pgrst_drop_watch ON sql_drop\n   EXECUTE FUNCTION extensions.pgrst_drop_watch();\n\n\n--\n-- PostgreSQL database dump complete\n--\n\n\n--\n-- Dbmate schema migrations\n--\n\n"
  },
  {
    "path": "data/db/row_level_security_polices.csv",
    "content": "schemaname,tablename,policyname,permissive,roles,cmd,qual,with_check\npublic,Profile,Public profiles are viewable by everyone.,PERMISSIVE,{public},SELECT,true,\npublic,Profile,Users can insert their own profile.,PERMISSIVE,{public},INSERT,,(auth.uid() = id)\npublic,Profile,Users can update own profile.,PERMISSIVE,{public},UPDATE,(auth.uid() = id),\nstorage,objects,Avatar images are publicly accessible.,PERMISSIVE,{public},SELECT,\"(bucket_id = 'avatars'::text)\",\nstorage,objects,Anyone can upload an avatar.,PERMISSIVE,{public},INSERT,,\"(bucket_id = 'avatars'::text)\"\nstorage,objects,Anyone can update an avatar.,PERMISSIVE,{public},UPDATE,,\"(bucket_id = 'avatars'::text)\"\npublic,Post,All users can view posts,PERMISSIVE,{public},SELECT,true,\npublic,Post,Only authenticated users can create posts,PERMISSIVE,{public},INSERT,,\"(auth.role() = 'authenticated'::text)\"\npublic,Post,Users can delete their own posts,PERMISSIVE,{public},DELETE,\"(auth.uid() = \"\"profileId\"\")\",\npublic,Post,Users can edit their own posts,PERMISSIVE,{public},UPDATE,\"(auth.uid() = \"\"profileId\"\")\",\"(auth.uid() = \"\"profileId\"\")\"\npublic,Comment,Everyone can view comments,PERMISSIVE,{public},SELECT,true,\npublic,Comment,Only authenticated users can comment,PERMISSIVE,{public},INSERT,,\"(auth.role() = 'authenticated'::text)\"\npublic,Comment,User can edit their own comments,PERMISSIVE,{public},UPDATE,\"(auth.uid() = \"\"profileId\"\")\",\"(auth.uid() = \"\"profileId\"\")\"\npublic,Comment,Users can delete their own comments,PERMISSIVE,{public},DELETE,\"(auth.uid() = \"\"profileId\"\")\",\npublic,Vote,Everyone can view votes,PERMISSIVE,{public},SELECT,true,\npublic,Vote,Only authenticated users can vote,PERMISSIVE,{public},INSERT,,\"(auth.role() = 'authenticated'::text)\"\npublic,Vote,Users can change their vote,PERMISSIVE,{public},UPDATE,\"(auth.uid() = \"\"profileId\"\")\",\"(auth.uid() = \"\"profileId\"\")\"\npublic,Vote,Users can delete their own votes,PERMISSIVE,{public},DELETE,\"(auth.uid() = \"\"profileId\"\")\","
  },
  {
    "path": "data/db/schema.sql",
    "content": "SET statement_timeout = 0;\nSET lock_timeout = 0;\nSET idle_in_transaction_session_timeout = 0;\nSET client_encoding = 'UTF8';\nSET standard_conforming_strings = on;\nSELECT pg_catalog.set_config('search_path', '', false);\nSET check_function_bodies = false;\nSET xmloption = content;\nSET client_min_messages = warning;\nSET row_security = off;\n\n--\n-- Name: auth; Type: SCHEMA; Schema: -; Owner: -\n--\n\nCREATE SCHEMA auth;\n\n\n--\n-- Name: extensions; Type: SCHEMA; Schema: -; Owner: -\n--\n\nCREATE SCHEMA extensions;\n\n\n--\n-- Name: pg_graphql; Type: EXTENSION; Schema: -; Owner: -\n--\n\nCREATE EXTENSION IF NOT EXISTS pg_graphql WITH SCHEMA public;\n\n\n--\n-- Name: EXTENSION pg_graphql; Type: COMMENT; Schema: -; Owner: -\n--\n\nCOMMENT ON EXTENSION pg_graphql IS 'GraphQL support';\n\n\n--\n-- Name: graphql_public; Type: SCHEMA; Schema: -; Owner: -\n--\n\nCREATE SCHEMA graphql_public;\n\n\n--\n-- Name: pg_net; Type: EXTENSION; Schema: -; Owner: -\n--\n\nCREATE EXTENSION IF NOT EXISTS pg_net WITH SCHEMA extensions;\n\n\n--\n-- Name: EXTENSION pg_net; Type: COMMENT; Schema: -; Owner: -\n--\n\nCOMMENT ON EXTENSION pg_net IS 'Async HTTP';\n\n\n--\n-- Name: pgbouncer; Type: SCHEMA; Schema: -; Owner: -\n--\n\nCREATE SCHEMA pgbouncer;\n\n\n--\n-- Name: realtime; Type: SCHEMA; Schema: -; Owner: -\n--\n\nCREATE SCHEMA realtime;\n\n\n--\n-- Name: storage; Type: SCHEMA; Schema: -; Owner: -\n--\n\nCREATE SCHEMA storage;\n\n\n--\n-- Name: supabase_functions; Type: SCHEMA; Schema: -; Owner: -\n--\n\nCREATE SCHEMA supabase_functions;\n\n\n--\n-- Name: pg_stat_statements; Type: EXTENSION; Schema: -; Owner: -\n--\n\nCREATE EXTENSION IF NOT EXISTS pg_stat_statements WITH SCHEMA extensions;\n\n\n--\n-- Name: EXTENSION pg_stat_statements; Type: COMMENT; Schema: -; Owner: -\n--\n\nCOMMENT ON EXTENSION pg_stat_statements IS 'track planning and execution statistics of all SQL statements executed';\n\n\n--\n-- Name: pgcrypto; Type: EXTENSION; Schema: -; Owner: -\n--\n\nCREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA extensions;\n\n\n--\n-- Name: EXTENSION pgcrypto; Type: COMMENT; Schema: -; Owner: -\n--\n\nCOMMENT ON EXTENSION pgcrypto IS 'cryptographic functions';\n\n\n--\n-- Name: pgjwt; Type: EXTENSION; Schema: -; Owner: -\n--\n\nCREATE EXTENSION IF NOT EXISTS pgjwt WITH SCHEMA extensions;\n\n\n--\n-- Name: EXTENSION pgjwt; Type: COMMENT; Schema: -; Owner: -\n--\n\nCOMMENT ON EXTENSION pgjwt IS 'JSON Web Token API for Postgresql';\n\n\n--\n-- Name: uuid-ossp; Type: EXTENSION; Schema: -; Owner: -\n--\n\nCREATE EXTENSION IF NOT EXISTS \"uuid-ossp\" WITH SCHEMA extensions;\n\n\n--\n-- Name: EXTENSION \"uuid-ossp\"; Type: COMMENT; Schema: -; Owner: -\n--\n\nCOMMENT ON EXTENSION \"uuid-ossp\" IS 'generate universally unique identifiers (UUIDs)';\n\n\n--\n-- Name: direction; Type: TYPE; Schema: public; Owner: -\n--\n\nCREATE TYPE public.direction AS ENUM (\n    'UP',\n    'DOWN'\n);\n\n\n--\n-- Name: action; Type: TYPE; Schema: realtime; Owner: -\n--\n\nCREATE TYPE realtime.action AS ENUM (\n    'INSERT',\n    'UPDATE',\n    'DELETE',\n    'TRUNCATE',\n    'ERROR'\n);\n\n\n--\n-- Name: equality_op; Type: TYPE; Schema: realtime; Owner: -\n--\n\nCREATE TYPE realtime.equality_op AS ENUM (\n    'eq',\n    'neq',\n    'lt',\n    'lte',\n    'gt',\n    'gte'\n);\n\n\n--\n-- Name: user_defined_filter; Type: TYPE; Schema: realtime; Owner: -\n--\n\nCREATE TYPE realtime.user_defined_filter AS (\n\tcolumn_name text,\n\top realtime.equality_op,\n\tvalue text\n);\n\n\n--\n-- Name: wal_column; Type: TYPE; Schema: realtime; Owner: -\n--\n\nCREATE TYPE realtime.wal_column AS (\n\tname text,\n\ttype text,\n\tvalue jsonb,\n\tis_pkey boolean,\n\tis_selectable boolean\n);\n\n\n--\n-- Name: wal_rls; Type: TYPE; Schema: realtime; Owner: -\n--\n\nCREATE TYPE realtime.wal_rls AS (\n\twal jsonb,\n\tis_rls_enabled boolean,\n\tsubscription_ids uuid[],\n\terrors text[]\n);\n\n\n--\n-- Name: email(); Type: FUNCTION; Schema: auth; Owner: -\n--\n\nCREATE FUNCTION auth.email() RETURNS text\n    LANGUAGE sql STABLE\n    AS $$\n  select\n  \tcoalesce(\n\t\tnullif(current_setting('request.jwt.claim.email', true), ''),\n\t\t(nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'email')\n\t)::text\n$$;\n\n\n--\n-- Name: role(); Type: FUNCTION; Schema: auth; Owner: -\n--\n\nCREATE FUNCTION auth.role() RETURNS text\n    LANGUAGE sql STABLE\n    AS $$\n  select\n  \tcoalesce(\n\t\tnullif(current_setting('request.jwt.claim.role', true), ''),\n\t\t(nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'role')\n\t)::text\n$$;\n\n\n--\n-- Name: uid(); Type: FUNCTION; Schema: auth; Owner: -\n--\n\nCREATE FUNCTION auth.uid() RETURNS uuid\n    LANGUAGE sql STABLE\n    AS $$\n  select\n  \tcoalesce(\n\t\tnullif(current_setting('request.jwt.claim.sub', true), ''),\n\t\t(nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'sub')\n\t)::uuid\n$$;\n\n\n--\n-- Name: grant_pg_cron_access(); Type: FUNCTION; Schema: extensions; Owner: -\n--\n\nCREATE FUNCTION extensions.grant_pg_cron_access() RETURNS event_trigger\n    LANGUAGE plpgsql\n    AS $$\nDECLARE\n  schema_is_cron bool;\nBEGIN\n  schema_is_cron = (\n    SELECT n.nspname = 'cron'\n    FROM pg_event_trigger_ddl_commands() AS ev\n    LEFT JOIN pg_catalog.pg_namespace AS n\n      ON ev.objid = n.oid\n  );\n\n  IF schema_is_cron\n  THEN\n    grant usage on schema cron to postgres with grant option;\n\n    alter default privileges in schema cron grant all on tables to postgres with grant option;\n    alter default privileges in schema cron grant all on functions to postgres with grant option;\n    alter default privileges in schema cron grant all on sequences to postgres with grant option;\n\n    alter default privileges for user supabase_admin in schema cron grant all\n        on sequences to postgres with grant option;\n    alter default privileges for user supabase_admin in schema cron grant all\n        on tables to postgres with grant option;\n    alter default privileges for user supabase_admin in schema cron grant all\n        on functions to postgres with grant option;\n\n    grant all privileges on all tables in schema cron to postgres with grant option;\n\n  END IF;\n\nEND;\n$$;\n\n\n--\n-- Name: FUNCTION grant_pg_cron_access(); Type: COMMENT; Schema: extensions; Owner: -\n--\n\nCOMMENT ON FUNCTION extensions.grant_pg_cron_access() IS 'Grants access to pg_cron';\n\n\n--\n-- Name: grant_pg_graphql_access(); Type: FUNCTION; Schema: extensions; Owner: -\n--\n\nCREATE FUNCTION extensions.grant_pg_graphql_access() RETURNS event_trigger\n    LANGUAGE plpgsql\n    AS $_$\n    DECLARE\n    func_is_graphql_resolve bool;\n    BEGIN\n    func_is_graphql_resolve = (\n        SELECT n.proname = 'resolve'\n        FROM pg_event_trigger_ddl_commands() AS ev\n        LEFT JOIN pg_catalog.pg_proc AS n\n        ON ev.objid = n.oid\n    );\n\n    IF func_is_graphql_resolve\n    THEN\n        grant usage on schema graphql to postgres, anon, authenticated, service_role;\n        grant all on function graphql.resolve to postgres, anon, authenticated, service_role;\n\n        alter default privileges in schema graphql grant all on tables to postgres, anon, authenticated, service_role;\n        alter default privileges in schema graphql grant all on functions to postgres, anon, authenticated, service_role;\n        alter default privileges in schema graphql grant all on sequences to postgres, anon, authenticated, service_role;\n\n        create or replace function graphql_public.graphql(\n            \"operationName\" text default null,\n            query text default null,\n            variables jsonb default null,\n            extensions jsonb default null\n        )\n            returns jsonb\n            language sql\n        as $$\n            SELECT graphql.resolve(query, coalesce(variables, '{}'));\n        $$;\n\n        grant select on graphql.field, graphql.type, graphql.enum_value to postgres, anon, authenticated, service_role;\n        grant execute on function graphql.resolve to postgres, anon, authenticated, service_role;\n    END IF;\n\n    END;\n$_$;\n\n\n--\n-- Name: FUNCTION grant_pg_graphql_access(); Type: COMMENT; Schema: extensions; Owner: -\n--\n\nCOMMENT ON FUNCTION extensions.grant_pg_graphql_access() IS 'Grants access to pg_graphql';\n\n\n--\n-- Name: grant_pg_net_access(); Type: FUNCTION; Schema: extensions; Owner: -\n--\n\nCREATE FUNCTION extensions.grant_pg_net_access() RETURNS event_trigger\n    LANGUAGE plpgsql\n    AS $$\n    BEGIN\n      IF EXISTS (\n        SELECT 1\n        FROM pg_event_trigger_ddl_commands() AS ev\n        JOIN pg_extension AS ext\n        ON ev.objid = ext.oid\n        WHERE ext.extname = 'pg_net'\n      )\n      THEN\n        GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role;\n\n        ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;\n        ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;\n        ALTER function net.http_collect_response(request_id bigint, async boolean) SECURITY DEFINER;\n\n        ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;\n        ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;\n        ALTER function net.http_collect_response(request_id bigint, async boolean) SET search_path = net;\n\n        REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;\n        REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;\n        REVOKE ALL ON FUNCTION net.http_collect_response(request_id bigint, async boolean) FROM PUBLIC;\n\n        GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;\n        GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;\n        GRANT EXECUTE ON FUNCTION net.http_collect_response(request_id bigint, async boolean) TO supabase_functions_admin, postgres, anon, authenticated, service_role;\n      END IF;\n    END;\n    $$;\n\n\n--\n-- Name: FUNCTION grant_pg_net_access(); Type: COMMENT; Schema: extensions; Owner: -\n--\n\nCOMMENT ON FUNCTION extensions.grant_pg_net_access() IS 'Grants access to pg_net';\n\n\n--\n-- Name: notify_api_restart(); Type: FUNCTION; Schema: extensions; Owner: -\n--\n\nCREATE FUNCTION extensions.notify_api_restart() RETURNS event_trigger\n    LANGUAGE plpgsql\n    AS $$\nBEGIN\n    NOTIFY pgrst, 'reload schema';\nEND;\n$$;\n\n\n--\n-- Name: FUNCTION notify_api_restart(); Type: COMMENT; Schema: extensions; Owner: -\n--\n\nCOMMENT ON FUNCTION extensions.notify_api_restart() IS 'Sends a notification to the API to restart. If your database schema has changed, this is required so that Supabase can rebuild the relationships.';\n\n\n--\n-- Name: pgrst_ddl_watch(); Type: FUNCTION; Schema: extensions; Owner: -\n--\n\nCREATE FUNCTION extensions.pgrst_ddl_watch() RETURNS event_trigger\n    LANGUAGE plpgsql\n    AS $$\nDECLARE\n  cmd record;\nBEGIN\n  FOR cmd IN SELECT * FROM pg_event_trigger_ddl_commands()\n  LOOP\n    IF cmd.command_tag IN (\n      'CREATE SCHEMA', 'ALTER SCHEMA'\n    , 'CREATE TABLE', 'CREATE TABLE AS', 'SELECT INTO', 'ALTER TABLE'\n    , 'CREATE FOREIGN TABLE', 'ALTER FOREIGN TABLE'\n    , 'CREATE VIEW', 'ALTER VIEW'\n    , 'CREATE MATERIALIZED VIEW', 'ALTER MATERIALIZED VIEW'\n    , 'CREATE FUNCTION', 'ALTER FUNCTION'\n    , 'CREATE TRIGGER'\n    , 'CREATE TYPE', 'ALTER TYPE'\n    , 'CREATE RULE'\n    , 'COMMENT'\n    )\n    -- don't notify in case of CREATE TEMP table or other objects created on pg_temp\n    AND cmd.schema_name is distinct from 'pg_temp'\n    THEN\n      NOTIFY pgrst, 'reload schema';\n    END IF;\n  END LOOP;\nEND; $$;\n\n\n--\n-- Name: pgrst_drop_watch(); Type: FUNCTION; Schema: extensions; Owner: -\n--\n\nCREATE FUNCTION extensions.pgrst_drop_watch() RETURNS event_trigger\n    LANGUAGE plpgsql\n    AS $$\nDECLARE\n  obj record;\nBEGIN\n  FOR obj IN SELECT * FROM pg_event_trigger_dropped_objects()\n  LOOP\n    IF obj.object_type IN (\n      'schema'\n    , 'table'\n    , 'foreign table'\n    , 'view'\n    , 'materialized view'\n    , 'function'\n    , 'trigger'\n    , 'type'\n    , 'rule'\n    )\n    AND obj.is_temporary IS false -- no pg_temp objects\n    THEN\n      NOTIFY pgrst, 'reload schema';\n    END IF;\n  END LOOP;\nEND; $$;\n\n\n--\n-- Name: set_graphql_placeholder(); Type: FUNCTION; Schema: extensions; Owner: -\n--\n\nCREATE FUNCTION extensions.set_graphql_placeholder() RETURNS event_trigger\n    LANGUAGE plpgsql\n    AS $_$\n    DECLARE\n    graphql_is_dropped bool;\n    BEGIN\n    graphql_is_dropped = (\n        SELECT ev.schema_name = 'graphql_public'\n        FROM pg_event_trigger_dropped_objects() AS ev\n        WHERE ev.schema_name = 'graphql_public'\n    );\n\n    IF graphql_is_dropped\n    THEN\n        create or replace function graphql_public.graphql(\n            \"operationName\" text default null,\n            query text default null,\n            variables jsonb default null,\n            extensions jsonb default null\n        )\n            returns jsonb\n            language plpgsql\n        as $$\n            DECLARE\n                server_version float;\n            BEGIN\n                server_version = (SELECT (SPLIT_PART((select version()), ' ', 2))::float);\n\n                IF server_version >= 14 THEN\n                    RETURN jsonb_build_object(\n                        'data', null::jsonb,\n                        'errors', array['pg_graphql extension is not enabled.']\n                    );\n                ELSE\n                    RETURN jsonb_build_object(\n                        'data', null::jsonb,\n                        'errors', array['pg_graphql is only available on projects running Postgres 14 onwards.']\n                    );\n                END IF;\n            END;\n        $$;\n    END IF;\n\n    END;\n$_$;\n\n\n--\n-- Name: FUNCTION set_graphql_placeholder(); Type: COMMENT; Schema: extensions; Owner: -\n--\n\nCOMMENT ON FUNCTION extensions.set_graphql_placeholder() IS 'Reintroduces placeholder function for graphql_public.graphql';\n\n\n--\n-- Name: get_auth(text); Type: FUNCTION; Schema: pgbouncer; Owner: -\n--\n\nCREATE FUNCTION pgbouncer.get_auth(p_usename text) RETURNS TABLE(username text, password text)\n    LANGUAGE plpgsql SECURITY DEFINER\n    AS $$\nBEGIN\n    RAISE WARNING 'PgBouncer auth request: %', p_usename;\n\n    RETURN QUERY\n    SELECT usename::TEXT, passwd::TEXT FROM pg_catalog.pg_shadow\n    WHERE usename = p_usename;\nEND;\n$$;\n\n\n--\n-- Name: graphql(text, text, jsonb, jsonb); Type: FUNCTION; Schema: public; Owner: -\n--\n\nCREATE FUNCTION public.graphql(\"operationName\" text DEFAULT NULL::text, query text DEFAULT NULL::text, variables jsonb DEFAULT NULL::jsonb, extensions jsonb DEFAULT NULL::jsonb) RETURNS jsonb\n    LANGUAGE sql\n    AS $$\n    select graphql.resolve(query, coalesce(variables, '{}'));\n$$;\n\n\n--\n-- Name: handle_new_user(); Type: FUNCTION; Schema: public; Owner: -\n--\n\nCREATE FUNCTION public.handle_new_user() RETURNS trigger\n    LANGUAGE plpgsql SECURITY DEFINER\n    AS $$\nbegin\n  insert into public.\"Profile\" (id, \"avatarUrl\", username)\n  values (new.id, 'https://www.gravatar.com/avatar/' || md5(new.email) || '?d=mp', split_part(new.email, '@', 1) || '-' || floor(random() * 10000));\n  return new;\nend;\n$$;\n\n\n--\n-- Name: update_vote_counts(); Type: FUNCTION; Schema: public; Owner: -\n--\n\nCREATE FUNCTION public.update_vote_counts() RETURNS trigger\n    LANGUAGE plpgsql SECURITY DEFINER\n    AS $$\nBEGIN\n\nWITH r AS (\nSELECT\n\tcoalesce(\"Vote\".\"postId\", \"Post\".id) AS \"postId\",\n\tcount(1) \"voteTotal\",\n\tcount(1) FILTER (WHERE direction = 'UP') \"upVoteTotal\",\n\tcount(1) FILTER (WHERE direction = 'DOWN') \"downVoteTotal\",\n\tcoalesce(sum(\n\t\t\tCASE WHEN direction = 'UP' THEN\n\t\t\t\t1\n\t\t\tWHEN direction = 'DOWN' THEN\n\t\t\t\t-1\n\t\t\tELSE\n\t\t\t\t0\n\t\t\tEND), 0) \"voteDelta\",\n\tround(coalesce((sum(\n\t\tCASE WHEN direction = 'UP' THEN\n\t\t\t1\n\t\tWHEN direction = 'DOWN' THEN\n\t\t\t-1\n\t\tELSE\n\t\t\t0\n\t\tEND ) - 1) / (DATE_PART('hour', now() - max(\"Vote\".\"createdAt\")) + 2) ^ 1.8 * 100000, -2147483648)::numeric, 0) AS \"score\",\n\trank() OVER (ORDER BY round(coalesce((sum( CASE WHEN direction = 'UP' THEN\n\t\t\t1\n\t\tWHEN direction = 'DOWN' THEN\n\t\t\t-1\n\t\tELSE\n\t\t\t0\n\t\tEND) - 1) / (DATE_PART('hour', now() - max(\"Vote\".\"createdAt\")) + 2) ^ 1.8 * 100000, -2147483648)::numeric, 0)\n\t\tDESC,\n\t\t\"Post\".\"createdAt\" DESC,\n\t\t\"Post\".title ASC) \"voteRank\"\nFROM\n\t\"Vote\"\n\tRIGHT JOIN \"Post\" ON \"Vote\".\"postId\" = \"Post\".id\nGROUP BY\n\t\"Post\".id,\n\t\"Vote\".\"postId\"\n)\n\nUPDATE\n\tpublic. \"Post\"\nSET\n\t\"upVoteTotal\" = r. \"upVoteTotal\",\n\t\"downVoteTotal\" = r. \"downVoteTotal\",\n\t\"voteTotal\" = r. \"voteTotal\",\n  \"voteDelta\" = r. \"voteDelta\",\n\t\"voteRank\" = r. \"voteRank\",\n  \"score\" = r. \"score\"\nFROM\n\tr\nWHERE\n\tr.\"postId\" = public. \"Post\".id;\n\nRETURN new;\nEND;\n$$;\n\n\n--\n-- Name: apply_rls(jsonb, integer); Type: FUNCTION; Schema: realtime; Owner: -\n--\n\nCREATE FUNCTION realtime.apply_rls(wal jsonb, max_record_bytes integer DEFAULT (1024 * 1024)) RETURNS SETOF realtime.wal_rls\n    LANGUAGE plpgsql\n    AS $$\n      declare\n        -- Regclass of the table e.g. public.notes\n        entity_ regclass = (quote_ident(wal ->> 'schema') || '.' || quote_ident(wal ->> 'table'))::regclass;\n\n        -- I, U, D, T: insert, update ...\n        action realtime.action = (\n          case wal ->> 'action'\n            when 'I' then 'INSERT'\n            when 'U' then 'UPDATE'\n            when 'D' then 'DELETE'\n            else 'ERROR'\n          end\n        );\n\n        -- Is row level security enabled for the table\n        is_rls_enabled bool = relrowsecurity from pg_class where oid = entity_;\n\n        subscriptions realtime.subscription[] = array_agg(subs)\n          from\n            realtime.subscription subs\n          where\n            subs.entity = entity_;\n\n        -- Subscription vars\n        roles regrole[] = array_agg(distinct us.claims_role)\n          from\n            unnest(subscriptions) us;\n\n        working_role regrole;\n        claimed_role regrole;\n        claims jsonb;\n\n        subscription_id uuid;\n        subscription_has_access bool;\n        visible_to_subscription_ids uuid[] = '{}';\n\n        -- structured info for wal's columns\n        columns realtime.wal_column[];\n        -- previous identity values for update/delete\n        old_columns realtime.wal_column[];\n\n        error_record_exceeds_max_size boolean = octet_length(wal::text) > max_record_bytes;\n\n        -- Primary jsonb output for record\n        output jsonb;\n\n      begin\n        perform set_config('role', null, true);\n\n        columns =\n          array_agg(\n            (\n              x->>'name',\n              x->>'type',\n              realtime.cast((x->'value') #>> '{}', (x->>'type')::regtype),\n              (pks ->> 'name') is not null,\n              true\n            )::realtime.wal_column\n          )\n          from\n            jsonb_array_elements(wal -> 'columns') x\n            left join jsonb_array_elements(wal -> 'pk') pks\n              on (x ->> 'name') = (pks ->> 'name');\n\n        old_columns =\n          array_agg(\n            (\n              x->>'name',\n              x->>'type',\n              realtime.cast((x->'value') #>> '{}', (x->>'type')::regtype),\n              (pks ->> 'name') is not null,\n              true\n            )::realtime.wal_column\n          )\n          from\n            jsonb_array_elements(wal -> 'identity') x\n            left join jsonb_array_elements(wal -> 'pk') pks\n              on (x ->> 'name') = (pks ->> 'name');\n\n        for working_role in select * from unnest(roles) loop\n\n          -- Update `is_selectable` for columns and old_columns\n          columns =\n            array_agg(\n              (\n                c.name,\n                c.type,\n                c.value,\n                c.is_pkey,\n                pg_catalog.has_column_privilege(working_role, entity_, c.name, 'SELECT')\n              )::realtime.wal_column\n            )\n            from\n              unnest(columns) c;\n\n          old_columns =\n            array_agg(\n              (\n                c.name,\n                c.type,\n                c.value,\n                c.is_pkey,\n                pg_catalog.has_column_privilege(working_role, entity_, c.name, 'SELECT')\n              )::realtime.wal_column\n            )\n            from\n              unnest(old_columns) c;\n\n          if action <> 'DELETE' and count(1) = 0 from unnest(columns) c where c.is_pkey then\n            return next (\n              null,\n              is_rls_enabled,\n              -- subscriptions is already filtered by entity\n              (select array_agg(s.subscription_id) from unnest(subscriptions) as s where claims_role = working_role),\n              array['Error 400: Bad Request, no primary key']\n            )::realtime.wal_rls;\n\n          -- The claims role does not have SELECT permission to the primary key of entity\n          elsif action <> 'DELETE' and sum(c.is_selectable::int) <> count(1) from unnest(columns) c where c.is_pkey then\n            return next (\n              null,\n              is_rls_enabled,\n              (select array_agg(s.subscription_id) from unnest(subscriptions) as s where claims_role = working_role),\n              array['Error 401: Unauthorized']\n            )::realtime.wal_rls;\n\n          else\n            output = jsonb_build_object(\n              'schema', wal ->> 'schema',\n              'table', wal ->> 'table',\n              'type', action,\n              'commit_timestamp', to_char(\n                (wal ->> 'timestamp')::timestamptz,\n                'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"'\n              ),\n              'columns', (\n                select\n                  jsonb_agg(\n                    jsonb_build_object(\n                      'name', pa.attname,\n                      'type', pt.typname\n                    )\n                    order by pa.attnum asc\n                  )\n                    from\n                      pg_attribute pa\n                      join pg_type pt\n                        on pa.atttypid = pt.oid\n                    where\n                      attrelid = entity_\n                      and attnum > 0\n                      and pg_catalog.has_column_privilege(working_role, entity_, pa.attname, 'SELECT')\n              )\n            )\n            -- Add \"record\" key for insert and update\n            || case\n                when error_record_exceeds_max_size then jsonb_build_object('record', '{}'::jsonb)\n                when action in ('INSERT', 'UPDATE') then\n                  jsonb_build_object(\n                    'record',\n                    (select jsonb_object_agg((c).name, (c).value) from unnest(columns) c where (c).is_selectable)\n                  )\n                else '{}'::jsonb\n            end\n            -- Add \"old_record\" key for update and delete\n            || case\n                when error_record_exceeds_max_size then jsonb_build_object('old_record', '{}'::jsonb)\n                when action in ('UPDATE', 'DELETE') then\n                  jsonb_build_object(\n                    'old_record',\n                    (select jsonb_object_agg((c).name, (c).value) from unnest(old_columns) c where (c).is_selectable)\n                  )\n                else '{}'::jsonb\n            end;\n\n            -- Create the prepared statement\n            if is_rls_enabled and action <> 'DELETE' then\n              if (select 1 from pg_prepared_statements where name = 'walrus_rls_stmt' limit 1) > 0 then\n                deallocate walrus_rls_stmt;\n              end if;\n              execute realtime.build_prepared_statement_sql('walrus_rls_stmt', entity_, columns);\n            end if;\n\n            visible_to_subscription_ids = '{}';\n\n            for subscription_id, claims in (\n                select\n                  subs.subscription_id,\n                  subs.claims\n                from\n                  unnest(subscriptions) subs\n                where\n                  subs.entity = entity_\n                  and subs.claims_role = working_role\n                  and realtime.is_visible_through_filters(columns, subs.filters)\n              ) loop\n\n              if not is_rls_enabled or action = 'DELETE' then\n                visible_to_subscription_ids = visible_to_subscription_ids || subscription_id;\n              else\n                -- Check if RLS allows the role to see the record\n                perform\n                  set_config('role', working_role::text, true),\n                  set_config('request.jwt.claims', claims::text, true);\n\n                execute 'execute walrus_rls_stmt' into subscription_has_access;\n\n                if subscription_has_access then\n                  visible_to_subscription_ids = visible_to_subscription_ids || subscription_id;\n                end if;\n              end if;\n            end loop;\n\n            perform set_config('role', null, true);\n\n            return next (\n              output,\n              is_rls_enabled,\n              visible_to_subscription_ids,\n              case\n                when error_record_exceeds_max_size then array['Error 413: Payload Too Large']\n                else '{}'\n              end\n            )::realtime.wal_rls;\n\n          end if;\n        end loop;\n\n        perform set_config('role', null, true);\n      end;\n      $$;\n\n\n--\n-- Name: build_prepared_statement_sql(text, regclass, realtime.wal_column[]); Type: FUNCTION; Schema: realtime; Owner: -\n--\n\nCREATE FUNCTION realtime.build_prepared_statement_sql(prepared_statement_name text, entity regclass, columns realtime.wal_column[]) RETURNS text\n    LANGUAGE sql\n    AS $$\n    /*\n    Builds a sql string that, if executed, creates a prepared statement to\n    tests retrive a row from *entity* by its primary key columns.\n\n    Example\n      select realtime.build_prepared_statment_sql('public.notes', '{\"id\"}'::text[], '{\"bigint\"}'::text[])\n    */\n      select\n    'prepare ' || prepared_statement_name || ' as\n      select\n        exists(\n          select\n            1\n          from\n            ' || entity || '\n          where\n            ' || string_agg(quote_ident(pkc.name) || '=' || quote_nullable(pkc.value #>> '{}') , ' and ') || '\n        )'\n      from\n        unnest(columns) pkc\n      where\n        pkc.is_pkey\n      group by\n        entity\n    $$;\n\n\n--\n-- Name: cast(text, regtype); Type: FUNCTION; Schema: realtime; Owner: -\n--\n\nCREATE FUNCTION realtime.\"cast\"(val text, type_ regtype) RETURNS jsonb\n    LANGUAGE plpgsql IMMUTABLE\n    AS $$\n    declare\n      res jsonb;\n    begin\n      execute format('select to_jsonb(%L::'|| type_::text || ')', val)  into res;\n      return res;\n    end\n    $$;\n\n\n--\n-- Name: check_equality_op(realtime.equality_op, regtype, text, text); Type: FUNCTION; Schema: realtime; Owner: -\n--\n\nCREATE FUNCTION realtime.check_equality_op(op realtime.equality_op, type_ regtype, val_1 text, val_2 text) RETURNS boolean\n    LANGUAGE plpgsql IMMUTABLE\n    AS $$\n    /*\n    Casts *val_1* and *val_2* as type *type_* and check the *op* condition for truthiness\n    */\n    declare\n      op_symbol text = (\n        case\n          when op = 'eq' then '='\n          when op = 'neq' then '!='\n          when op = 'lt' then '<'\n          when op = 'lte' then '<='\n          when op = 'gt' then '>'\n          when op = 'gte' then '>='\n          else 'UNKNOWN OP'\n        end\n      );\n      res boolean;\n    begin\n      execute format('select %L::'|| type_::text || ' ' || op_symbol || ' %L::'|| type_::text, val_1, val_2) into res;\n      return res;\n    end;\n    $$;\n\n\n--\n-- Name: is_visible_through_filters(realtime.wal_column[], realtime.user_defined_filter[]); Type: FUNCTION; Schema: realtime; Owner: -\n--\n\nCREATE FUNCTION realtime.is_visible_through_filters(columns realtime.wal_column[], filters realtime.user_defined_filter[]) RETURNS boolean\n    LANGUAGE sql IMMUTABLE\n    AS $$\n    /*\n    Should the record be visible (true) or filtered out (false) after *filters* are applied\n    */\n    select\n      -- Default to allowed when no filters present\n      coalesce(\n        sum(\n          realtime.check_equality_op(\n            op:=f.op,\n            type_:=col.type::regtype,\n            -- cast jsonb to text\n            val_1:=col.value #>> '{}',\n            val_2:=f.value\n          )::int\n        ) = count(1),\n        true\n      )\n    from\n      unnest(filters) f\n      join unnest(columns) col\n          on f.column_name = col.name;\n    $$;\n\n\n--\n-- Name: quote_wal2json(regclass); Type: FUNCTION; Schema: realtime; Owner: -\n--\n\nCREATE FUNCTION realtime.quote_wal2json(entity regclass) RETURNS text\n    LANGUAGE sql IMMUTABLE STRICT\n    AS $$\n      select\n        (\n          select string_agg('' || ch,'')\n          from unnest(string_to_array(nsp.nspname::text, null)) with ordinality x(ch, idx)\n          where\n            not (x.idx = 1 and x.ch = '\"')\n            and not (\n              x.idx = array_length(string_to_array(nsp.nspname::text, null), 1)\n              and x.ch = '\"'\n            )\n        )\n        || '.'\n        || (\n          select string_agg('' || ch,'')\n          from unnest(string_to_array(pc.relname::text, null)) with ordinality x(ch, idx)\n          where\n            not (x.idx = 1 and x.ch = '\"')\n            and not (\n              x.idx = array_length(string_to_array(nsp.nspname::text, null), 1)\n              and x.ch = '\"'\n            )\n          )\n      from\n        pg_class pc\n        join pg_namespace nsp\n          on pc.relnamespace = nsp.oid\n      where\n        pc.oid = entity\n    $$;\n\n\n--\n-- Name: subscription_check_filters(); Type: FUNCTION; Schema: realtime; Owner: -\n--\n\nCREATE FUNCTION realtime.subscription_check_filters() RETURNS trigger\n    LANGUAGE plpgsql\n    AS $$\n    /*\n    Validates that the user defined filters for a subscription:\n    - refer to valid columns that the claimed role may access\n    - values are coercable to the correct column type\n    */\n    declare\n      col_names text[] = coalesce(\n        array_agg(c.column_name order by c.ordinal_position),\n        '{}'::text[]\n      )\n      from\n        information_schema.columns c\n      where\n        format('%I.%I', c.table_schema, c.table_name)::regclass = new.entity\n        and pg_catalog.has_column_privilege(\n          (new.claims ->> 'role'),\n          format('%I.%I', c.table_schema, c.table_name)::regclass,\n          c.column_name,\n          'SELECT'\n        );\n      filter realtime.user_defined_filter;\n      col_type regtype;\n    begin\n      for filter in select * from unnest(new.filters) loop\n        -- Filtered column is valid\n        if not filter.column_name = any(col_names) then\n          raise exception 'invalid column for filter %', filter.column_name;\n        end if;\n\n        -- Type is sanitized and safe for string interpolation\n        col_type = (\n          select atttypid::regtype\n          from pg_catalog.pg_attribute\n          where attrelid = new.entity\n            and attname = filter.column_name\n        );\n        if col_type is null then\n          raise exception 'failed to lookup type for column %', filter.column_name;\n        end if;\n        -- raises an exception if value is not coercable to type\n        perform realtime.cast(filter.value, col_type);\n      end loop;\n\n      -- Apply consistent order to filters so the unique constraint on\n      -- (subscription_id, entity, filters) can't be tricked by a different filter order\n      new.filters = coalesce(\n        array_agg(f order by f.column_name, f.op, f.value),\n        '{}'\n      ) from unnest(new.filters) f;\n\n    return new;\n  end;\n  $$;\n\n\n--\n-- Name: to_regrole(text); Type: FUNCTION; Schema: realtime; Owner: -\n--\n\nCREATE FUNCTION realtime.to_regrole(role_name text) RETURNS regrole\n    LANGUAGE sql IMMUTABLE\n    AS $$ select role_name::regrole $$;\n\n\n--\n-- Name: extension(text); Type: FUNCTION; Schema: storage; Owner: -\n--\n\nCREATE FUNCTION storage.extension(name text) RETURNS text\n    LANGUAGE plpgsql\n    AS $$\nDECLARE\n_parts text[];\n_filename text;\nBEGIN\n\tselect string_to_array(name, '/') into _parts;\n\tselect _parts[array_length(_parts,1)] into _filename;\n\t-- @todo return the last part instead of 2\n\treturn split_part(_filename, '.', 2);\nEND\n$$;\n\n\n--\n-- Name: filename(text); Type: FUNCTION; Schema: storage; Owner: -\n--\n\nCREATE FUNCTION storage.filename(name text) RETURNS text\n    LANGUAGE plpgsql\n    AS $$\nDECLARE\n_parts text[];\nBEGIN\n\tselect string_to_array(name, '/') into _parts;\n\treturn _parts[array_length(_parts,1)];\nEND\n$$;\n\n\n--\n-- Name: foldername(text); Type: FUNCTION; Schema: storage; Owner: -\n--\n\nCREATE FUNCTION storage.foldername(name text) RETURNS text[]\n    LANGUAGE plpgsql\n    AS $$\nDECLARE\n_parts text[];\nBEGIN\n\tselect string_to_array(name, '/') into _parts;\n\treturn _parts[1:array_length(_parts,1)-1];\nEND\n$$;\n\n\n--\n-- Name: get_size_by_bucket(); Type: FUNCTION; Schema: storage; Owner: -\n--\n\nCREATE FUNCTION storage.get_size_by_bucket() RETURNS TABLE(size bigint, bucket_id text)\n    LANGUAGE plpgsql\n    AS $$\nBEGIN\n    return query\n        select sum((metadata->>'size')::int) as size, obj.bucket_id\n        from \"storage\".objects as obj\n        group by obj.bucket_id;\nEND\n$$;\n\n\n--\n-- Name: search(text, text, integer, integer, integer, text, text, text); Type: FUNCTION; Schema: storage; Owner: -\n--\n\nCREATE FUNCTION storage.search(prefix text, bucketname text, limits integer DEFAULT 100, levels integer DEFAULT 1, offsets integer DEFAULT 0, search text DEFAULT ''::text, sortcolumn text DEFAULT 'name'::text, sortorder text DEFAULT 'asc'::text) RETURNS TABLE(name text, id uuid, updated_at timestamp with time zone, created_at timestamp with time zone, last_accessed_at timestamp with time zone, metadata jsonb)\n    LANGUAGE plpgsql STABLE\n    AS $_$\ndeclare\n  v_order_by text;\n  v_sort_order text;\nbegin\n  case\n    when sortcolumn = 'name' then\n      v_order_by = 'name';\n    when sortcolumn = 'updated_at' then\n      v_order_by = 'updated_at';\n    when sortcolumn = 'created_at' then\n      v_order_by = 'created_at';\n    when sortcolumn = 'last_accessed_at' then\n      v_order_by = 'last_accessed_at';\n    else\n      v_order_by = 'name';\n  end case;\n\n  case\n    when sortorder = 'asc' then\n      v_sort_order = 'asc';\n    when sortorder = 'desc' then\n      v_sort_order = 'desc';\n    else\n      v_sort_order = 'asc';\n  end case;\n\n  v_order_by = v_order_by || ' ' || v_sort_order;\n\n  return query execute\n    'with folders as (\n       select path_tokens[$1] as folder\n       from storage.objects\n         where objects.name ilike $2 || $3 || ''%''\n           and bucket_id = $4\n           and array_length(regexp_split_to_array(objects.name, ''/''), 1) <> $1\n       group by folder\n       order by folder ' || v_sort_order || '\n     )\n     (select folder as \"name\",\n            null as id,\n            null as updated_at,\n            null as created_at,\n            null as last_accessed_at,\n            null as metadata from folders)\n     union all\n     (select path_tokens[$1] as \"name\",\n            id,\n            updated_at,\n            created_at,\n            last_accessed_at,\n            metadata\n     from storage.objects\n     where objects.name ilike $2 || $3 || ''%''\n       and bucket_id = $4\n       and array_length(regexp_split_to_array(objects.name, ''/''), 1) = $1\n     order by ' || v_order_by || ')\n     limit $5\n     offset $6' using levels, prefix, search, bucketname, limits, offsets;\nend;\n$_$;\n\n\n--\n-- Name: http_request(); Type: FUNCTION; Schema: supabase_functions; Owner: -\n--\n\nCREATE FUNCTION supabase_functions.http_request() RETURNS trigger\n    LANGUAGE plpgsql SECURITY DEFINER\n    SET search_path TO 'supabase_functions'\n    AS $$\n      DECLARE\n        request_id bigint;\n        payload jsonb;\n        url text := TG_ARGV[0]::text;\n        method text := TG_ARGV[1]::text;\n        headers jsonb DEFAULT '{}'::jsonb;\n        params jsonb DEFAULT '{}'::jsonb;\n        timeout_ms integer DEFAULT 1000;\n      BEGIN\n        IF url IS NULL OR url = 'null' THEN\n          RAISE EXCEPTION 'url argument is missing';\n        END IF;\n\n        IF method IS NULL OR method = 'null' THEN\n          RAISE EXCEPTION 'method argument is missing';\n        END IF;\n\n        IF TG_ARGV[2] IS NULL OR TG_ARGV[2] = 'null' THEN\n          headers = '{\"Content-Type\": \"application/json\"}'::jsonb;\n        ELSE\n          headers = TG_ARGV[2]::jsonb;\n        END IF;\n\n        IF TG_ARGV[3] IS NULL OR TG_ARGV[3] = 'null' THEN\n          params = '{}'::jsonb;\n        ELSE\n          params = TG_ARGV[3]::jsonb;\n        END IF;\n\n        IF TG_ARGV[4] IS NULL OR TG_ARGV[4] = 'null' THEN\n          timeout_ms = 1000;\n        ELSE\n          timeout_ms = TG_ARGV[4]::integer;\n        END IF;\n\n        CASE\n          WHEN method = 'GET' THEN\n            SELECT http_get INTO request_id FROM net.http_get(\n              url,\n              params,\n              headers,\n              timeout_ms\n            );\n          WHEN method = 'POST' THEN\n            payload = jsonb_build_object(\n              'old_record', OLD,\n              'record', NEW,\n              'type', TG_OP,\n              'table', TG_TABLE_NAME,\n              'schema', TG_TABLE_SCHEMA\n            );\n\n            SELECT http_post INTO request_id FROM net.http_post(\n              url,\n              payload,\n              params,\n              headers,\n              timeout_ms\n            );\n          ELSE\n            RAISE EXCEPTION 'method argument % is invalid', method;\n        END CASE;\n\n        INSERT INTO supabase_functions.hooks\n          (hook_table_id, hook_name, request_id)\n        VALUES\n          (TG_RELID, TG_NAME, request_id);\n\n        RETURN NEW;\n      END\n    $$;\n\n\nSET default_tablespace = '';\n\nSET default_table_access_method = heap;\n\n--\n-- Name: audit_log_entries; Type: TABLE; Schema: auth; Owner: -\n--\n\nCREATE TABLE auth.audit_log_entries (\n    instance_id uuid,\n    id uuid NOT NULL,\n    payload json,\n    created_at timestamp with time zone\n);\n\n\n--\n-- Name: TABLE audit_log_entries; Type: COMMENT; Schema: auth; Owner: -\n--\n\nCOMMENT ON TABLE auth.audit_log_entries IS 'Auth: Audit trail for user actions.';\n\n\n--\n-- Name: identities; Type: TABLE; Schema: auth; Owner: -\n--\n\nCREATE TABLE auth.identities (\n    id text NOT NULL,\n    user_id uuid NOT NULL,\n    identity_data jsonb NOT NULL,\n    provider text NOT NULL,\n    last_sign_in_at timestamp with time zone,\n    created_at timestamp with time zone,\n    updated_at timestamp with time zone\n);\n\n\n--\n-- Name: TABLE identities; Type: COMMENT; Schema: auth; Owner: -\n--\n\nCOMMENT ON TABLE auth.identities IS 'Auth: Stores identities associated to a user.';\n\n\n--\n-- Name: instances; Type: TABLE; Schema: auth; Owner: -\n--\n\nCREATE TABLE auth.instances (\n    id uuid NOT NULL,\n    uuid uuid,\n    raw_base_config text,\n    created_at timestamp with time zone,\n    updated_at timestamp with time zone\n);\n\n\n--\n-- Name: TABLE instances; Type: COMMENT; Schema: auth; Owner: -\n--\n\nCOMMENT ON TABLE auth.instances IS 'Auth: Manages users across multiple sites.';\n\n\n--\n-- Name: refresh_tokens; Type: TABLE; Schema: auth; Owner: -\n--\n\nCREATE TABLE auth.refresh_tokens (\n    instance_id uuid,\n    id bigint NOT NULL,\n    token character varying(255),\n    user_id character varying(255),\n    revoked boolean,\n    created_at timestamp with time zone,\n    updated_at timestamp with time zone,\n    parent character varying(255)\n);\n\n\n--\n-- Name: TABLE refresh_tokens; Type: COMMENT; Schema: auth; Owner: -\n--\n\nCOMMENT ON TABLE auth.refresh_tokens IS 'Auth: Store of tokens used to refresh JWT tokens once they expire.';\n\n\n--\n-- Name: refresh_tokens_id_seq; Type: SEQUENCE; Schema: auth; Owner: -\n--\n\nCREATE SEQUENCE auth.refresh_tokens_id_seq\n    START WITH 1\n    INCREMENT BY 1\n    NO MINVALUE\n    NO MAXVALUE\n    CACHE 1;\n\n\n--\n-- Name: refresh_tokens_id_seq; Type: SEQUENCE OWNED BY; Schema: auth; Owner: -\n--\n\nALTER SEQUENCE auth.refresh_tokens_id_seq OWNED BY auth.refresh_tokens.id;\n\n\n--\n-- Name: schema_migrations; Type: TABLE; Schema: auth; Owner: -\n--\n\nCREATE TABLE auth.schema_migrations (\n    version character varying(255) NOT NULL\n);\n\n\n--\n-- Name: TABLE schema_migrations; Type: COMMENT; Schema: auth; Owner: -\n--\n\nCOMMENT ON TABLE auth.schema_migrations IS 'Auth: Manages updates to the auth system.';\n\n\n--\n-- Name: users; Type: TABLE; Schema: auth; Owner: -\n--\n\nCREATE TABLE auth.users (\n    instance_id uuid,\n    id uuid NOT NULL,\n    aud character varying(255),\n    role character varying(255),\n    email character varying(255),\n    encrypted_password character varying(255),\n    email_confirmed_at timestamp with time zone,\n    invited_at timestamp with time zone,\n    confirmation_token character varying(255),\n    confirmation_sent_at timestamp with time zone,\n    recovery_token character varying(255),\n    recovery_sent_at timestamp with time zone,\n    email_change_token_new character varying(255),\n    email_change character varying(255),\n    email_change_sent_at timestamp with time zone,\n    last_sign_in_at timestamp with time zone,\n    raw_app_meta_data jsonb,\n    raw_user_meta_data jsonb,\n    is_super_admin boolean,\n    created_at timestamp with time zone,\n    updated_at timestamp with time zone,\n    phone character varying(15) DEFAULT NULL::character varying,\n    phone_confirmed_at timestamp with time zone,\n    phone_change character varying(15) DEFAULT ''::character varying,\n    phone_change_token character varying(255) DEFAULT ''::character varying,\n    phone_change_sent_at timestamp with time zone,\n    confirmed_at timestamp with time zone GENERATED ALWAYS AS (LEAST(email_confirmed_at, phone_confirmed_at)) STORED,\n    email_change_token_current character varying(255) DEFAULT ''::character varying,\n    email_change_confirm_status smallint DEFAULT 0,\n    banned_until timestamp with time zone,\n    reauthentication_token character varying(255) DEFAULT ''::character varying,\n    reauthentication_sent_at timestamp with time zone,\n    CONSTRAINT users_email_change_confirm_status_check CHECK (((email_change_confirm_status >= 0) AND (email_change_confirm_status <= 2)))\n);\n\n\n--\n-- Name: TABLE users; Type: COMMENT; Schema: auth; Owner: -\n--\n\nCOMMENT ON TABLE auth.users IS 'Auth: Stores user login data within a secure schema.';\n\n\n--\n-- Name: Comment; Type: TABLE; Schema: public; Owner: -\n--\n\nCREATE TABLE public.\"Comment\" (\n    id bigint NOT NULL,\n    \"createdAt\" timestamp with time zone DEFAULT now(),\n    \"updatedAt\" timestamp with time zone,\n    message text NOT NULL,\n    \"profileId\" uuid NOT NULL,\n    \"postId\" bigint NOT NULL\n);\n\n\n--\n-- Name: TABLE \"Comment\"; Type: COMMENT; Schema: public; Owner: -\n--\n\nCOMMENT ON TABLE public.\"Comment\" IS '@graphql({\"totalCount\": {\"enabled\": true}})';\n\n\n--\n-- Name: Comment_id_seq; Type: SEQUENCE; Schema: public; Owner: -\n--\n\nALTER TABLE public.\"Comment\" ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY (\n    SEQUENCE NAME public.\"Comment_id_seq\"\n    START WITH 1\n    INCREMENT BY 1\n    NO MINVALUE\n    NO MAXVALUE\n    CACHE 1\n);\n\n\n--\n-- Name: Vote; Type: TABLE; Schema: public; Owner: -\n--\n\nCREATE TABLE public.\"Vote\" (\n    id bigint NOT NULL,\n    \"createdAt\" timestamp with time zone DEFAULT now(),\n    \"updatedAt\" timestamp with time zone,\n    \"profileId\" uuid NOT NULL,\n    \"postId\" bigint NOT NULL,\n    direction public.direction NOT NULL\n);\n\n\n--\n-- Name: TABLE \"Vote\"; Type: COMMENT; Schema: public; Owner: -\n--\n\nCOMMENT ON TABLE public.\"Vote\" IS '@graphql({\"totalCount\": {\"enabled\": true}})';\n\n\n--\n-- Name: DownVote_id_seq; Type: SEQUENCE; Schema: public; Owner: -\n--\n\nALTER TABLE public.\"Vote\" ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY (\n    SEQUENCE NAME public.\"DownVote_id_seq\"\n    START WITH 1\n    INCREMENT BY 1\n    NO MINVALUE\n    NO MAXVALUE\n    CACHE 1\n);\n\n\n--\n-- Name: Post; Type: TABLE; Schema: public; Owner: -\n--\n\nCREATE TABLE public.\"Post\" (\n    id bigint NOT NULL,\n    \"createdAt\" timestamp with time zone DEFAULT now() NOT NULL,\n    \"updatedAt\" timestamp with time zone,\n    title text NOT NULL,\n    url text NOT NULL,\n    \"profileId\" uuid NOT NULL,\n    \"upVoteTotal\" integer DEFAULT 0 NOT NULL,\n    \"downVoteTotal\" integer DEFAULT 0 NOT NULL,\n    \"voteTotal\" integer DEFAULT 0 NOT NULL,\n    \"voteRank\" integer DEFAULT 1 NOT NULL,\n    score integer DEFAULT 0,\n    \"voteDelta\" integer DEFAULT 0 NOT NULL,\n    CONSTRAINT post_title_length CHECK ((char_length(title) > 0)),\n    CONSTRAINT post_url_length CHECK ((char_length(url) > 0))\n);\n\n\n--\n-- Name: TABLE \"Post\"; Type: COMMENT; Schema: public; Owner: -\n--\n\nCOMMENT ON TABLE public.\"Post\" IS '@graphql({\"totalCount\": {\"enabled\": true}})';\n\n\n--\n-- Name: Post_id_seq; Type: SEQUENCE; Schema: public; Owner: -\n--\n\nALTER TABLE public.\"Post\" ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY (\n    SEQUENCE NAME public.\"Post_id_seq\"\n    START WITH 1\n    INCREMENT BY 1\n    NO MINVALUE\n    NO MAXVALUE\n    CACHE 1\n);\n\n\n--\n-- Name: Profile; Type: TABLE; Schema: public; Owner: -\n--\n\nCREATE TABLE public.\"Profile\" (\n    id uuid NOT NULL,\n    updatedat timestamp with time zone,\n    username text,\n    \"avatarUrl\" text,\n    website text,\n    bio text,\n    CONSTRAINT usernamelength CHECK ((char_length(username) >= 3))\n);\n\n\n--\n-- Name: TABLE \"Profile\"; Type: COMMENT; Schema: public; Owner: -\n--\n\nCOMMENT ON TABLE public.\"Profile\" IS '@graphql({\"totalCount\": {\"enabled\": true}})';\n\n\n--\n-- Name: schema_migrations; Type: TABLE; Schema: public; Owner: -\n--\n\nCREATE TABLE public.schema_migrations (\n    version character varying(255) NOT NULL\n);\n\n\n--\n-- Name: schema_migrations; Type: TABLE; Schema: realtime; Owner: -\n--\n\nCREATE TABLE realtime.schema_migrations (\n    version bigint NOT NULL,\n    inserted_at timestamp(0) without time zone\n);\n\n\n--\n-- Name: subscription; Type: TABLE; Schema: realtime; Owner: -\n--\n\nCREATE TABLE realtime.subscription (\n    id bigint NOT NULL,\n    subscription_id uuid NOT NULL,\n    entity regclass NOT NULL,\n    filters realtime.user_defined_filter[] DEFAULT '{}'::realtime.user_defined_filter[] NOT NULL,\n    claims jsonb NOT NULL,\n    claims_role regrole GENERATED ALWAYS AS (realtime.to_regrole((claims ->> 'role'::text))) STORED NOT NULL,\n    created_at timestamp without time zone DEFAULT timezone('utc'::text, now()) NOT NULL\n);\n\n\n--\n-- Name: subscription_id_seq; Type: SEQUENCE; Schema: realtime; Owner: -\n--\n\nALTER TABLE realtime.subscription ALTER COLUMN id ADD GENERATED ALWAYS AS IDENTITY (\n    SEQUENCE NAME realtime.subscription_id_seq\n    START WITH 1\n    INCREMENT BY 1\n    NO MINVALUE\n    NO MAXVALUE\n    CACHE 1\n);\n\n\n--\n-- Name: buckets; Type: TABLE; Schema: storage; Owner: -\n--\n\nCREATE TABLE storage.buckets (\n    id text NOT NULL,\n    name text NOT NULL,\n    owner uuid,\n    created_at timestamp with time zone DEFAULT now(),\n    updated_at timestamp with time zone DEFAULT now(),\n    public boolean DEFAULT false\n);\n\n\n--\n-- Name: migrations; Type: TABLE; Schema: storage; Owner: -\n--\n\nCREATE TABLE storage.migrations (\n    id integer NOT NULL,\n    name character varying(100) NOT NULL,\n    hash character varying(40) NOT NULL,\n    executed_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP\n);\n\n\n--\n-- Name: objects; Type: TABLE; Schema: storage; Owner: -\n--\n\nCREATE TABLE storage.objects (\n    id uuid DEFAULT extensions.uuid_generate_v4() NOT NULL,\n    bucket_id text,\n    name text,\n    owner uuid,\n    created_at timestamp with time zone DEFAULT now(),\n    updated_at timestamp with time zone DEFAULT now(),\n    last_accessed_at timestamp with time zone DEFAULT now(),\n    metadata jsonb\n);\n\n\n--\n-- Name: hooks; Type: TABLE; Schema: supabase_functions; Owner: -\n--\n\nCREATE TABLE supabase_functions.hooks (\n    id bigint NOT NULL,\n    hook_table_id integer NOT NULL,\n    hook_name text NOT NULL,\n    created_at timestamp with time zone DEFAULT now() NOT NULL,\n    request_id bigint\n);\n\n\n--\n-- Name: TABLE hooks; Type: COMMENT; Schema: supabase_functions; Owner: -\n--\n\nCOMMENT ON TABLE supabase_functions.hooks IS 'Supabase Functions Hooks: Audit trail for triggered hooks.';\n\n\n--\n-- Name: hooks_id_seq; Type: SEQUENCE; Schema: supabase_functions; Owner: -\n--\n\nCREATE SEQUENCE supabase_functions.hooks_id_seq\n    START WITH 1\n    INCREMENT BY 1\n    NO MINVALUE\n    NO MAXVALUE\n    CACHE 1;\n\n\n--\n-- Name: hooks_id_seq; Type: SEQUENCE OWNED BY; Schema: supabase_functions; Owner: -\n--\n\nALTER SEQUENCE supabase_functions.hooks_id_seq OWNED BY supabase_functions.hooks.id;\n\n\n--\n-- Name: migrations; Type: TABLE; Schema: supabase_functions; Owner: -\n--\n\nCREATE TABLE supabase_functions.migrations (\n    version text NOT NULL,\n    inserted_at timestamp with time zone DEFAULT now() NOT NULL\n);\n\n\n--\n-- Name: refresh_tokens id; Type: DEFAULT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.refresh_tokens ALTER COLUMN id SET DEFAULT nextval('auth.refresh_tokens_id_seq'::regclass);\n\n\n--\n-- Name: hooks id; Type: DEFAULT; Schema: supabase_functions; Owner: -\n--\n\nALTER TABLE ONLY supabase_functions.hooks ALTER COLUMN id SET DEFAULT nextval('supabase_functions.hooks_id_seq'::regclass);\n\n\n--\n-- Name: audit_log_entries audit_log_entries_pkey; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.audit_log_entries\n    ADD CONSTRAINT audit_log_entries_pkey PRIMARY KEY (id);\n\n\n--\n-- Name: identities identities_pkey; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.identities\n    ADD CONSTRAINT identities_pkey PRIMARY KEY (provider, id);\n\n\n--\n-- Name: instances instances_pkey; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.instances\n    ADD CONSTRAINT instances_pkey PRIMARY KEY (id);\n\n\n--\n-- Name: refresh_tokens refresh_tokens_pkey; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.refresh_tokens\n    ADD CONSTRAINT refresh_tokens_pkey PRIMARY KEY (id);\n\n\n--\n-- Name: refresh_tokens refresh_tokens_token_unique; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.refresh_tokens\n    ADD CONSTRAINT refresh_tokens_token_unique UNIQUE (token);\n\n\n--\n-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.schema_migrations\n    ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version);\n\n\n--\n-- Name: users users_email_key; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.users\n    ADD CONSTRAINT users_email_key UNIQUE (email);\n\n\n--\n-- Name: users users_phone_key; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.users\n    ADD CONSTRAINT users_phone_key UNIQUE (phone);\n\n\n--\n-- Name: users users_pkey; Type: CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.users\n    ADD CONSTRAINT users_pkey PRIMARY KEY (id);\n\n\n--\n-- Name: Comment Comment_pkey; Type: CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Comment\"\n    ADD CONSTRAINT \"Comment_pkey\" PRIMARY KEY (id);\n\n\n--\n-- Name: Vote DownVote_pkey; Type: CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Vote\"\n    ADD CONSTRAINT \"DownVote_pkey\" PRIMARY KEY (id);\n\n\n--\n-- Name: Post Post_pkey; Type: CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Post\"\n    ADD CONSTRAINT \"Post_pkey\" PRIMARY KEY (id);\n\n\n--\n-- Name: Post Post_url_key; Type: CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Post\"\n    ADD CONSTRAINT \"Post_url_key\" UNIQUE (url);\n\n\n--\n-- Name: Profile Profile_pkey; Type: CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Profile\"\n    ADD CONSTRAINT \"Profile_pkey\" PRIMARY KEY (id);\n\n\n--\n-- Name: Profile Profile_username_key; Type: CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Profile\"\n    ADD CONSTRAINT \"Profile_username_key\" UNIQUE (username);\n\n\n--\n-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.schema_migrations\n    ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version);\n\n\n--\n-- Name: subscription pk_subscription; Type: CONSTRAINT; Schema: realtime; Owner: -\n--\n\nALTER TABLE ONLY realtime.subscription\n    ADD CONSTRAINT pk_subscription PRIMARY KEY (id);\n\n\n--\n-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: realtime; Owner: -\n--\n\nALTER TABLE ONLY realtime.schema_migrations\n    ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version);\n\n\n--\n-- Name: buckets buckets_pkey; Type: CONSTRAINT; Schema: storage; Owner: -\n--\n\nALTER TABLE ONLY storage.buckets\n    ADD CONSTRAINT buckets_pkey PRIMARY KEY (id);\n\n\n--\n-- Name: migrations migrations_name_key; Type: CONSTRAINT; Schema: storage; Owner: -\n--\n\nALTER TABLE ONLY storage.migrations\n    ADD CONSTRAINT migrations_name_key UNIQUE (name);\n\n\n--\n-- Name: migrations migrations_pkey; Type: CONSTRAINT; Schema: storage; Owner: -\n--\n\nALTER TABLE ONLY storage.migrations\n    ADD CONSTRAINT migrations_pkey PRIMARY KEY (id);\n\n\n--\n-- Name: objects objects_pkey; Type: CONSTRAINT; Schema: storage; Owner: -\n--\n\nALTER TABLE ONLY storage.objects\n    ADD CONSTRAINT objects_pkey PRIMARY KEY (id);\n\n\n--\n-- Name: hooks hooks_pkey; Type: CONSTRAINT; Schema: supabase_functions; Owner: -\n--\n\nALTER TABLE ONLY supabase_functions.hooks\n    ADD CONSTRAINT hooks_pkey PRIMARY KEY (id);\n\n\n--\n-- Name: migrations migrations_pkey; Type: CONSTRAINT; Schema: supabase_functions; Owner: -\n--\n\nALTER TABLE ONLY supabase_functions.migrations\n    ADD CONSTRAINT migrations_pkey PRIMARY KEY (version);\n\n\n--\n-- Name: audit_logs_instance_id_idx; Type: INDEX; Schema: auth; Owner: -\n--\n\nCREATE INDEX audit_logs_instance_id_idx ON auth.audit_log_entries USING btree (instance_id);\n\n\n--\n-- Name: identities_user_id_idx; Type: INDEX; Schema: auth; Owner: -\n--\n\nCREATE INDEX identities_user_id_idx ON auth.identities USING btree (user_id);\n\n\n--\n-- Name: refresh_tokens_instance_id_idx; Type: INDEX; Schema: auth; Owner: -\n--\n\nCREATE INDEX refresh_tokens_instance_id_idx ON auth.refresh_tokens USING btree (instance_id);\n\n\n--\n-- Name: refresh_tokens_instance_id_user_id_idx; Type: INDEX; Schema: auth; Owner: -\n--\n\nCREATE INDEX refresh_tokens_instance_id_user_id_idx ON auth.refresh_tokens USING btree (instance_id, user_id);\n\n\n--\n-- Name: refresh_tokens_parent_idx; Type: INDEX; Schema: auth; Owner: -\n--\n\nCREATE INDEX refresh_tokens_parent_idx ON auth.refresh_tokens USING btree (parent);\n\n\n--\n-- Name: refresh_tokens_token_idx; Type: INDEX; Schema: auth; Owner: -\n--\n\nCREATE INDEX refresh_tokens_token_idx ON auth.refresh_tokens USING btree (token);\n\n\n--\n-- Name: users_instance_id_email_idx; Type: INDEX; Schema: auth; Owner: -\n--\n\nCREATE INDEX users_instance_id_email_idx ON auth.users USING btree (instance_id, lower((email)::text));\n\n\n--\n-- Name: users_instance_id_idx; Type: INDEX; Schema: auth; Owner: -\n--\n\nCREATE INDEX users_instance_id_idx ON auth.users USING btree (instance_id);\n\n\n--\n-- Name: idx_one_vote_per_post; Type: INDEX; Schema: public; Owner: -\n--\n\nCREATE UNIQUE INDEX idx_one_vote_per_post ON public.\"Vote\" USING btree (\"profileId\", \"postId\");\n\n\n--\n-- Name: idx_unique_post_url; Type: INDEX; Schema: public; Owner: -\n--\n\nCREATE UNIQUE INDEX idx_unique_post_url ON public.\"Post\" USING btree (url);\n\n\n--\n-- Name: ix_realtime_subscription_entity; Type: INDEX; Schema: realtime; Owner: -\n--\n\nCREATE INDEX ix_realtime_subscription_entity ON realtime.subscription USING hash (entity);\n\n\n--\n-- Name: subscription_subscription_id_entity_filters_key; Type: INDEX; Schema: realtime; Owner: -\n--\n\nCREATE UNIQUE INDEX subscription_subscription_id_entity_filters_key ON realtime.subscription USING btree (subscription_id, entity, filters);\n\n\n--\n-- Name: bname; Type: INDEX; Schema: storage; Owner: -\n--\n\nCREATE UNIQUE INDEX bname ON storage.buckets USING btree (name);\n\n\n--\n-- Name: bucketid_objname; Type: INDEX; Schema: storage; Owner: -\n--\n\nCREATE UNIQUE INDEX bucketid_objname ON storage.objects USING btree (bucket_id, name);\n\n\n--\n-- Name: name_prefix_search; Type: INDEX; Schema: storage; Owner: -\n--\n\nCREATE INDEX name_prefix_search ON storage.objects USING btree (name text_pattern_ops);\n\n\n--\n-- Name: supabase_functions_hooks_h_table_id_h_name_idx; Type: INDEX; Schema: supabase_functions; Owner: -\n--\n\nCREATE INDEX supabase_functions_hooks_h_table_id_h_name_idx ON supabase_functions.hooks USING btree (hook_table_id, hook_name);\n\n\n--\n-- Name: supabase_functions_hooks_request_id_idx; Type: INDEX; Schema: supabase_functions; Owner: -\n--\n\nCREATE INDEX supabase_functions_hooks_request_id_idx ON supabase_functions.hooks USING btree (request_id);\n\n\n--\n-- Name: users on_auth_user_created; Type: TRIGGER; Schema: auth; Owner: -\n--\n\nCREATE TRIGGER on_auth_user_created AFTER INSERT ON auth.users FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();\n\n\n--\n-- Name: Vote on_vote_created; Type: TRIGGER; Schema: public; Owner: -\n--\n\nCREATE TRIGGER on_vote_created AFTER INSERT ON public.\"Vote\" FOR EACH ROW EXECUTE FUNCTION public.update_vote_counts();\n\n\n--\n-- Name: Vote on_vote_deleted; Type: TRIGGER; Schema: public; Owner: -\n--\n\nCREATE TRIGGER on_vote_deleted AFTER DELETE ON public.\"Vote\" FOR EACH ROW EXECUTE FUNCTION public.update_vote_counts();\n\n\n--\n-- Name: subscription tr_check_filters; Type: TRIGGER; Schema: realtime; Owner: -\n--\n\nCREATE TRIGGER tr_check_filters BEFORE INSERT OR UPDATE ON realtime.subscription FOR EACH ROW EXECUTE FUNCTION realtime.subscription_check_filters();\n\n\n--\n-- Name: identities identities_user_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.identities\n    ADD CONSTRAINT identities_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE;\n\n\n--\n-- Name: refresh_tokens refresh_tokens_parent_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: -\n--\n\nALTER TABLE ONLY auth.refresh_tokens\n    ADD CONSTRAINT refresh_tokens_parent_fkey FOREIGN KEY (parent) REFERENCES auth.refresh_tokens(token);\n\n\n--\n-- Name: Comment Comment_postId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Comment\"\n    ADD CONSTRAINT \"Comment_postId_fkey\" FOREIGN KEY (\"postId\") REFERENCES public.\"Post\"(id) ON DELETE CASCADE;\n\n\n--\n-- Name: Comment Comment_profileId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Comment\"\n    ADD CONSTRAINT \"Comment_profileId_fkey\" FOREIGN KEY (\"profileId\") REFERENCES public.\"Profile\"(id);\n\n\n--\n-- Name: Vote DownVote_profileId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Vote\"\n    ADD CONSTRAINT \"DownVote_profileId_fkey\" FOREIGN KEY (\"profileId\") REFERENCES public.\"Profile\"(id);\n\n\n--\n-- Name: Post Post_profileId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Post\"\n    ADD CONSTRAINT \"Post_profileId_fkey\" FOREIGN KEY (\"profileId\") REFERENCES public.\"Profile\"(id);\n\n\n--\n-- Name: Profile Profile_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Profile\"\n    ADD CONSTRAINT \"Profile_id_fkey\" FOREIGN KEY (id) REFERENCES auth.users(id);\n\n\n--\n-- Name: Vote Vote_postId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -\n--\n\nALTER TABLE ONLY public.\"Vote\"\n    ADD CONSTRAINT \"Vote_postId_fkey\" FOREIGN KEY (\"postId\") REFERENCES public.\"Post\"(id) ON DELETE CASCADE;\n\n\n--\n-- Name: buckets buckets_owner_fkey; Type: FK CONSTRAINT; Schema: storage; Owner: -\n--\n\nALTER TABLE ONLY storage.buckets\n    ADD CONSTRAINT buckets_owner_fkey FOREIGN KEY (owner) REFERENCES auth.users(id);\n\n\n--\n-- Name: objects objects_bucketId_fkey; Type: FK CONSTRAINT; Schema: storage; Owner: -\n--\n\nALTER TABLE ONLY storage.objects\n    ADD CONSTRAINT \"objects_bucketId_fkey\" FOREIGN KEY (bucket_id) REFERENCES storage.buckets(id);\n\n\n--\n-- Name: objects objects_owner_fkey; Type: FK CONSTRAINT; Schema: storage; Owner: -\n--\n\nALTER TABLE ONLY storage.objects\n    ADD CONSTRAINT objects_owner_fkey FOREIGN KEY (owner) REFERENCES auth.users(id);\n\n\n--\n-- Name: hooks hooks_request_id_fkey; Type: FK CONSTRAINT; Schema: supabase_functions; Owner: -\n--\n\nALTER TABLE ONLY supabase_functions.hooks\n    ADD CONSTRAINT hooks_request_id_fkey FOREIGN KEY (request_id) REFERENCES net.http_request_queue(id) ON DELETE CASCADE;\n\n\n--\n-- Name: Post All users can view posts; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"All users can view posts\" ON public.\"Post\" FOR SELECT USING (true);\n\n\n--\n-- Name: Comment; Type: ROW SECURITY; Schema: public; Owner: -\n--\n\nALTER TABLE public.\"Comment\" ENABLE ROW LEVEL SECURITY;\n\n--\n-- Name: Comment Everyone can view comments; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Everyone can view comments\" ON public.\"Comment\" FOR SELECT USING (true);\n\n\n--\n-- Name: Vote Everyone can view votes; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Everyone can view votes\" ON public.\"Vote\" FOR SELECT USING (true);\n\n\n--\n-- Name: Comment Only authenticated users can comment; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Only authenticated users can comment\" ON public.\"Comment\" FOR INSERT WITH CHECK ((auth.role() = 'authenticated'::text));\n\n\n--\n-- Name: Post Only authenticated users can create posts; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Only authenticated users can create posts\" ON public.\"Post\" FOR INSERT WITH CHECK ((auth.role() = 'authenticated'::text));\n\n\n--\n-- Name: Vote Only authenticated users can vote; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Only authenticated users can vote\" ON public.\"Vote\" FOR INSERT WITH CHECK ((auth.role() = 'authenticated'::text));\n\n\n--\n-- Name: Post; Type: ROW SECURITY; Schema: public; Owner: -\n--\n\nALTER TABLE public.\"Post\" ENABLE ROW LEVEL SECURITY;\n\n--\n-- Name: Profile; Type: ROW SECURITY; Schema: public; Owner: -\n--\n\nALTER TABLE public.\"Profile\" ENABLE ROW LEVEL SECURITY;\n\n--\n-- Name: Profile Public profiles are viewable by everyone.; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Public profiles are viewable by everyone.\" ON public.\"Profile\" FOR SELECT USING (true);\n\n\n--\n-- Name: Comment User can edit their own comments; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"User can edit their own comments\" ON public.\"Comment\" FOR UPDATE USING ((auth.uid() = \"profileId\")) WITH CHECK ((auth.uid() = \"profileId\"));\n\n\n--\n-- Name: Vote Users can change their vote; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Users can change their vote\" ON public.\"Vote\" FOR UPDATE USING ((auth.uid() = \"profileId\")) WITH CHECK ((auth.uid() = \"profileId\"));\n\n\n--\n-- Name: Comment Users can delete their own comments; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Users can delete their own comments\" ON public.\"Comment\" FOR DELETE USING ((auth.uid() = \"profileId\"));\n\n\n--\n-- Name: Post Users can delete their own posts; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Users can delete their own posts\" ON public.\"Post\" FOR DELETE USING ((auth.uid() = \"profileId\"));\n\n\n--\n-- Name: Vote Users can delete their own votes; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Users can delete their own votes\" ON public.\"Vote\" FOR DELETE USING ((auth.uid() = \"profileId\"));\n\n\n--\n-- Name: Post Users can edit their own posts; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Users can edit their own posts\" ON public.\"Post\" FOR UPDATE USING ((auth.uid() = \"profileId\")) WITH CHECK ((auth.uid() = \"profileId\"));\n\n\n--\n-- Name: Profile Users can insert their own profile.; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Users can insert their own profile.\" ON public.\"Profile\" FOR INSERT WITH CHECK ((auth.uid() = id));\n\n\n--\n-- Name: Profile Users can update own profile.; Type: POLICY; Schema: public; Owner: -\n--\n\nCREATE POLICY \"Users can update own profile.\" ON public.\"Profile\" FOR UPDATE USING ((auth.uid() = id));\n\n\n--\n-- Name: Vote; Type: ROW SECURITY; Schema: public; Owner: -\n--\n\nALTER TABLE public.\"Vote\" ENABLE ROW LEVEL SECURITY;\n\n--\n-- Name: schema_migrations; Type: ROW SECURITY; Schema: public; Owner: -\n--\n\nALTER TABLE public.schema_migrations ENABLE ROW LEVEL SECURITY;\n\n--\n-- Name: objects Anyone can update an avatar.; Type: POLICY; Schema: storage; Owner: -\n--\n\nCREATE POLICY \"Anyone can update an avatar.\" ON storage.objects FOR UPDATE WITH CHECK ((bucket_id = 'avatars'::text));\n\n\n--\n-- Name: objects Anyone can upload an avatar.; Type: POLICY; Schema: storage; Owner: -\n--\n\nCREATE POLICY \"Anyone can upload an avatar.\" ON storage.objects FOR INSERT WITH CHECK ((bucket_id = 'avatars'::text));\n\n\n--\n-- Name: objects Avatar images are publicly accessible.; Type: POLICY; Schema: storage; Owner: -\n--\n\nCREATE POLICY \"Avatar images are publicly accessible.\" ON storage.objects FOR SELECT USING ((bucket_id = 'avatars'::text));\n\n\n--\n-- Name: buckets; Type: ROW SECURITY; Schema: storage; Owner: -\n--\n\nALTER TABLE storage.buckets ENABLE ROW LEVEL SECURITY;\n\n--\n-- Name: migrations; Type: ROW SECURITY; Schema: storage; Owner: -\n--\n\nALTER TABLE storage.migrations ENABLE ROW LEVEL SECURITY;\n\n--\n-- Name: objects; Type: ROW SECURITY; Schema: storage; Owner: -\n--\n\nALTER TABLE storage.objects ENABLE ROW LEVEL SECURITY;\n\n--\n-- Name: supabase_realtime; Type: PUBLICATION; Schema: -; Owner: -\n--\n\nCREATE PUBLICATION supabase_realtime WITH (publish = 'insert, update, delete, truncate');\n\n\n--\n-- Name: supabase_realtime Profile; Type: PUBLICATION TABLE; Schema: public; Owner: -\n--\n\nALTER PUBLICATION supabase_realtime ADD TABLE ONLY public.\"Profile\";\n\n\n--\n-- Name: issue_graphql_placeholder; Type: EVENT TRIGGER; Schema: -; Owner: -\n--\n\nCREATE EVENT TRIGGER issue_graphql_placeholder ON sql_drop\n         WHEN TAG IN ('DROP EXTENSION')\n   EXECUTE FUNCTION extensions.set_graphql_placeholder();\n\n\n--\n-- Name: issue_pg_cron_access; Type: EVENT TRIGGER; Schema: -; Owner: -\n--\n\nCREATE EVENT TRIGGER issue_pg_cron_access ON ddl_command_end\n         WHEN TAG IN ('CREATE SCHEMA')\n   EXECUTE FUNCTION extensions.grant_pg_cron_access();\n\n\n--\n-- Name: issue_pg_graphql_access; Type: EVENT TRIGGER; Schema: -; Owner: -\n--\n\nCREATE EVENT TRIGGER issue_pg_graphql_access ON ddl_command_end\n         WHEN TAG IN ('CREATE FUNCTION')\n   EXECUTE FUNCTION extensions.grant_pg_graphql_access();\n\n\n--\n-- Name: issue_pg_net_access; Type: EVENT TRIGGER; Schema: -; Owner: -\n--\n\nCREATE EVENT TRIGGER issue_pg_net_access ON ddl_command_end\n         WHEN TAG IN ('CREATE EXTENSION')\n   EXECUTE FUNCTION extensions.grant_pg_net_access();\n\n\n--\n-- Name: pgrst_ddl_watch; Type: EVENT TRIGGER; Schema: -; Owner: -\n--\n\nCREATE EVENT TRIGGER pgrst_ddl_watch ON ddl_command_end\n   EXECUTE FUNCTION extensions.pgrst_ddl_watch();\n\n\n--\n-- Name: pgrst_drop_watch; Type: EVENT TRIGGER; Schema: -; Owner: -\n--\n\nCREATE EVENT TRIGGER pgrst_drop_watch ON sql_drop\n   EXECUTE FUNCTION extensions.pgrst_drop_watch();\n\n\n--\n-- PostgreSQL database dump complete\n--\n\n\n--\n-- Dbmate schema migrations\n--\n\n"
  },
  {
    "path": "data/seed/blog.xml",
    "content": "\n  <rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\">\n    <channel>\n      <title>Blog - Supabase</title>\n      <link>https://supabase.com</link>\n      <description>Latest news from Supabase</description>\n      <language>en</language>\n      <lastBuildDate>Tue, 08 Mar 2022 00:00:00 GMT</lastBuildDate>\n      <atom:link href=\"https://supabase.com/blog/rss.xml\" rel=\"self\" type=\"application/rss+xml\"/>\n      \n<item>\n  <guid>https://supabase.com/blog/2022/03/08/audit</guid>\n  <title>Postgres Auditing in 150 lines of SQL</title>\n  <link>https://supabase.com/blog/2022/03/08/audit</link>\n  <description>PostgreSQL has a robust set of features which we can leverage to create a generic auditing solution in 150 lines of SQL.</description>\n  <pubDate>Tue, 08 Mar 2022 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2022/02/22/supabase-beta-january-2022</guid>\n  <title>Supabase Beta January 2022</title>\n  <link>https://supabase.com/blog/2022/02/22/supabase-beta-january-2022</link>\n  <description>New auth providers, SMS providers, and new videos.</description>\n  <pubDate>Tue, 22 Feb 2022 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2022/01/20/supabase-beta-december-2021</guid>\n  <title>Supabase Beta December 2021</title>\n  <link>https://supabase.com/blog/2022/01/20/supabase-beta-december-2021</link>\n  <description>New crypto extension, Postgres videos, and a bunch of cool integrations.</description>\n  <pubDate>Thu, 20 Jan 2022 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2022/01/20/product-hunt-golden-kitty-awards-2021</guid>\n  <title>Golden Kitty Awards Ceremony Watch Party with Supabase</title>\n  <link>https://supabase.com/blog/2022/01/20/product-hunt-golden-kitty-awards-2021</link>\n  <description>Hang out with us while watching the Product Hunt Golden Kitty Awards Ceremony</description>\n  <pubDate>Thu, 20 Jan 2022 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/12/17/holiday-hackdays-winners-2021</guid>\n  <title>Holiday Hackdays Winners 2021</title>\n  <link>https://supabase.com/blog/2021/12/17/holiday-hackdays-winners-2021</link>\n  <description>Celebrating many amazing projects submitted to our Holiday Hackdays Hackathon.</description>\n  <pubDate>Fri, 17 Dec 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/12/15/beta-november-2021-launch-week-recap</guid>\n  <title>Supabase Beta November 2021: Launch Week Recap</title>\n  <link>https://supabase.com/blog/2021/12/15/beta-november-2021-launch-week-recap</link>\n  <description>We wrapped up November with Supabase's third Launch Week. Here's all the awesome stuff that got shipped ...</description>\n  <pubDate>Wed, 15 Dec 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/12/03/supabase-holiday-hackdays-hackathon</guid>\n  <title>Kicking off the Holiday Hackdays</title>\n  <link>https://supabase.com/blog/2021/12/03/supabase-holiday-hackdays-hackathon</link>\n  <description>Build cool stuff and celebrate open-source software with us during the Holiday Hackdays!</description>\n  <pubDate>Fri, 03 Dec 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/12/03/pg-graphql</guid>\n  <title>pg_graphql: A GraphQL extension for PostgreSQL</title>\n  <link>https://supabase.com/blog/2021/12/03/pg-graphql</link>\n  <description>GraphQL support is in development for PostgreSQL + Supabase.</description>\n  <pubDate>Fri, 03 Dec 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/12/03/launch-week-three-friday-five-more-things</guid>\n  <title>Five more things</title>\n  <link>https://supabase.com/blog/2021/12/03/launch-week-three-friday-five-more-things</link>\n  <description>It's never just one more thing!</description>\n  <pubDate>Fri, 03 Dec 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/12/02/supabase-acquires-logflare</guid>\n  <title>Supabase acquires Logflare</title>\n  <link>https://supabase.com/blog/2021/12/02/supabase-acquires-logflare</link>\n  <description>Today, we're ecstatic to announce that Logflare is joining Supabase.</description>\n  <pubDate>Thu, 02 Dec 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/12/01/realtime-row-level-security-in-postgresql</guid>\n  <title>Realtime Postgres RLS now available on Supabase</title>\n  <link>https://supabase.com/blog/2021/12/01/realtime-row-level-security-in-postgresql</link>\n  <description>Realtime database changes are now broadcast to authenticated users, respecting the same PostgreSQL policies that you use for Row Level Security.</description>\n  <pubDate>Wed, 01 Dec 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/11/30/supabase-studio</guid>\n  <title>Supabase Studio</title>\n  <link>https://supabase.com/blog/2021/11/30/supabase-studio</link>\n  <description>The same Dashboard that you're using on our Platform is now available for local development and Self-Hosting.</description>\n  <pubDate>Tue, 30 Nov 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/11/29/community-day</guid>\n  <title>Community Day</title>\n  <link>https://supabase.com/blog/2021/11/29/community-day</link>\n  <description>Kicking off launch week by highlighting the communities around Supabase.</description>\n  <pubDate>Mon, 29 Nov 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/11/28/whats-new-in-postgres-14</guid>\n  <title>New in PostgreSQL 14: What every developer should know</title>\n  <link>https://supabase.com/blog/2021/11/28/whats-new-in-postgres-14</link>\n  <description>A quick look at some new features and functionality in PostgreSQL 14.</description>\n  <pubDate>Sun, 28 Nov 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/11/28/postgrest-9</guid>\n  <title>PostgREST 9</title>\n  <link>https://supabase.com/blog/2021/11/28/postgrest-9</link>\n  <description>New features and updates in PostgREST version 9.</description>\n  <pubDate>Sat, 27 Nov 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/11/26/supabase-launch-week-the-trilogy</guid>\n  <title>Supabase Launch Week III: Holiday Special</title>\n  <link>https://supabase.com/blog/2021/11/26/supabase-launch-week-the-trilogy</link>\n  <description>Tis the season to be shipping.</description>\n  <pubDate>Fri, 26 Nov 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/11/26/supabase-how-we-launch</guid>\n  <title>How we launch at Supabase</title>\n  <link>https://supabase.com/blog/2021/11/26/supabase-how-we-launch</link>\n  <description>The history and methodology of Supabase Launch Week.</description>\n  <pubDate>Fri, 26 Nov 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/11/05/supabase-beta-october-2021</guid>\n  <title>Supabase Beta October 2021</title>\n  <link>https://supabase.com/blog/2021/11/05/supabase-beta-october-2021</link>\n  <description>Three new Auth providers, multi-schema support, and we're gearing up for another Launch Week.</description>\n  <pubDate>Sun, 07 Nov 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/10/28/supabase-series-a</guid>\n  <title>Supabase $30m Series A</title>\n  <link>https://supabase.com/blog/2021/10/28/supabase-series-a</link>\n  <description>Supabase just raised $30M, bringing our total funding to $36M.</description>\n  <pubDate>Thu, 28 Oct 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/10/19/replenysh-time-to-value-in-less-than-24-hours</guid>\n  <title>Replenysh uses Supabase to implement OTP in less than 24-hours</title>\n  <link>https://supabase.com/blog/2021/10/19/replenysh-time-to-value-in-less-than-24-hours</link>\n  <description>Learn how Replenysh uses Supabase to power the circular economy, redefining how brands interact with their customers and products.</description>\n  <pubDate>Tue, 19 Oct 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/10/14/hacktoberfest-hackathon-winners-2021</guid>\n  <title>Hacktoberfest Hackathon Winners 2021</title>\n  <link>https://supabase.com/blog/2021/10/14/hacktoberfest-hackathon-winners-2021</link>\n  <description>Celebrating many amazing projects submitted to our Hacktoberfest Hackathon.</description>\n  <pubDate>Thu, 14 Oct 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/10/04/supabase-beta-sept-2021</guid>\n  <title>Supabase Beta Sept 2021</title>\n  <link>https://supabase.com/blog/2021/10/04/supabase-beta-sept-2021</link>\n  <description>Hackathon, Aborting request, UI updates, and now Hiring.</description>\n  <pubDate>Mon, 04 Oct 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/09/28/supabase-hacktoberfest-hackathon-2021</guid>\n  <title>Supabase Hacktoberfest Hackathon 2021</title>\n  <link>https://supabase.com/blog/2021/09/28/supabase-hacktoberfest-hackathon-2021</link>\n  <description>We're running another Supabase Hackathon during Hacktoberfest!</description>\n  <pubDate>Tue, 28 Sep 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/09/10/supabase-beta-august-2021</guid>\n  <title>Supabase Beta August 2021</title>\n  <link>https://supabase.com/blog/2021/09/10/supabase-beta-august-2021</link>\n  <description>Fundraising, Realtime Security, custom SMS templates, and deployments in South Korea.</description>\n  <pubDate>Fri, 10 Sep 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/08/12/supabase-beta-july-2021</guid>\n  <title>Supabase Beta July 2021</title>\n  <link>https://supabase.com/blog/2021/08/12/supabase-beta-july-2021</link>\n  <description>Discord Logins, Vercel Integration, Full text search, and OAuth guides.</description>\n  <pubDate>Thu, 12 Aug 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/08/09/hackathon-winners</guid>\n  <title>Open Source Hackathon Winners</title>\n  <link>https://supabase.com/blog/2021/08/09/hackathon-winners</link>\n  <description>Let the medal ceremony begin for the best projects submitted during the Supabase Hackathon.</description>\n  <pubDate>Mon, 09 Aug 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/07/30/supabase-swag-store</guid>\n  <title>Supabase Swag Store</title>\n  <link>https://supabase.com/blog/2021/07/30/supabase-swag-store</link>\n  <description>Today we are officially launching the Supabase Swag Store.</description>\n  <pubDate>Fri, 30 Jul 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/07/30/supabase-functions-updates</guid>\n  <title>Updates for Supabase Functions</title>\n  <link>https://supabase.com/blog/2021/07/30/supabase-functions-updates</link>\n  <description>The question on everyone's mind - are we launching Supabase Functions? Well, it's complicated.</description>\n  <pubDate>Fri, 30 Jul 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/07/30/1-the-supabase-hackathon</guid>\n  <title>The Supabase Hackathon</title>\n  <link>https://supabase.com/blog/2021/07/30/1-the-supabase-hackathon</link>\n  <description>A whole week of Hacking for Fun and Prizes.</description>\n  <pubDate>Fri, 30 Jul 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/07/29/supabase-reports-and-metrics</guid>\n  <title>Supabase Reports and Metrics</title>\n  <link>https://supabase.com/blog/2021/07/29/supabase-reports-and-metrics</link>\n  <description>We're exposing a full set of metrics in your projects, so that you can build better (and faster) products for your users.</description>\n  <pubDate>Thu, 29 Jul 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/07/28/supabase-auth-passwordless-sms-login</guid>\n  <title>Supabase Auth v2: Phone Auth now available</title>\n  <link>https://supabase.com/blog/2021/07/28/supabase-auth-passwordless-sms-login</link>\n  <description>Phone Auth is available today on all new and existing Supabase projects.</description>\n  <pubDate>Wed, 28 Jul 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/07/28/mobbin-supabase-200000-users</guid>\n  <title>Mobbin uses Supabase to authenticate 200,000 users</title>\n  <link>https://supabase.com/blog/2021/07/28/mobbin-supabase-200000-users</link>\n  <description>Learn how Mobbin migrated 200,000 users from Firebase for a better authentication experience.</description>\n  <pubDate>Wed, 28 Jul 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/07/27/storage-beta</guid>\n  <title>Supabase Storage now in Beta</title>\n  <link>https://supabase.com/blog/2021/07/27/storage-beta</link>\n  <description>Supabase Storage moves into Beta.</description>\n  <pubDate>Tue, 27 Jul 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/07/27/spot-flutter-with-postgres</guid>\n  <title>Spot: a video sharing app built with Flutter</title>\n  <link>https://supabase.com/blog/2021/07/27/spot-flutter-with-postgres</link>\n  <description>Spot is a geolocation-based video-sharing app with some social networking features.</description>\n  <pubDate>Tue, 27 Jul 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/07/26/supabase-postgres-13</guid>\n  <title>Supabase is now on Postgres 13.3</title>\n  <link>https://supabase.com/blog/2021/07/26/supabase-postgres-13</link>\n  <description>From today, new Supabase projects will be on a version of Supabase Postgres that runs on Postgres 13.3.</description>\n  <pubDate>Mon, 26 Jul 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/07/26/supabase-community-day</guid>\n  <title>Supabase Community Day</title>\n  <link>https://supabase.com/blog/2021/07/26/supabase-community-day</link>\n  <description>Community Day</description>\n  <pubDate>Mon, 26 Jul 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/07/26/epsilon3-self-hosting</guid>\n  <title>Epsilon3 Self-Host Supabase To Revolutionize Space Operations </title>\n  <link>https://supabase.com/blog/2021/07/26/epsilon3-self-hosting</link>\n  <description>Learn how the team at Epsilon3 use Supabase to help teams execute secure and reliable operations in an industry that project spend runs into the billions.</description>\n  <pubDate>Mon, 26 Jul 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/07/22/supabase-launch-week-sql</guid>\n  <title>Supabase Launch Week II: The SQL</title>\n  <link>https://supabase.com/blog/2021/07/22/supabase-launch-week-sql</link>\n  <description>Five days of Supabase. Again.</description>\n  <pubDate>Thu, 22 Jul 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/07/01/roles-postgres-hooks</guid>\n  <title>Protecting reserved roles with PostgreSQL Hooks</title>\n  <link>https://supabase.com/blog/2021/07/01/roles-postgres-hooks</link>\n  <description>Using Postgres Hooks to protect functionality in your Postgres database.</description>\n  <pubDate>Fri, 02 Jul 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/07/02/supabase-beta-june-2021</guid>\n  <title>Supabase Beta June 2021</title>\n  <link>https://supabase.com/blog/2021/07/02/supabase-beta-june-2021</link>\n  <description>Discord Logins, Vercel Integration, Full text search, and OAuth guides.</description>\n  <pubDate>Wed, 02 Jun 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/06/02/supabase-beta-may-2021</guid>\n  <title>Supabase Beta May 2021</title>\n  <link>https://supabase.com/blog/2021/06/02/supabase-beta-may-2021</link>\n  <description>Apple &amp; Twitter Logins, Supabase Grid, Go &amp; Swift Libraries.</description>\n  <pubDate>Wed, 02 Jun 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/05/03/supabase-beta-april-2021</guid>\n  <title>Supabase Beta April 2021</title>\n  <link>https://supabase.com/blog/2021/05/03/supabase-beta-april-2021</link>\n  <description>Supabase \"gardening\" - stability, security, and community support.</description>\n  <pubDate>Wed, 05 May 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/04/06/supabase-beta-march-2021</guid>\n  <title>Supabase Beta March 2021</title>\n  <link>https://supabase.com/blog/2021/04/06/supabase-beta-march-2021</link>\n  <description>Launch week, Storage, Supabase CLI, Connection Pooling, Supabase UI, and Pricing.</description>\n  <pubDate>Tue, 06 Apr 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/04/02/supabase-workflows</guid>\n  <title>Workflows are coming to Supabase</title>\n  <link>https://supabase.com/blog/2021/04/02/supabase-workflows</link>\n  <description>Functions are great, but you know what's better?</description>\n  <pubDate>Fri, 02 Apr 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/04/02/supabase-pgbouncer</guid>\n  <title>PgBouncer is now available in Supabase</title>\n  <link>https://supabase.com/blog/2021/04/02/supabase-pgbouncer</link>\n  <description>Better support for Serverless and Postgres.</description>\n  <pubDate>Fri, 02 Apr 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/04/02/supabase-dot-com</guid>\n  <title>Supabase Dot Com</title>\n  <link>https://supabase.com/blog/2021/04/02/supabase-dot-com</link>\n  <description>The Supabase Domain name is changing.</description>\n  <pubDate>Fri, 02 Apr 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/04/01/supabase-nft-marketplace</guid>\n  <title>Supabase Launches NFT Marketplace</title>\n  <link>https://supabase.com/blog/2021/04/01/supabase-nft-marketplace</link>\n  <description>A fully encrypted NFT platform to protect and transact your digital assets</description>\n  <pubDate>Thu, 01 Apr 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/03/31/supabase-cli</guid>\n  <title>Supabase CLI</title>\n  <link>https://supabase.com/blog/2021/03/31/supabase-cli</link>\n  <description>Local development, database migrations, and self-hosting.</description>\n  <pubDate>Wed, 31 Mar 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/03/30/supabase-storage</guid>\n  <title>Storage is now available in Supabase</title>\n  <link>https://supabase.com/blog/2021/03/30/supabase-storage</link>\n  <description>Launching Supabase Storage and how you can use it in your apps</description>\n  <pubDate>Tue, 30 Mar 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/03/29/pricing</guid>\n  <title>Supabase Beta Pricing</title>\n  <link>https://supabase.com/blog/2021/03/29/pricing</link>\n  <description>Supabase launches Beta pricing structure</description>\n  <pubDate>Mon, 29 Mar 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/03/25/launch-week</guid>\n  <title>Launch week</title>\n  <link>https://supabase.com/blog/2021/03/25/launch-week</link>\n  <description>Five days of Supabase.</description>\n  <pubDate>Thu, 25 Mar 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/03/25/angels-of-supabase</guid>\n  <title>Angels of Supabase</title>\n  <link>https://supabase.com/blog/2021/03/25/angels-of-supabase</link>\n  <description>Meet the investors of Supabase.</description>\n  <pubDate>Thu, 25 Mar 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/03/22/In-The-Loop</guid>\n  <title>Developers stay up to date with intheloop.dev</title>\n  <link>https://supabase.com/blog/2021/03/22/In-The-Loop</link>\n  <description>Learn why Kevin is building intheloop.dev with Supabase</description>\n  <pubDate>Mon, 22 Mar 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/03/11/using-supabase-replit</guid>\n  <title>Using Supabase in Replit</title>\n  <link>https://supabase.com/blog/2021/03/11/using-supabase-replit</link>\n  <description>Free hosted relational database from within your node.js repl</description>\n  <pubDate>Thu, 11 Mar 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/03/08/toad-a-link-shortener-with-simple-apis-for-low-coders</guid>\n  <title>Toad, a link shortener with simple APIs for low-coders</title>\n  <link>https://supabase.com/blog/2021/03/08/toad-a-link-shortener-with-simple-apis-for-low-coders</link>\n  <description>An easy-to-use link shortening tool with simple APIs</description>\n  <pubDate>Mon, 08 Mar 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/03/05/postgres-as-a-cron-server</guid>\n  <title>Postgres as a CRON Server</title>\n  <link>https://supabase.com/blog/2021/03/05/postgres-as-a-cron-server</link>\n  <description>Running repetitive tasks with your Postgres database.</description>\n  <pubDate>Fri, 05 Mar 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/03/02/supabase-beta-february-2021</guid>\n  <title>Supabase Beta February 2021</title>\n  <link>https://supabase.com/blog/2021/03/02/supabase-beta-february-2021</link>\n  <description>One year of building.</description>\n  <pubDate>Tue, 02 Mar 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/02/27/cracking-postgres-interview</guid>\n  <title>Cracking PostgreSQL Interview Questions</title>\n  <link>https://supabase.com/blog/2021/02/27/cracking-postgres-interview</link>\n  <description>Understand the top PostgreSQL Interview Questions</description>\n  <pubDate>Sat, 27 Feb 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/02/09/case-study-roboflow</guid>\n  <title>Roboflow.com choose Supabase to power Paint.wtf leaderboard</title>\n  <link>https://supabase.com/blog/2021/02/09/case-study-roboflow</link>\n  <description>Learn how Roboflow.com used Supabase to build their Paint.wtf leaderboard</description>\n  <pubDate>Tue, 09 Feb 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/02/02/supabase-beta-january-2021</guid>\n  <title>Supabase Beta January 2021</title>\n  <link>https://supabase.com/blog/2021/02/02/supabase-beta-january-2021</link>\n  <description>Eleven months of building.</description>\n  <pubDate>Tue, 02 Feb 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2021/01/02/supabase-beta-december-2020</guid>\n  <title>Supabase Beta December 2020</title>\n  <link>https://supabase.com/blog/2021/01/02/supabase-beta-december-2020</link>\n  <description>Ten months of building.</description>\n  <pubDate>Sat, 02 Jan 2021 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/12/13/supabase-dashboard-performance</guid>\n  <title>Making the Supabase Dashboard Supa-fast</title>\n  <link>https://supabase.com/blog/2020/12/13/supabase-dashboard-performance</link>\n  <description>Improving the performance of the Supabase dashboard</description>\n  <pubDate>Sun, 13 Dec 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/12/02/supabase-striveschool</guid>\n  <title>Supabase Partners With Strive School To Help Teach Open Source</title>\n  <link>https://supabase.com/blog/2020/12/02/supabase-striveschool</link>\n  <description>Supabase Partners With Strive School To Help Teach Open Source To The Next Generation Of Developers</description>\n  <pubDate>Wed, 02 Dec 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/12/02/case-study-xendit</guid>\n  <title>Xendit Built a Counter-Fraud Watchlist for the Fintech Industry</title>\n  <link>https://supabase.com/blog/2020/12/02/case-study-xendit</link>\n  <description>See how Xendit use Supabase to build a full-text search engine.</description>\n  <pubDate>Wed, 02 Dec 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/12/02/case-study-tayfa</guid>\n  <title>TAYFA Built a No-Code Website Builder in Seven Days</title>\n  <link>https://supabase.com/blog/2020/12/02/case-study-tayfa</link>\n  <description>See how Tayfa went from idea to paying customer in less than 30 days.</description>\n  <pubDate>Wed, 02 Dec 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/12/02/case-study-monitoro</guid>\n  <title>Monitoro Built a Web Crawler Handling Millions of API Requests</title>\n  <link>https://supabase.com/blog/2020/12/02/case-study-monitoro</link>\n  <description>See how Monitoro built an automated scraping platform using Supabase.</description>\n  <pubDate>Wed, 02 Dec 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/12/01/supabase-alpha-november-2020</guid>\n  <title>Supabase Alpha November 2020</title>\n  <link>https://supabase.com/blog/2020/12/01/supabase-alpha-november-2020</link>\n  <description>Nine months of building.</description>\n  <pubDate>Tue, 01 Dec 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/11/18/postgresql-views</guid>\n  <title>Postgres Views</title>\n  <link>https://supabase.com/blog/2020/11/18/postgresql-views</link>\n  <description>Creating and using a view in PostgreSQL.</description>\n  <pubDate>Wed, 18 Nov 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/11/02/supabase-alpha-october-2020</guid>\n  <title>Supabase Alpha October 2020</title>\n  <link>https://supabase.com/blog/2020/11/02/supabase-alpha-october-2020</link>\n  <description>Eight months of building.</description>\n  <pubDate>Mon, 02 Nov 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/10/30/improved-dx</guid>\n  <title>Supabase.js 1.0</title>\n  <link>https://supabase.com/blog/2020/10/30/improved-dx</link>\n  <description>We're releasing a new version of our Supabase client with some awesome new improvements.</description>\n  <pubDate>Fri, 30 Oct 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/10/03/supabase-alpha-september-2020</guid>\n  <title>Supabase Alpha September 2020</title>\n  <link>https://supabase.com/blog/2020/10/03/supabase-alpha-september-2020</link>\n  <description>Seven months of building.</description>\n  <pubDate>Sat, 03 Oct 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/09/11/supabase-hacktoberfest-2020</guid>\n  <title>Supabase Hacktoberfest 2020</title>\n  <link>https://supabase.com/blog/2020/09/11/supabase-hacktoberfest-2020</link>\n  <description>Join us for a celebration of open source software and learn how to contribute to Supabase.</description>\n  <pubDate>Fri, 11 Sep 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/09/03/supabase-alpha-august-2020</guid>\n  <title>Supabase Alpha August 2020</title>\n  <link>https://supabase.com/blog/2020/09/03/supabase-alpha-august-2020</link>\n  <description>Six months of building</description>\n  <pubDate>Thu, 03 Sep 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/08/05/supabase-auth</guid>\n  <title>Supabase Auth</title>\n  <link>https://supabase.com/blog/2020/08/05/supabase-auth</link>\n  <description>Authenticate and authorize your users with Supabase Auth</description>\n  <pubDate>Wed, 05 Aug 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/08/02/supabase-alpha-july-2020</guid>\n  <title>Supabase Alpha July 2020</title>\n  <link>https://supabase.com/blog/2020/08/02/supabase-alpha-july-2020</link>\n  <description>Five months of building</description>\n  <pubDate>Sun, 02 Aug 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/08/02/continuous-postgresql-backup-walg</guid>\n  <title>Continuous PostgreSQL Backups using WAL-G</title>\n  <link>https://supabase.com/blog/2020/08/02/continuous-postgresql-backup-walg</link>\n  <description>Have you ever wanted to restore your database's state to a particular moment in time? This post explains how, using WAL-G.</description>\n  <pubDate>Sun, 02 Aug 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/07/10/alpha-launch-postmortem</guid>\n  <title>Alpha Launch Postmortem</title>\n  <link>https://supabase.com/blog/2020/07/10/alpha-launch-postmortem</link>\n  <description>Everything that went wrong with Supabase's launch</description>\n  <pubDate>Fri, 10 Jul 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/07/09/postgresql-templates</guid>\n  <title>What are PostgreSQL Templates?</title>\n  <link>https://supabase.com/blog/2020/07/09/postgresql-templates</link>\n  <description>What are PostgreSQL templates and what are they used for?</description>\n  <pubDate>Thu, 09 Jul 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/07/17/postgresql-physical-logical-backups</guid>\n  <title>Physical vs Logical Backups in PostgreSQL</title>\n  <link>https://supabase.com/blog/2020/07/17/postgresql-physical-logical-backups</link>\n  <description>What are physical and logical backups in Postgres?</description>\n  <pubDate>Tue, 07 Jul 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/07/01/supabase-alpha-june-2020</guid>\n  <title>Supabase Alpha June 2020</title>\n  <link>https://supabase.com/blog/2020/07/01/supabase-alpha-june-2020</link>\n  <description>Four months of building</description>\n  <pubDate>Wed, 01 Jul 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/06/15/supabase-steve-chavez</guid>\n  <title>Steve Chavez has joined Supabase</title>\n  <link>https://supabase.com/blog/2020/06/15/supabase-steve-chavez</link>\n  <description>Steve joins Supabase to help build Auth.</description>\n  <pubDate>Mon, 15 Jun 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/06/01/supabase-alpha-may-2020</guid>\n  <title>Supabase Alpha May 2020</title>\n  <link>https://supabase.com/blog/2020/06/01/supabase-alpha-may-2020</link>\n  <description>Three months of building</description>\n  <pubDate>Mon, 01 Jun 2020 00:00:00 GMT</pubDate>\n</item>\n\n<item>\n  <guid>https://supabase.com/blog/2020/05/01/supabase-alpha-april-2020</guid>\n  <title>Supabase Alpha April 2020</title>\n  <link>https://supabase.com/blog/2020/05/01/supabase-alpha-april-2020</link>\n  <description>Two months of building</description>\n  <pubDate>Mon, 01 Jun 2020 00:00:00 GMT</pubDate>\n</item>\n\n    </channel>\n  </rss>\n"
  },
  {
    "path": "data/seed/blog_posts.csv",
    "content": "\"profileId\",\"title\",\"url\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Blog - Supabase\",\"https://supabase.com\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Postgres Auditing in 150 lines of SQL\",\"https://supabase.com/blog/2022/03/08/audit\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Beta January 2022\",\"https://supabase.com/blog/2022/02/22/supabase-beta-january-2022\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Beta December 2021\",\"https://supabase.com/blog/2022/01/20/supabase-beta-december-2021\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Golden Kitty Awards Ceremony Watch Party with Supabase\",\"https://supabase.com/blog/2022/01/20/product-hunt-golden-kitty-awards-2021\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Holiday Hackdays Winners 2021\",\"https://supabase.com/blog/2021/12/17/holiday-hackdays-winners-2021\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Beta November 2021: Launch Week Recap\",\"https://supabase.com/blog/2021/12/15/beta-november-2021-launch-week-recap\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Kicking off the Holiday Hackdays\",\"https://supabase.com/blog/2021/12/03/supabase-holiday-hackdays-hackathon\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"pg_graphql: A GraphQL extension for PostgreSQL\",\"https://supabase.com/blog/2021/12/03/pg-graphql\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Five more things\",\"https://supabase.com/blog/2021/12/03/launch-week-three-friday-five-more-things\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase acquires Logflare\",\"https://supabase.com/blog/2021/12/02/supabase-acquires-logflare\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Realtime Postgres RLS now available on Supabase\",\"https://supabase.com/blog/2021/12/01/realtime-row-level-security-in-postgresql\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Studio\",\"https://supabase.com/blog/2021/11/30/supabase-studio\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Community Day\",\"https://supabase.com/blog/2021/11/29/community-day\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"New in PostgreSQL 14: What every developer should know\",\"https://supabase.com/blog/2021/11/28/whats-new-in-postgres-14\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"PostgREST 9\",\"https://supabase.com/blog/2021/11/28/postgrest-9\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Launch Week III: Holiday Special\",\"https://supabase.com/blog/2021/11/26/supabase-launch-week-the-trilogy\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"How we launch at Supabase\",\"https://supabase.com/blog/2021/11/26/supabase-how-we-launch\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Beta October 2021\",\"https://supabase.com/blog/2021/11/05/supabase-beta-october-2021\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase $30m Series A\",\"https://supabase.com/blog/2021/10/28/supabase-series-a\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Replenysh uses Supabase to implement OTP in less than 24-hours\",\"https://supabase.com/blog/2021/10/19/replenysh-time-to-value-in-less-than-24-hours\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Hacktoberfest Hackathon Winners 2021\",\"https://supabase.com/blog/2021/10/14/hacktoberfest-hackathon-winners-2021\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Beta Sept 2021\",\"https://supabase.com/blog/2021/10/04/supabase-beta-sept-2021\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Hacktoberfest Hackathon 2021\",\"https://supabase.com/blog/2021/09/28/supabase-hacktoberfest-hackathon-2021\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Beta August 2021\",\"https://supabase.com/blog/2021/09/10/supabase-beta-august-2021\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Beta July 2021\",\"https://supabase.com/blog/2021/08/12/supabase-beta-july-2021\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Open Source Hackathon Winners\",\"https://supabase.com/blog/2021/08/09/hackathon-winners\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Swag Store\",\"https://supabase.com/blog/2021/07/30/supabase-swag-store\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Updates for Supabase Functions\",\"https://supabase.com/blog/2021/07/30/supabase-functions-updates\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"The Supabase Hackathon\",\"https://supabase.com/blog/2021/07/30/1-the-supabase-hackathon\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Reports and Metrics\",\"https://supabase.com/blog/2021/07/29/supabase-reports-and-metrics\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Auth v2: Phone Auth now available\",\"https://supabase.com/blog/2021/07/28/supabase-auth-passwordless-sms-login\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Mobbin uses Supabase to authenticate 200,000 users\",\"https://supabase.com/blog/2021/07/28/mobbin-supabase-200000-users\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Storage now in Beta\",\"https://supabase.com/blog/2021/07/27/storage-beta\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Spot: a video sharing app built with Flutter\",\"https://supabase.com/blog/2021/07/27/spot-flutter-with-postgres\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase is now on Postgres 13.3\",\"https://supabase.com/blog/2021/07/26/supabase-postgres-13\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Community Day\",\"https://supabase.com/blog/2021/07/26/supabase-community-day\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Epsilon3 Self-Host Supabase To Revolutionize Space Operations \",\"https://supabase.com/blog/2021/07/26/epsilon3-self-hosting\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Launch Week II: The SQL\",\"https://supabase.com/blog/2021/07/22/supabase-launch-week-sql\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Protecting reserved roles with PostgreSQL Hooks\",\"https://supabase.com/blog/2021/07/01/roles-postgres-hooks\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Beta June 2021\",\"https://supabase.com/blog/2021/07/02/supabase-beta-june-2021\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Beta May 2021\",\"https://supabase.com/blog/2021/06/02/supabase-beta-may-2021\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Beta April 2021\",\"https://supabase.com/blog/2021/05/03/supabase-beta-april-2021\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Beta March 2021\",\"https://supabase.com/blog/2021/04/06/supabase-beta-march-2021\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Workflows are coming to Supabase\",\"https://supabase.com/blog/2021/04/02/supabase-workflows\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"PgBouncer is now available in Supabase\",\"https://supabase.com/blog/2021/04/02/supabase-pgbouncer\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Dot Com\",\"https://supabase.com/blog/2021/04/02/supabase-dot-com\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Launches NFT Marketplace\",\"https://supabase.com/blog/2021/04/01/supabase-nft-marketplace\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase CLI\",\"https://supabase.com/blog/2021/03/31/supabase-cli\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Storage is now available in Supabase\",\"https://supabase.com/blog/2021/03/30/supabase-storage\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Beta Pricing\",\"https://supabase.com/blog/2021/03/29/pricing\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Launch week\",\"https://supabase.com/blog/2021/03/25/launch-week\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Angels of Supabase\",\"https://supabase.com/blog/2021/03/25/angels-of-supabase\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Developers stay up to date with intheloop.dev\",\"https://supabase.com/blog/2021/03/22/In-The-Loop\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Using Supabase in Replit\",\"https://supabase.com/blog/2021/03/11/using-supabase-replit\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Toad, a link shortener with simple APIs for low-coders\",\"https://supabase.com/blog/2021/03/08/toad-a-link-shortener-with-simple-apis-for-low-coders\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Postgres as a CRON Server\",\"https://supabase.com/blog/2021/03/05/postgres-as-a-cron-server\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Beta February 2021\",\"https://supabase.com/blog/2021/03/02/supabase-beta-february-2021\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Cracking PostgreSQL Interview Questions\",\"https://supabase.com/blog/2021/02/27/cracking-postgres-interview\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Roboflow.com choose Supabase to power Paint.wtf leaderboard\",\"https://supabase.com/blog/2021/02/09/case-study-roboflow\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Beta January 2021\",\"https://supabase.com/blog/2021/02/02/supabase-beta-january-2021\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Beta December 2020\",\"https://supabase.com/blog/2021/01/02/supabase-beta-december-2020\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Making the Supabase Dashboard Supa-fast\",\"https://supabase.com/blog/2020/12/13/supabase-dashboard-performance\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Partners With Strive School To Help Teach Open Source\",\"https://supabase.com/blog/2020/12/02/supabase-striveschool\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Xendit Built a Counter-Fraud Watchlist for the Fintech Industry\",\"https://supabase.com/blog/2020/12/02/case-study-xendit\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"TAYFA Built a No-Code Website Builder in Seven Days\",\"https://supabase.com/blog/2020/12/02/case-study-tayfa\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Monitoro Built a Web Crawler Handling Millions of API Requests\",\"https://supabase.com/blog/2020/12/02/case-study-monitoro\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Alpha November 2020\",\"https://supabase.com/blog/2020/12/01/supabase-alpha-november-2020\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Postgres Views\",\"https://supabase.com/blog/2020/11/18/postgresql-views\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Alpha October 2020\",\"https://supabase.com/blog/2020/11/02/supabase-alpha-october-2020\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase.js 1.0\",\"https://supabase.com/blog/2020/10/30/improved-dx\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Alpha September 2020\",\"https://supabase.com/blog/2020/10/03/supabase-alpha-september-2020\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Hacktoberfest 2020\",\"https://supabase.com/blog/2020/09/11/supabase-hacktoberfest-2020\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Alpha August 2020\",\"https://supabase.com/blog/2020/09/03/supabase-alpha-august-2020\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Auth\",\"https://supabase.com/blog/2020/08/05/supabase-auth\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Alpha July 2020\",\"https://supabase.com/blog/2020/08/02/supabase-alpha-july-2020\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Continuous PostgreSQL Backups using WAL-G\",\"https://supabase.com/blog/2020/08/02/continuous-postgresql-backup-walg\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Alpha Launch Postmortem\",\"https://supabase.com/blog/2020/07/10/alpha-launch-postmortem\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"What are PostgreSQL Templates?\",\"https://supabase.com/blog/2020/07/09/postgresql-templates\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Physical vs Logical Backups in PostgreSQL\",\"https://supabase.com/blog/2020/07/17/postgresql-physical-logical-backups\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Alpha June 2020\",\"https://supabase.com/blog/2020/07/01/supabase-alpha-june-2020\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Steve Chavez has joined Supabase\",\"https://supabase.com/blog/2020/06/15/supabase-steve-chavez\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Alpha May 2020\",\"https://supabase.com/blog/2020/06/01/supabase-alpha-may-2020\"\n\"5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb\",\"Supabase Alpha April 2020\",\"https://supabase.com/blog/2020/05/01/supabase-alpha-april-2020\"\n"
  },
  {
    "path": "data/seed/comments.csv",
    "content": "postId,profileId,message\n32,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,I agree!\n33,3e223118-04b2-4faa-8ed9-d3995fc50975,Great story.\n34,dc1b4809-2c14-42a3-a384-ca65718e3421,Yea ... maybe.\n35,8a773ce6-9d46-4a76-b06b-436724cd1ce4,Best. News. Ever.\n36,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,I agree!\n37,3e223118-04b2-4faa-8ed9-d3995fc50975,Great story.\n38,dc1b4809-2c14-42a3-a384-ca65718e3421,Yea ... maybe.\n39,8a773ce6-9d46-4a76-b06b-436724cd1ce4,Best. News. Ever.\n40,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,I agree!\n41,3e223118-04b2-4faa-8ed9-d3995fc50975,Great story.\n42,dc1b4809-2c14-42a3-a384-ca65718e3421,Yea ... maybe.\n43,8a773ce6-9d46-4a76-b06b-436724cd1ce4,Best. News. Ever.\n44,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,I agree!\n45,3e223118-04b2-4faa-8ed9-d3995fc50975,Great story.\n46,dc1b4809-2c14-42a3-a384-ca65718e3421,Yea ... maybe.\n47,8a773ce6-9d46-4a76-b06b-436724cd1ce4,Best. News. Ever.\n48,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,Great story.\n49,3e223118-04b2-4faa-8ed9-d3995fc50975,Yea ... maybe.\n50,dc1b4809-2c14-42a3-a384-ca65718e3421,Best. News. Ever.\n51,8a773ce6-9d46-4a76-b06b-436724cd1ce4,I agree!\n52,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,Great story.\n53,3e223118-04b2-4faa-8ed9-d3995fc50975,Yea ... maybe.\n54,dc1b4809-2c14-42a3-a384-ca65718e3421,Best. News. Ever.\n55,8a773ce6-9d46-4a76-b06b-436724cd1ce4,I agree!\n56,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,Great story.\n57,3e223118-04b2-4faa-8ed9-d3995fc50975,Yea ... maybe.\n58,dc1b4809-2c14-42a3-a384-ca65718e3421,Best. News. Ever.\n59,8a773ce6-9d46-4a76-b06b-436724cd1ce4,I agree!\n60,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,Great story.\n61,3e223118-04b2-4faa-8ed9-d3995fc50975,Yea ... maybe.\n62,dc1b4809-2c14-42a3-a384-ca65718e3421,Best. News. Ever.\n83,8a773ce6-9d46-4a76-b06b-436724cd1ce4,I agree!\n84,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,Great story.\n85,3e223118-04b2-4faa-8ed9-d3995fc50975,Yea ... maybe.\n86,dc1b4809-2c14-42a3-a384-ca65718e3421,Best. News. Ever.\n3,8a773ce6-9d46-4a76-b06b-436724cd1ce4,Yea ... maybe.\n4,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,Best. News. Ever.\n6,3e223118-04b2-4faa-8ed9-d3995fc50975,I agree!\n8,dc1b4809-2c14-42a3-a384-ca65718e3421,Great story.\n9,8a773ce6-9d46-4a76-b06b-436724cd1ce4,Yea ... maybe.\n10,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,I agree!\n11,3e223118-04b2-4faa-8ed9-d3995fc50975,Great story.\n12,dc1b4809-2c14-42a3-a384-ca65718e3421,Yea ... maybe.\n13,8a773ce6-9d46-4a76-b06b-436724cd1ce4,Best. News. Ever.\n14,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,I agree!\n15,3e223118-04b2-4faa-8ed9-d3995fc50975,I agree!\n16,dc1b4809-2c14-42a3-a384-ca65718e3421,Great story.\n17,8a773ce6-9d46-4a76-b06b-436724cd1ce4,Yea ... maybe.\n18,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,I agree!\n19,3e223118-04b2-4faa-8ed9-d3995fc50975,Great story.\n20,dc1b4809-2c14-42a3-a384-ca65718e3421,Yea ... maybe.\n21,8a773ce6-9d46-4a76-b06b-436724cd1ce4,I agree!\n23,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,Great story.\n24,3e223118-04b2-4faa-8ed9-d3995fc50975,Yea ... maybe.\n25,dc1b4809-2c14-42a3-a384-ca65718e3421,I agree!\n26,8a773ce6-9d46-4a76-b06b-436724cd1ce4,Great story.\n27,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,Yea ... maybe.\n28,3e223118-04b2-4faa-8ed9-d3995fc50975,Best. News. Ever.\n29,dc1b4809-2c14-42a3-a384-ca65718e3421,I agree!\n30,8a773ce6-9d46-4a76-b06b-436724cd1ce4,Great story.\n63,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,Yea ... maybe.\n64,3e223118-04b2-4faa-8ed9-d3995fc50975,I agree!\n65,dc1b4809-2c14-42a3-a384-ca65718e3421,Great story.\n66,8a773ce6-9d46-4a76-b06b-436724cd1ce4,Yea ... maybe.\n67,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,I agree!\n68,3e223118-04b2-4faa-8ed9-d3995fc50975,Great story.\n69,dc1b4809-2c14-42a3-a384-ca65718e3421,Yea ... maybe.\n70,8a773ce6-9d46-4a76-b06b-436724cd1ce4,Best. News. Ever.\n71,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,I agree!\n72,3e223118-04b2-4faa-8ed9-d3995fc50975,Great story.\n73,dc1b4809-2c14-42a3-a384-ca65718e3421,Yea ... maybe.\n74,8a773ce6-9d46-4a76-b06b-436724cd1ce4,Best. News. Ever.\n75,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,Best. News. Ever.\n76,3e223118-04b2-4faa-8ed9-d3995fc50975,I agree!\n77,dc1b4809-2c14-42a3-a384-ca65718e3421,Great story.\n78,8a773ce6-9d46-4a76-b06b-436724cd1ce4,Yea ... maybe.\n79,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,Best. News. Ever.\n80,3e223118-04b2-4faa-8ed9-d3995fc50975,Great story.\n81,dc1b4809-2c14-42a3-a384-ca65718e3421,Yea ... maybe.\n82,8a773ce6-9d46-4a76-b06b-436724cd1ce4,Best. News. Ever.\n22,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,I agree!\n7,3e223118-04b2-4faa-8ed9-d3995fc50975,Great story.\n2,dc1b4809-2c14-42a3-a384-ca65718e3421,Yea ... maybe.\n5,8a773ce6-9d46-4a76-b06b-436724cd1ce4,I agree!\n90,5fdfeaaa-c9aa-40fe-8d8a-d0f3abbf4ceb,Great story.\n89,3e223118-04b2-4faa-8ed9-d3995fc50975,Yea ... maybe.\n31,dc1b4809-2c14-42a3-a384-ca65718e3421,Best. News. Ever.\n"
  },
  {
    "path": "data/supabase/00-initial-schema.sql",
    "content": "-- Set up realtime\ncreate schema if not exists realtime;\n-- create publication supabase_realtime; -- defaults to empty publication\ncreate publication supabase_realtime;\n\n-- Supabase super admin\ncreate user supabase_admin;\nalter user  supabase_admin with superuser createdb createrole replication bypassrls;\n\n-- Extension namespacing\ncreate schema if not exists extensions;\ncreate extension if not exists \"uuid-ossp\"      with schema extensions;\ncreate extension if not exists pgcrypto         with schema extensions;\ncreate extension if not exists pgjwt            with schema extensions;\n\n-- Set up auth roles for the developer\ncreate role anon                nologin noinherit;\ncreate role authenticated       nologin noinherit; -- \"logged in\" user: web_user, app_user, etc\ncreate role service_role        nologin noinherit bypassrls; -- allow developers to create JWT's that bypass their policies\n\ncreate user authenticator noinherit;\ngrant anon              to authenticator;\ngrant authenticated     to authenticator;\ngrant service_role      to authenticator;\ngrant supabase_admin    to authenticator;\n\ngrant usage                     on schema public to postgres, anon, authenticated, service_role;\nalter default privileges in schema public grant all on tables to postgres, anon, authenticated, service_role;\nalter default privileges in schema public grant all on functions to postgres, anon, authenticated, service_role;\nalter default privileges in schema public grant all on sequences to postgres, anon, authenticated, service_role;\n\n-- Allow Extensions to be used in the API\ngrant usage                     on schema extensions to postgres, anon, authenticated, service_role;\n\n-- Set up namespacing\nalter user supabase_admin SET search_path TO public, extensions; -- don't include the \"auth\" schema\n\n-- These are required so that the users receive grants whenever \"supabase_admin\" creates tables/function\nalter default privileges for user supabase_admin in schema public grant all\n    on sequences to postgres, anon, authenticated, service_role;\nalter default privileges for user supabase_admin in schema public grant all\n    on tables to postgres, anon, authenticated, service_role;\nalter default privileges for user supabase_admin in schema public grant all\n    on functions to postgres, anon, authenticated, service_role;\n\n-- Set short statement/query timeouts for API roles\nalter role anon set statement_timeout = '3s';\nalter role authenticated set statement_timeout = '8s';\n"
  },
  {
    "path": "data/supabase/01-auth-schema.sql",
    "content": "\nCREATE SCHEMA IF NOT EXISTS auth AUTHORIZATION supabase_admin;\n\n-- auth.users definition\n\nCREATE TABLE auth.users (\n\tinstance_id uuid NULL,\n\tid uuid NOT NULL UNIQUE,\n\taud varchar(255) NULL,\n\t\"role\" varchar(255) NULL,\n\temail varchar(255) NULL UNIQUE,\n\tencrypted_password varchar(255) NULL,\n\tconfirmed_at timestamptz NULL,\n\tinvited_at timestamptz NULL,\n\tconfirmation_token varchar(255) NULL,\n\tconfirmation_sent_at timestamptz NULL,\n\trecovery_token varchar(255) NULL,\n\trecovery_sent_at timestamptz NULL,\n\temail_change_token varchar(255) NULL,\n\temail_change varchar(255) NULL,\n\temail_change_sent_at timestamptz NULL,\n\tlast_sign_in_at timestamptz NULL,\n\traw_app_meta_data jsonb NULL,\n\traw_user_meta_data jsonb NULL,\n\tis_super_admin bool NULL,\n\tcreated_at timestamptz NULL,\n\tupdated_at timestamptz NULL,\n\tCONSTRAINT users_pkey PRIMARY KEY (id)\n);\nCREATE INDEX users_instance_id_email_idx ON auth.users USING btree (instance_id, email);\nCREATE INDEX users_instance_id_idx ON auth.users USING btree (instance_id);\ncomment on table auth.users is 'Auth: Stores user login data within a secure schema.';\n\n-- auth.refresh_tokens definition\n\nCREATE TABLE auth.refresh_tokens (\n\tinstance_id uuid NULL,\n\tid bigserial NOT NULL,\n\t\"token\" varchar(255) NULL,\n\tuser_id varchar(255) NULL,\n\trevoked bool NULL,\n\tcreated_at timestamptz NULL,\n\tupdated_at timestamptz NULL,\n\tCONSTRAINT refresh_tokens_pkey PRIMARY KEY (id)\n);\nCREATE INDEX refresh_tokens_instance_id_idx ON auth.refresh_tokens USING btree (instance_id);\nCREATE INDEX refresh_tokens_instance_id_user_id_idx ON auth.refresh_tokens USING btree (instance_id, user_id);\nCREATE INDEX refresh_tokens_token_idx ON auth.refresh_tokens USING btree (token);\ncomment on table auth.refresh_tokens is 'Auth: Store of tokens used to refresh JWT tokens once they expire.';\n\n-- auth.instances definition\n\nCREATE TABLE auth.instances (\n\tid uuid NOT NULL,\n\tuuid uuid NULL,\n\traw_base_config text NULL,\n\tcreated_at timestamptz NULL,\n\tupdated_at timestamptz NULL,\n\tCONSTRAINT instances_pkey PRIMARY KEY (id)\n);\ncomment on table auth.instances is 'Auth: Manages users across multiple sites.';\n\n-- auth.audit_log_entries definition\n\nCREATE TABLE auth.audit_log_entries (\n\tinstance_id uuid NULL,\n\tid uuid NOT NULL,\n\tpayload json NULL,\n\tcreated_at timestamptz NULL,\n\tCONSTRAINT audit_log_entries_pkey PRIMARY KEY (id)\n);\nCREATE INDEX audit_logs_instance_id_idx ON auth.audit_log_entries USING btree (instance_id);\ncomment on table auth.audit_log_entries is 'Auth: Audit trail for user actions.';\n\n-- auth.schema_migrations definition\n\nCREATE TABLE auth.schema_migrations (\n\t\"version\" varchar(255) NOT NULL,\n\tCONSTRAINT schema_migrations_pkey PRIMARY KEY (\"version\")\n);\ncomment on table auth.schema_migrations is 'Auth: Manages updates to the auth system.';\n\nINSERT INTO auth.schema_migrations (version)\nVALUES  ('20171026211738'),\n        ('20171026211808'),\n        ('20171026211834'),\n        ('20180103212743'),\n        ('20180108183307'),\n        ('20180119214651'),\n        ('20180125194653');\n\ncreate or replace function auth.uid() \nreturns uuid \nlanguage sql stable\nas $$\n  select \n  \tcoalesce(\n\t\tcurrent_setting('request.jwt.claim.sub', true),\n\t\t(current_setting('request.jwt.claims', true)::jsonb ->> 'sub')\n\t)::uuid\n$$;\n\ncreate or replace function auth.role() \nreturns text \nlanguage sql stable\nas $$\n  select \n  \tcoalesce(\n\t\tcurrent_setting('request.jwt.claim.role', true),\n\t\t(current_setting('request.jwt.claims', true)::jsonb ->> 'role')\n\t)::text\n$$;\n\ncreate or replace function auth.email() \nreturns text \nlanguage sql stable\nas $$\n  select \n  \tcoalesce(\n\t\tcurrent_setting('request.jwt.claim.email', true),\n\t\t(current_setting('request.jwt.claims', true)::jsonb ->> 'email')\n\t)::text\n$$;\n\n-- usage on auth functions to API roles\nGRANT USAGE ON SCHEMA auth TO anon, authenticated, service_role;\n\n-- Supabase super admin\nCREATE USER supabase_auth_admin NOINHERIT CREATEROLE LOGIN NOREPLICATION;\nGRANT ALL PRIVILEGES ON SCHEMA auth TO supabase_auth_admin;\nGRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA auth TO supabase_auth_admin;\nGRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA auth TO supabase_auth_admin;\nALTER USER supabase_auth_admin SET search_path = \"auth\";\nALTER table \"auth\".users OWNER TO supabase_auth_admin;\nALTER table \"auth\".refresh_tokens OWNER TO supabase_auth_admin;\nALTER table \"auth\".audit_log_entries OWNER TO supabase_auth_admin;\nALTER table \"auth\".instances OWNER TO supabase_auth_admin;\nALTER table \"auth\".schema_migrations OWNER TO supabase_auth_admin;\n\nALTER FUNCTION \"auth\".\"uid\" OWNER TO supabase_auth_admin;\nALTER FUNCTION \"auth\".\"role\" OWNER TO supabase_auth_admin;\nALTER FUNCTION \"auth\".\"email\" OWNER TO supabase_auth_admin;\nGRANT EXECUTE ON FUNCTION \"auth\".\"uid\"() TO PUBLIC;\nGRANT EXECUTE ON FUNCTION \"auth\".\"role\"() TO PUBLIC;\nGRANT EXECUTE ON FUNCTION \"auth\".\"email\"() TO PUBLIC;\n"
  },
  {
    "path": "data/supabase/02-storage-schema.sql",
    "content": "CREATE SCHEMA IF NOT EXISTS storage AUTHORIZATION supabase_admin;\n\ngrant usage on schema storage to postgres, anon, authenticated, service_role;\nalter default privileges in schema storage grant all on tables to postgres, anon, authenticated, service_role;\nalter default privileges in schema storage grant all on functions to postgres, anon, authenticated, service_role;\nalter default privileges in schema storage grant all on sequences to postgres, anon, authenticated, service_role;\n\nCREATE TABLE \"storage\".\"buckets\" (\n    \"id\" text not NULL,\n    \"name\" text NOT NULL,\n    \"owner\" uuid,\n    \"created_at\" timestamptz DEFAULT now(),\n    \"updated_at\" timestamptz DEFAULT now(),\n    CONSTRAINT \"buckets_owner_fkey\" FOREIGN KEY (\"owner\") REFERENCES \"auth\".\"users\"(\"id\"),\n    PRIMARY KEY (\"id\")\n);\nCREATE UNIQUE INDEX \"bname\" ON \"storage\".\"buckets\" USING BTREE (\"name\");\n\nCREATE TABLE \"storage\".\"objects\" (\n    \"id\" uuid NOT NULL DEFAULT extensions.uuid_generate_v4(),\n    \"bucket_id\" text,\n    \"name\" text,\n    \"owner\" uuid,\n    \"created_at\" timestamptz DEFAULT now(),\n    \"updated_at\" timestamptz DEFAULT now(),\n    \"last_accessed_at\" timestamptz DEFAULT now(),\n    \"metadata\" jsonb,\n    CONSTRAINT \"objects_bucketId_fkey\" FOREIGN KEY (\"bucket_id\") REFERENCES \"storage\".\"buckets\"(\"id\"),\n    CONSTRAINT \"objects_owner_fkey\" FOREIGN KEY (\"owner\") REFERENCES \"auth\".\"users\"(\"id\"),\n    PRIMARY KEY (\"id\")\n);\nCREATE UNIQUE INDEX \"bucketid_objname\" ON \"storage\".\"objects\" USING BTREE (\"bucket_id\",\"name\");\nCREATE INDEX name_prefix_search ON storage.objects(name text_pattern_ops);\n\nALTER TABLE storage.objects ENABLE ROW LEVEL SECURITY;\n\nCREATE FUNCTION storage.foldername(name text)\n RETURNS text[]\n LANGUAGE plpgsql\nAS $function$\nDECLARE\n_parts text[];\nBEGIN\n\tselect string_to_array(name, '/') into _parts;\n\treturn _parts[1:array_length(_parts,1)-1];\nEND\n$function$;\n\nCREATE FUNCTION storage.filename(name text)\n RETURNS text\n LANGUAGE plpgsql\nAS $function$\nDECLARE\n_parts text[];\nBEGIN\n\tselect string_to_array(name, '/') into _parts;\n\treturn _parts[array_length(_parts,1)];\nEND\n$function$;\n\nCREATE FUNCTION storage.extension(name text)\n RETURNS text\n LANGUAGE plpgsql\nAS $function$\nDECLARE\n_parts text[];\n_filename text;\nBEGIN\n\tselect string_to_array(name, '/') into _parts;\n\tselect _parts[array_length(_parts,1)] into _filename;\n\t-- @todo return the last part instead of 2\n\treturn split_part(_filename, '.', 2);\nEND\n$function$;\n\nCREATE FUNCTION storage.search(prefix text, bucketname text, limits int DEFAULT 100, levels int DEFAULT 1, offsets int DEFAULT 0)\n RETURNS TABLE (\n    name text,\n    id uuid,\n    updated_at TIMESTAMPTZ,\n    created_at TIMESTAMPTZ,\n    last_accessed_at TIMESTAMPTZ,\n    metadata jsonb\n  )\n LANGUAGE plpgsql\nAS $function$\nDECLARE\n_bucketId text;\nBEGIN\n    -- will be replaced by migrations when server starts\n    -- saving space for cloud-init\nEND\n$function$;\n\n-- create migrations table\n-- https://github.com/ThomWright/postgres-migrations/blob/master/src/migrations/0_create-migrations-table.sql\n-- we add this table here and not let it be auto-created so that the permissions are properly applied to it\nCREATE TABLE IF NOT EXISTS storage.migrations (\n  id integer PRIMARY KEY,\n  name varchar(100) UNIQUE NOT NULL,\n  hash varchar(40) NOT NULL, -- sha1 hex encoded hash of the file name and contents, to ensure it hasn't been altered since applying the migration\n  executed_at timestamp DEFAULT current_timestamp\n);\n\nCREATE USER supabase_storage_admin NOINHERIT CREATEROLE LOGIN NOREPLICATION;\nGRANT ALL PRIVILEGES ON SCHEMA storage TO supabase_storage_admin;\nGRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA storage TO supabase_storage_admin;\nGRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA storage TO supabase_storage_admin;\nALTER USER supabase_storage_admin SET search_path = \"storage\";\nALTER table \"storage\".objects owner to supabase_storage_admin;\nALTER table \"storage\".buckets owner to supabase_storage_admin;\nALTER table \"storage\".migrations OWNER TO supabase_storage_admin;\nALTER function \"storage\".foldername(text) owner to supabase_storage_admin;\nALTER function \"storage\".filename(text) owner to supabase_storage_admin;\nALTER function \"storage\".extension(text) owner to supabase_storage_admin;\nALTER function \"storage\".search(text,text,int,int,int) owner to supabase_storage_admin;\n"
  },
  {
    "path": "data/supabase/03-post-setup.sql",
    "content": "ALTER ROLE postgres SET search_path TO \"\\$user\",public,extensions;\nCREATE OR REPLACE FUNCTION extensions.notify_api_restart()\nRETURNS event_trigger\nLANGUAGE plpgsql\nAS $$\nBEGIN\n    NOTIFY pgrst, 'reload schema';\nEND;\n$$;\nCREATE EVENT TRIGGER api_restart ON ddl_command_end\nEXECUTE PROCEDURE extensions.notify_api_restart();\nCOMMENT ON FUNCTION extensions.notify_api_restart IS 'Sends a notification to the API to restart. If your database schema has changed, this is required so that Supabase can rebuild the relationships.';\n\n-- Trigger for pg_cron\nCREATE OR REPLACE FUNCTION extensions.grant_pg_cron_access()\nRETURNS event_trigger\nLANGUAGE plpgsql\nAS $$\nDECLARE\n  schema_is_cron bool;\nBEGIN\n  schema_is_cron = (\n    SELECT n.nspname = 'cron'\n    FROM pg_event_trigger_ddl_commands() AS ev\n    LEFT JOIN pg_catalog.pg_namespace AS n\n      ON ev.objid = n.oid\n  );\n\n  IF schema_is_cron\n  THEN\n    grant usage on schema cron to postgres with grant option;\n\n    alter default privileges in schema cron grant all on tables to postgres with grant option;\n    alter default privileges in schema cron grant all on functions to postgres with grant option;\n    alter default privileges in schema cron grant all on sequences to postgres with grant option;\n\n    alter default privileges for user supabase_admin in schema cron grant all\n        on sequences to postgres with grant option;\n    alter default privileges for user supabase_admin in schema cron grant all\n        on tables to postgres with grant option;\n    alter default privileges for user supabase_admin in schema cron grant all\n        on functions to postgres with grant option;\n\n    grant all privileges on all tables in schema cron to postgres with grant option; \n\n  END IF;\n\nEND;\n$$;\nCREATE EVENT TRIGGER issue_pg_cron_access ON ddl_command_end WHEN TAG in ('CREATE SCHEMA')\nEXECUTE PROCEDURE extensions.grant_pg_cron_access();\nCOMMENT ON FUNCTION extensions.grant_pg_cron_access IS 'Grants access to pg_cron';\n\n-- Supabase dashboard user\nCREATE ROLE dashboard_user NOSUPERUSER CREATEDB CREATEROLE REPLICATION;\nGRANT ALL ON DATABASE postgres TO dashboard_user;\nGRANT ALL ON SCHEMA auth TO dashboard_user;\nGRANT ALL ON SCHEMA extensions TO dashboard_user;\nGRANT ALL ON SCHEMA storage TO dashboard_user;\nGRANT ALL ON ALL TABLES IN SCHEMA auth TO dashboard_user;\nGRANT ALL ON ALL TABLES IN SCHEMA extensions TO dashboard_user;\n-- GRANT ALL ON ALL TABLES IN SCHEMA storage TO dashboard_user;\nGRANT ALL ON ALL SEQUENCES IN SCHEMA auth TO dashboard_user;\nGRANT ALL ON ALL SEQUENCES IN SCHEMA storage TO dashboard_user;\nGRANT ALL ON ALL SEQUENCES IN SCHEMA extensions TO dashboard_user;\nGRANT ALL ON ALL ROUTINES IN SCHEMA auth TO dashboard_user;\nGRANT ALL ON ALL ROUTINES IN SCHEMA storage TO dashboard_user;\nGRANT ALL ON ALL ROUTINES IN SCHEMA extensions TO dashboard_user;\n"
  },
  {
    "path": "data/supabase/04-public-profiles.sql",
    "content": "-- Create a table for Public Profiles\ncreate table \"Profile\" (\n  id uuid references auth.users not null,\n  updatedAt timestamp with time zone,\n  username text unique,\n  avatarUrl text,\n  website text,\n\n  primary key (id),\n  unique(username),\n  constraint usernameLength check (char_length(username) >= 3)\n);\n\nalter table \"Profile\" enable row level security;\n\ncreate policy \"Public profiles are viewable by everyone.\"\n  on \"Profile\" for select\n  using ( true );\n\ncreate policy \"Users can insert their own profile.\"\n  on \"Profile\" for insert\n  with check ( auth.uid() = id );\n\ncreate policy \"Users can update own profile.\"\n  on \"Profile\" for update\n  using ( auth.uid() = id );\n\n-- Set up Realtime!\nbegin;\n  drop publication if exists supabase_realtime;\n  create publication supabase_realtime;\ncommit;\nalter publication supabase_realtime add table \"Profile\";\n\n-- Set up Storage!\ninsert into storage.buckets (id, name)\nvalues ('avatars', 'avatars');\n\ncreate policy \"Avatar images are publicly accessible.\"\n  on storage.objects for select\n  using ( bucket_id = 'avatars' );\n\ncreate policy \"Anyone can upload an avatar.\"\n  on storage.objects for insert\n  with check ( bucket_id = 'avatars' );\n\ncreate policy \"Anyone can update an avatar.\"\n  on storage.objects for update\n  with check ( bucket_id = 'avatars' );\n"
  },
  {
    "path": "data/supabase/05-setup-total-counts.sql",
    "content": "comment on table \"Profile\" is '@graphql({\"totalCount\": {\"enabled\": true}})';\ncomment on table \"Post\" is '@graphql({\"totalCount\": {\"enabled\": true}})';\ncomment on table \"Comment\" is '@graphql({\"totalCount\": {\"enabled\": true}})';\ncomment on table \"Vote\" is '@graphql({\"totalCount\": {\"enabled\": true}})';\n\n"
  },
  {
    "path": "data/supabase/05-setup-user-profile-trigger.sql",
    "content": "CREATE OR REPLACE FUNCTION public.handle_new_user()\n RETURNS trigger\n LANGUAGE plpgsql\n SECURITY DEFINER\nAS $function$\nbegin\n  insert into public.\"Profile\" (id, \"avatarUrl\", username)\n  values (new.id, 'https://www.gravatar.com/avatar/' || md5(new.email) || '?d=mp', split_part(new.email, '@', 1) || '-' || floor(random() * 10000));\n  return new;\nend;\n$function$\n\nCREATE TRIGGER on_auth_user_created AFTER INSERT ON auth.users FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();\n"
  },
  {
    "path": "data/supabase/06-update-post-vote-counts.sql",
    "content": "CREATE OR REPLACE FUNCTION public.update_vote_counts()\nRETURNS trigger as $$\nBEGIN\n\nWITH r AS (\nSELECT\n\tcoalesce(\"Vote\".\"postId\", \"Post\".id) AS \"postId\",\n\tcount(1) \"voteTotal\",\n\tcount(1) FILTER (WHERE direction = 'UP') \"upVoteTotal\",\n\tcount(1) FILTER (WHERE direction = 'DOWN') \"downVoteTotal\",\n\tcoalesce(sum(\n\t\t\tCASE WHEN direction = 'UP' THEN\n\t\t\t\t1\n\t\t\tWHEN direction = 'DOWN' THEN\n\t\t\t\t-1\n\t\t\tELSE\n\t\t\t\t0\n\t\t\tEND), 0) \"voteDelta\",\n\tround(coalesce((sum(\n\t\tCASE WHEN direction = 'UP' THEN\n\t\t\t1\n\t\tWHEN direction = 'DOWN' THEN\n\t\t\t-1\n\t\tELSE\n\t\t\t0\n\t\tEND ) - 1) / (DATE_PART('hour', now() - max(\"Vote\".\"createdAt\")) + 2) ^ 1.8 * 100000, -2147483648)::numeric, 0) AS \"score\",\n\trank() OVER (ORDER BY round(coalesce((sum( CASE WHEN direction = 'UP' THEN\n\t\t\t1\n\t\tWHEN direction = 'DOWN' THEN\n\t\t\t-1\n\t\tELSE\n\t\t\t0\n\t\tEND) - 1) / (DATE_PART('hour', now() - max(\"Vote\".\"createdAt\")) + 2) ^ 1.8 * 100000, -2147483648)::numeric, 0)\n\t\tDESC,\n\t\t\"Post\".\"createdAt\" DESC,\n\t\t\"Post\".title ASC) \"voteRank\"\nFROM\n\t\"Vote\"\n\tRIGHT JOIN \"Post\" ON \"Vote\".\"postId\" = \"Post\".id\nGROUP BY\n\t\"Post\".id,\n\t\"Vote\".\"postId\"\n)\n\nUPDATE\n\tpublic. \"Post\"\nSET\n\t\"upVoteTotal\" = r. \"upVoteTotal\",\n\t\"downVoteTotal\" = r. \"downVoteTotal\",\n\t\"voteTotal\" = r. \"voteTotal\",\n  \"voteDelta\" = r. \"voteDelta\",\n\t\"voteRank\" = r. \"voteRank\",\n  \"score\" = r. \"score\"\nFROM\n\tr\nWHERE\n\tr.\"postId\" = public. \"Post\".id;\n\nRETURN new;\nEND;\n$$ language plpgsql security definer;\n\nCREATE TRIGGER on_vote_created AFTER INSERT ON public.\"Vote\" FOR EACH ROW EXECUTE FUNCTION public.update_vote_counts();\nCREATE TRIGGER on_vote_deleted AFTER DELETE ON public.\"Vote\" FOR EACH ROW EXECUTE FUNCTION public.update_vote_counts();\n\n"
  },
  {
    "path": "data/supabase/07-add-post-title-url-constraints.sql",
    "content": "ALTER TABLE \"Post\"\nADD CONSTRAINT post_title_length check (char_length(title) > 0);\n\nALTER TABLE \"Post\"\nADD CONSTRAINT post_url_length check (char_length(url) > 0);\n"
  },
  {
    "path": "data/supabase/08-update-post-cascahe-delete-constraints.sql",
    "content": "ALTER TABLE ONLY public.\"Comment\"\n    DROP CONSTRAINT \"Comment_postId_fkey\";\n\nALTER TABLE ONLY public.\"Comment\"\n    ADD CONSTRAINT \"Comment_postId_fkey\" FOREIGN KEY (\"postId\") REFERENCES public.\"Post\"(id) ON DELETE CASCADE;\n\nALTER TABLE ONLY public.\"Vote\"\n    DROP CONSTRAINT \"DownVote_postId_fkey\";\n\nALTER TABLE ONLY public.\"Vote\"\n    ADD CONSTRAINT \"Vote_postId_fkey\" FOREIGN KEY (\"postId\") REFERENCES public.\"Post\"(id) ON DELETE CASCADE;\n\n"
  },
  {
    "path": "data/supabase/09-update-all-gravatars.sql",
    "content": "WITH a AS (\n\tSELECT\n\t\tid,\n\t\t'https://www.gravatar.com/avatar/' || md5(email) || '?d=mp' AS \"avatarUrl\",\n\t\temail\n\tFROM\n\t\tauth.users\n)\nUPDATE\n\tpublic. \"Profile\"\nSET\n\t\"avatarUrl\" = a. \"avatarUrl\"\nFROM\n\ta\nWHERE\n\ta.id = public. \"Profile\".id\n"
  },
  {
    "path": "data/supabase/rls-policies.md",
    "content": "# Row Level Security Matrix (RLS)\n\n## Profile\n\n- All users can `SELECT` all `PROFILE`s\n- Only authenticated users can CREATE `PROFILE`\n- Only `PROFILE`s where auth user is `id` can `UPDATE`\n- No `PROFILE` `DELETE`. This might be an Admin role eventually.\n\n## Posts\n\n- All users can `SELECT` all `POST`s\n- Only authenticated users can `CREATE POST`\n- Only `POST`s where auth user is `profileId` can `UPDATE`\n- Only `POST`s where auth user is `profileId` can `DELETE`\n\nFYI: `DELETE POST` cascade to `COMMENT`s and `VOTE`s\n\n## Comment\n\n- All users can `SELECT` all `COMMENT`s\n- Only authenticated users can `CREATE COMMENT`\n- Only `COMMENT`s where auth user is `profileId` can `UPDATE`\n- Only `COMMENT`s where auth user is `profileId` can `DELETE`\n\n## Vote\n\n- All users can `SELECT` all `VOTE`s\n- Only authenticated users can `CREATE VOTE`\n- Only `VOTE`s where auth user is `profileId` can `UPDATE`\n- Only `VOTE`s where auth user is `profileId` can `DELETE`\n\nNote: Does this mean I can see how people voted?\n\n## Export of Policies\n\nYou can query all policies via: `select * from pg_policies`.\n\nSee: [row_level_security_polices.csv](../db/row_level_security_polices.csv)\n\n| schemaname | tablename | policyname                                | permissive | roles    | cmd    | qual                          | with_check                            |\n| ---------- | --------- | ----------------------------------------- | ---------- | -------- | ------ | ----------------------------- | ------------------------------------- |\n| public     | Profile   | Public profiles are viewable by everyone. | PERMISSIVE | {public} | SELECT | true                          |                                       |\n| public     | Profile   | Users can insert their own profile.       | PERMISSIVE | {public} | INSERT |                               | (auth.uid() = id)                     |\n| public     | Profile   | Users can update own profile.             | PERMISSIVE | {public} | UPDATE | (auth.uid() = id)             |                                       |\n| storage    | objects   | Avatar images are publicly accessible.    | PERMISSIVE | {public} | SELECT | (bucket_id = 'avatars'::text) |                                       |\n| storage    | objects   | Anyone can upload an avatar.              | PERMISSIVE | {public} | INSERT |                               | (bucket_id = 'avatars'::text)         |\n| storage    | objects   | Anyone can update an avatar.              | PERMISSIVE | {public} | UPDATE |                               | (bucket_id = 'avatars'::text)         |\n| public     | Post      | All users can view posts                  | PERMISSIVE | {public} | SELECT | true                          |                                       |\n| public     | Post      | Only authenticated users can create posts | PERMISSIVE | {public} | INSERT |                               | (auth.role() = 'authenticated'::text) |\n| public     | Post      | Users can delete their own posts          | PERMISSIVE | {public} | DELETE | (auth.uid() = \"profileId\")    |                                       |\n| public     | Post      | Users can edit their own posts            | PERMISSIVE | {public} | UPDATE | (auth.uid() = \"profileId\")    | (auth.uid() = \"profileId\")            |\n| public     | Comment   | Everyone can view comments                | PERMISSIVE | {public} | SELECT | true                          |                                       |\n| public     | Comment   | Only authenticated users can comment      | PERMISSIVE | {public} | INSERT |                               | (auth.role() = 'authenticated'::text) |\n| public     | Comment   | User can edit their own comments          | PERMISSIVE | {public} | UPDATE | (auth.uid() = \"profileId\")    | (auth.uid() = \"profileId\")            |\n| public     | Comment   | Users can delete their own comments       | PERMISSIVE | {public} | DELETE | (auth.uid() = \"profileId\")    |                                       |\n| public     | Vote      | Everyone can view votes                   | PERMISSIVE | {public} | SELECT | true                          |                                       |\n| public     | Vote      | Only authenticated users can vote         | PERMISSIVE | {public} | INSERT |                               | (auth.role() = 'authenticated'::text) |\n| public     | Vote      | Users can change their vote               | PERMISSIVE | {public} | UPDATE | (auth.uid() = \"profileId\")    | (auth.uid() = \"profileId\")            |\n| public     | Vote      | Users can delete their own votes          | PERMISSIVE | {public} | DELETE | (auth.uid() = \"profileId\")    |                                       |\n"
  },
  {
    "path": "graphql/queries/feed.graphql",
    "content": "# Your GraphQL query or mutation goes here\nquery {\n  feed: postCollection {\n    edges {\n      post: node {\n        id\n        title\n        url\n        upVotes: voteCollection(filter: { direction: { eq: \"UP\" } }) {\n          totalCount\n        }\n        downVotes: voteCollection(filter: { direction: { eq: \"DOWN\" } }) {\n          totalCount\n        }\n        comments: commentCollection {\n          edges {\n            node {\n              id\n              message\n              profile {\n                id\n                username\n                avatarUrl\n              }\n            }\n          }\n          commentCount: totalCount\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "graphql/queries/hasProfileVotes.graphql",
    "content": "query {\n  post: postCollection(filter: { id: { eq: 22 } }, first: 1) {\n    edges {\n      post: node {\n        id\n        title\n        upVoteCount: voteCollection(\n          filter: {\n            profileId: { eq: \"3e223118-04b2-4faa-8ed9-d3995fc50975\" }\n            direction: { eq: \"UP\" }\n          }\n        ) {\n          totalCount\n        }\n        downVoteCount: voteCollection(\n          filter: {\n            profileId: { eq: \"3e223118-04b2-4faa-8ed9-d3995fc50975\" }\n            direction: { eq: \"DOWN\" }\n          }\n        ) {\n          totalCount\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "graphql/queries/rankedFeed.graphql",
    "content": "query {\n  rankedFeed: postCollection(\n    orderBy: [\n      { voteRank: AscNullsFirst }\n      { score: DescNullsFirst }\n      { createdAt: DescNullsFirst }\n    ]\n  ) {\n    edges {\n      post: node {\n        id\n        title\n        url\n        upVoteTotal\n        downVoteTotal\n        voteTotal\n        voteDelta\n        score\n        voteRank\n        comments: commentCollection {\n          edges {\n            node {\n              id\n              message\n              profile {\n                id\n                username\n                avatarUrl\n              }\n            }\n          }\n          commentCount: totalCount\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "graphql/schema/schema.graphql",
    "content": "scalar BigInt\n\n\"\"\"\nBoolean expression comparing fields on type \"BigInt\"\n\"\"\"\ninput BigIntFilter {\n  eq: BigInt\n  gt: BigInt\n  gte: BigInt\n  lt: BigInt\n  lte: BigInt\n  neq: BigInt\n}\n\n\"\"\"\nBoolean expression comparing fields on type \"Boolean\"\n\"\"\"\ninput BooleanFilter {\n  eq: Boolean\n  gt: Boolean\n  gte: Boolean\n  lt: Boolean\n  lte: Boolean\n  neq: Boolean\n}\n\ntype Comment {\n  id: BigInt!\n  createdAt: Datetime\n  updatedAt: Datetime\n  message: String!\n  profileId: UUID!\n  postId: BigInt!\n  post: Post\n  profile: Profile\n}\n\ntype CommentConnection {\n  edges: [CommentEdge!]!\n  pageInfo: PageInfo!\n\n  \"\"\"The total number of records matching the `filter` criteria\"\"\"\n  totalCount: Int!\n}\n\ntype CommentDeleteResponse {\n  \"\"\"Count of the records impacted by the mutation\"\"\"\n  affectedCount: Int!\n\n  \"\"\"Array of records impacted by the mutation\"\"\"\n  records: [Comment!]!\n}\n\ntype CommentEdge {\n  cursor: String!\n  node: Comment\n}\n\ninput CommentFilter {\n  id: BigIntFilter\n  createdAt: DatetimeFilter\n  updatedAt: DatetimeFilter\n  message: StringFilter\n  profileId: UUIDFilter\n  postId: BigIntFilter\n}\n\ninput CommentInsertInput {\n  createdAt: Datetime\n  updatedAt: Datetime\n  message: String\n  profileId: UUID\n  postId: BigInt\n}\n\ntype CommentInsertResponse {\n  \"\"\"Count of the records impacted by the mutation\"\"\"\n  affectedCount: Int!\n\n  \"\"\"Array of records impacted by the mutation\"\"\"\n  records: [Comment!]!\n}\n\ninput CommentOrderBy {\n  id: OrderByDirection\n  createdAt: OrderByDirection\n  updatedAt: OrderByDirection\n  message: OrderByDirection\n  profileId: OrderByDirection\n  postId: OrderByDirection\n}\n\ninput CommentUpdateInput {\n  createdAt: Datetime\n  updatedAt: Datetime\n  message: String\n  profileId: UUID\n  postId: BigInt\n}\n\ntype CommentUpdateResponse {\n  \"\"\"Count of the records impacted by the mutation\"\"\"\n  affectedCount: Int!\n\n  \"\"\"Array of records impacted by the mutation\"\"\"\n  records: [Comment!]!\n}\n\nscalar Cursor\n\nscalar Date\n\n\"\"\"\nBoolean expression comparing fields on type \"Date\"\n\"\"\"\ninput DateFilter {\n  eq: Date\n  gt: Date\n  gte: Date\n  lt: Date\n  lte: Date\n  neq: Date\n}\n\nscalar Datetime\n\n\"\"\"\nBoolean expression comparing fields on type \"Datetime\"\n\"\"\"\ninput DatetimeFilter {\n  eq: Datetime\n  gt: Datetime\n  gte: Datetime\n  lt: Datetime\n  lte: Datetime\n  neq: Datetime\n}\n\nenum Direction {\n  DOWN\n  UP\n}\n\n\"\"\"\nBoolean expression comparing fields on type \"Float\"\n\"\"\"\ninput FloatFilter {\n  eq: Float\n  gt: Float\n  gte: Float\n  lt: Float\n  lte: Float\n  neq: Float\n}\n\n\"\"\"\nBoolean expression comparing fields on type \"Int\"\n\"\"\"\ninput IntFilter {\n  eq: Int\n  gt: Int\n  gte: Int\n  lt: Int\n  lte: Int\n  neq: Int\n}\n\nscalar JSON\n\n\"\"\"\nBoolean expression comparing fields on type \"JSON\"\n\"\"\"\ninput JSONFilter {\n  eq: JSON\n  neq: JSON\n}\n\n\"\"\"The root type for creating and mutating data\"\"\"\ntype Mutation {\n  \"\"\"Deletes zero or more records from the collection\"\"\"\n  deleteFromCommentCollection(\n    \"\"\"Restricts the mutation's impact to records matching the critera\"\"\"\n    filter: CommentFilter\n\n    \"\"\"\n    The maximum number of records in the collection permitted to be affected\n    \"\"\"\n    atMost: Int! = 1\n  ): CommentDeleteResponse!\n\n  \"\"\"Deletes zero or more records from the collection\"\"\"\n  deleteFromPostCollection(\n    \"\"\"Restricts the mutation's impact to records matching the critera\"\"\"\n    filter: PostFilter\n\n    \"\"\"\n    The maximum number of records in the collection permitted to be affected\n    \"\"\"\n    atMost: Int! = 1\n  ): PostDeleteResponse!\n\n  \"\"\"Deletes zero or more records from the collection\"\"\"\n  deleteFromProfileCollection(\n    \"\"\"Restricts the mutation's impact to records matching the critera\"\"\"\n    filter: ProfileFilter\n\n    \"\"\"\n    The maximum number of records in the collection permitted to be affected\n    \"\"\"\n    atMost: Int! = 1\n  ): ProfileDeleteResponse!\n\n  \"\"\"Deletes zero or more records from the collection\"\"\"\n  deleteFromVoteCollection(\n    \"\"\"Restricts the mutation's impact to records matching the critera\"\"\"\n    filter: VoteFilter\n\n    \"\"\"\n    The maximum number of records in the collection permitted to be affected\n    \"\"\"\n    atMost: Int! = 1\n  ): VoteDeleteResponse!\n\n  \"\"\"Adds one or more `CommentInsertResponse` records to the collection\"\"\"\n  insertIntoCommentCollection(objects: [CommentInsertInput!]!): CommentInsertResponse\n\n  \"\"\"Adds one or more `PostInsertResponse` records to the collection\"\"\"\n  insertIntoPostCollection(objects: [PostInsertInput!]!): PostInsertResponse\n\n  \"\"\"Adds one or more `ProfileInsertResponse` records to the collection\"\"\"\n  insertIntoProfileCollection(objects: [ProfileInsertInput!]!): ProfileInsertResponse\n\n  \"\"\"Adds one or more `VoteInsertResponse` records to the collection\"\"\"\n  insertIntoVoteCollection(objects: [VoteInsertInput!]!): VoteInsertResponse\n\n  \"\"\"Updates zero or more records in the collection\"\"\"\n  updateCommentCollection(\n    \"\"\"\n    Fields that are set will be updated for all records matching the `filter`\n    \"\"\"\n    set: CommentUpdateInput!\n\n    \"\"\"Restricts the mutation's impact to records matching the critera\"\"\"\n    filter: CommentFilter\n\n    \"\"\"\n    The maximum number of records in the collection permitted to be affected\n    \"\"\"\n    atMost: Int! = 1\n  ): CommentUpdateResponse!\n\n  \"\"\"Updates zero or more records in the collection\"\"\"\n  updatePostCollection(\n    \"\"\"\n    Fields that are set will be updated for all records matching the `filter`\n    \"\"\"\n    set: PostUpdateInput!\n\n    \"\"\"Restricts the mutation's impact to records matching the critera\"\"\"\n    filter: PostFilter\n\n    \"\"\"\n    The maximum number of records in the collection permitted to be affected\n    \"\"\"\n    atMost: Int! = 1\n  ): PostUpdateResponse!\n\n  \"\"\"Updates zero or more records in the collection\"\"\"\n  updateProfileCollection(\n    \"\"\"\n    Fields that are set will be updated for all records matching the `filter`\n    \"\"\"\n    set: ProfileUpdateInput!\n\n    \"\"\"Restricts the mutation's impact to records matching the critera\"\"\"\n    filter: ProfileFilter\n\n    \"\"\"\n    The maximum number of records in the collection permitted to be affected\n    \"\"\"\n    atMost: Int! = 1\n  ): ProfileUpdateResponse!\n\n  \"\"\"Updates zero or more records in the collection\"\"\"\n  updateVoteCollection(\n    \"\"\"\n    Fields that are set will be updated for all records matching the `filter`\n    \"\"\"\n    set: VoteUpdateInput!\n\n    \"\"\"Restricts the mutation's impact to records matching the critera\"\"\"\n    filter: VoteFilter\n\n    \"\"\"\n    The maximum number of records in the collection permitted to be affected\n    \"\"\"\n    atMost: Int! = 1\n  ): VoteUpdateResponse!\n}\n\n\"\"\"Defines a per-field sorting order\"\"\"\nenum OrderByDirection {\n  AscNullsFirst\n  AscNullsLast\n  DescNullsFirst\n  DescNullsLast\n}\n\ntype PageInfo {\n  endCursor: String\n  hasNextPage: Boolean!\n  hasPreviousPage: Boolean!\n  startCursor: String\n}\n\ntype Post {\n  id: BigInt!\n  createdAt: Datetime!\n  updatedAt: Datetime\n  title: String!\n  url: String!\n  profileId: UUID!\n  upVoteTotal: Int!\n  downVoteTotal: Int!\n  voteTotal: Int!\n  voteRank: Int!\n  score: Int\n  voteDelta: Int!\n  commentCollection(\n    \"\"\"Query the first `n` records in the collection\"\"\"\n    first: Int\n\n    \"\"\"Query the last `n` records in the collection\"\"\"\n    last: Int\n\n    \"\"\"Query values in the collection before the provided cursor\"\"\"\n    before: Cursor\n\n    \"\"\"Query values in the collection after the provided cursor\"\"\"\n    after: Cursor\n\n    \"\"\"Filters to apply to the results set when querying from the collection\"\"\"\n    filter: CommentFilter\n\n    \"\"\"Sort order to apply to the collection\"\"\"\n    orderBy: [CommentOrderBy!]\n  ): CommentConnection\n  profile: Profile\n  voteCollection(\n    \"\"\"Query the first `n` records in the collection\"\"\"\n    first: Int\n\n    \"\"\"Query the last `n` records in the collection\"\"\"\n    last: Int\n\n    \"\"\"Query values in the collection before the provided cursor\"\"\"\n    before: Cursor\n\n    \"\"\"Query values in the collection after the provided cursor\"\"\"\n    after: Cursor\n\n    \"\"\"Filters to apply to the results set when querying from the collection\"\"\"\n    filter: VoteFilter\n\n    \"\"\"Sort order to apply to the collection\"\"\"\n    orderBy: [VoteOrderBy!]\n  ): VoteConnection\n}\n\ntype PostConnection {\n  edges: [PostEdge!]!\n  pageInfo: PageInfo!\n\n  \"\"\"The total number of records matching the `filter` criteria\"\"\"\n  totalCount: Int!\n}\n\ntype PostDeleteResponse {\n  \"\"\"Count of the records impacted by the mutation\"\"\"\n  affectedCount: Int!\n\n  \"\"\"Array of records impacted by the mutation\"\"\"\n  records: [Post!]!\n}\n\ntype PostEdge {\n  cursor: String!\n  node: Post\n}\n\ninput PostFilter {\n  id: BigIntFilter\n  createdAt: DatetimeFilter\n  updatedAt: DatetimeFilter\n  title: StringFilter\n  url: StringFilter\n  profileId: UUIDFilter\n  upVoteTotal: IntFilter\n  downVoteTotal: IntFilter\n  voteTotal: IntFilter\n  voteRank: IntFilter\n  score: IntFilter\n  voteDelta: IntFilter\n}\n\ninput PostInsertInput {\n  createdAt: Datetime\n  updatedAt: Datetime\n  title: String\n  url: String\n  profileId: UUID\n  upVoteTotal: Int\n  downVoteTotal: Int\n  voteTotal: Int\n  voteRank: Int\n  score: Int\n  voteDelta: Int\n}\n\ntype PostInsertResponse {\n  \"\"\"Count of the records impacted by the mutation\"\"\"\n  affectedCount: Int!\n\n  \"\"\"Array of records impacted by the mutation\"\"\"\n  records: [Post!]!\n}\n\ninput PostOrderBy {\n  id: OrderByDirection\n  createdAt: OrderByDirection\n  updatedAt: OrderByDirection\n  title: OrderByDirection\n  url: OrderByDirection\n  profileId: OrderByDirection\n  upVoteTotal: OrderByDirection\n  downVoteTotal: OrderByDirection\n  voteTotal: OrderByDirection\n  voteRank: OrderByDirection\n  score: OrderByDirection\n  voteDelta: OrderByDirection\n}\n\ninput PostUpdateInput {\n  createdAt: Datetime\n  updatedAt: Datetime\n  title: String\n  url: String\n  profileId: UUID\n  upVoteTotal: Int\n  downVoteTotal: Int\n  voteTotal: Int\n  voteRank: Int\n  score: Int\n  voteDelta: Int\n}\n\ntype PostUpdateResponse {\n  \"\"\"Count of the records impacted by the mutation\"\"\"\n  affectedCount: Int!\n\n  \"\"\"Array of records impacted by the mutation\"\"\"\n  records: [Post!]!\n}\n\ntype Profile {\n  id: UUID!\n  updatedat: Datetime\n  username: String\n  avatarUrl: String\n  website: String\n  bio: String\n  commentCollection(\n    \"\"\"Query the first `n` records in the collection\"\"\"\n    first: Int\n\n    \"\"\"Query the last `n` records in the collection\"\"\"\n    last: Int\n\n    \"\"\"Query values in the collection before the provided cursor\"\"\"\n    before: Cursor\n\n    \"\"\"Query values in the collection after the provided cursor\"\"\"\n    after: Cursor\n\n    \"\"\"Filters to apply to the results set when querying from the collection\"\"\"\n    filter: CommentFilter\n\n    \"\"\"Sort order to apply to the collection\"\"\"\n    orderBy: [CommentOrderBy!]\n  ): CommentConnection\n  postCollection(\n    \"\"\"Query the first `n` records in the collection\"\"\"\n    first: Int\n\n    \"\"\"Query the last `n` records in the collection\"\"\"\n    last: Int\n\n    \"\"\"Query values in the collection before the provided cursor\"\"\"\n    before: Cursor\n\n    \"\"\"Query values in the collection after the provided cursor\"\"\"\n    after: Cursor\n\n    \"\"\"Filters to apply to the results set when querying from the collection\"\"\"\n    filter: PostFilter\n\n    \"\"\"Sort order to apply to the collection\"\"\"\n    orderBy: [PostOrderBy!]\n  ): PostConnection\n  voteCollection(\n    \"\"\"Query the first `n` records in the collection\"\"\"\n    first: Int\n\n    \"\"\"Query the last `n` records in the collection\"\"\"\n    last: Int\n\n    \"\"\"Query values in the collection before the provided cursor\"\"\"\n    before: Cursor\n\n    \"\"\"Query values in the collection after the provided cursor\"\"\"\n    after: Cursor\n\n    \"\"\"Filters to apply to the results set when querying from the collection\"\"\"\n    filter: VoteFilter\n\n    \"\"\"Sort order to apply to the collection\"\"\"\n    orderBy: [VoteOrderBy!]\n  ): VoteConnection\n}\n\ntype ProfileConnection {\n  edges: [ProfileEdge!]!\n  pageInfo: PageInfo!\n\n  \"\"\"The total number of records matching the `filter` criteria\"\"\"\n  totalCount: Int!\n}\n\ntype ProfileDeleteResponse {\n  \"\"\"Count of the records impacted by the mutation\"\"\"\n  affectedCount: Int!\n\n  \"\"\"Array of records impacted by the mutation\"\"\"\n  records: [Profile!]!\n}\n\ntype ProfileEdge {\n  cursor: String!\n  node: Profile\n}\n\ninput ProfileFilter {\n  id: UUIDFilter\n  updatedat: DatetimeFilter\n  username: StringFilter\n  avatarUrl: StringFilter\n  website: StringFilter\n  bio: StringFilter\n}\n\ninput ProfileInsertInput {\n  id: UUID\n  updatedat: Datetime\n  username: String\n  avatarUrl: String\n  website: String\n  bio: String\n}\n\ntype ProfileInsertResponse {\n  \"\"\"Count of the records impacted by the mutation\"\"\"\n  affectedCount: Int!\n\n  \"\"\"Array of records impacted by the mutation\"\"\"\n  records: [Profile!]!\n}\n\ninput ProfileOrderBy {\n  id: OrderByDirection\n  updatedat: OrderByDirection\n  username: OrderByDirection\n  avatarUrl: OrderByDirection\n  website: OrderByDirection\n  bio: OrderByDirection\n}\n\ninput ProfileUpdateInput {\n  id: UUID\n  updatedat: Datetime\n  username: String\n  avatarUrl: String\n  website: String\n  bio: String\n}\n\ntype ProfileUpdateResponse {\n  \"\"\"Count of the records impacted by the mutation\"\"\"\n  affectedCount: Int!\n\n  \"\"\"Array of records impacted by the mutation\"\"\"\n  records: [Profile!]!\n}\n\n\"\"\"The root type for querying data\"\"\"\ntype Query {\n  \"\"\"A pagable collection of type `Comment`\"\"\"\n  commentCollection(\n    \"\"\"Query the first `n` records in the collection\"\"\"\n    first: Int\n\n    \"\"\"Query the last `n` records in the collection\"\"\"\n    last: Int\n\n    \"\"\"Query values in the collection before the provided cursor\"\"\"\n    before: Cursor\n\n    \"\"\"Query values in the collection after the provided cursor\"\"\"\n    after: Cursor\n\n    \"\"\"Filters to apply to the results set when querying from the collection\"\"\"\n    filter: CommentFilter\n\n    \"\"\"Sort order to apply to the collection\"\"\"\n    orderBy: [CommentOrderBy!]\n  ): CommentConnection\n\n  \"\"\"A pagable collection of type `Post`\"\"\"\n  postCollection(\n    \"\"\"Query the first `n` records in the collection\"\"\"\n    first: Int\n\n    \"\"\"Query the last `n` records in the collection\"\"\"\n    last: Int\n\n    \"\"\"Query values in the collection before the provided cursor\"\"\"\n    before: Cursor\n\n    \"\"\"Query values in the collection after the provided cursor\"\"\"\n    after: Cursor\n\n    \"\"\"Filters to apply to the results set when querying from the collection\"\"\"\n    filter: PostFilter\n\n    \"\"\"Sort order to apply to the collection\"\"\"\n    orderBy: [PostOrderBy!]\n  ): PostConnection\n\n  \"\"\"A pagable collection of type `Profile`\"\"\"\n  profileCollection(\n    \"\"\"Query the first `n` records in the collection\"\"\"\n    first: Int\n\n    \"\"\"Query the last `n` records in the collection\"\"\"\n    last: Int\n\n    \"\"\"Query values in the collection before the provided cursor\"\"\"\n    before: Cursor\n\n    \"\"\"Query values in the collection after the provided cursor\"\"\"\n    after: Cursor\n\n    \"\"\"Filters to apply to the results set when querying from the collection\"\"\"\n    filter: ProfileFilter\n\n    \"\"\"Sort order to apply to the collection\"\"\"\n    orderBy: [ProfileOrderBy!]\n  ): ProfileConnection\n\n  \"\"\"A pagable collection of type `Vote`\"\"\"\n  voteCollection(\n    \"\"\"Query the first `n` records in the collection\"\"\"\n    first: Int\n\n    \"\"\"Query the last `n` records in the collection\"\"\"\n    last: Int\n\n    \"\"\"Query values in the collection before the provided cursor\"\"\"\n    before: Cursor\n\n    \"\"\"Query values in the collection after the provided cursor\"\"\"\n    after: Cursor\n\n    \"\"\"Filters to apply to the results set when querying from the collection\"\"\"\n    filter: VoteFilter\n\n    \"\"\"Sort order to apply to the collection\"\"\"\n    orderBy: [VoteOrderBy!]\n  ): VoteConnection\n}\n\n\"\"\"\nBoolean expression comparing fields on type \"String\"\n\"\"\"\ninput StringFilter {\n  eq: String\n  gt: String\n  gte: String\n  lt: String\n  lte: String\n  neq: String\n}\n\nscalar Time\n\n\"\"\"\nBoolean expression comparing fields on type \"Time\"\n\"\"\"\ninput TimeFilter {\n  eq: Time\n  gt: Time\n  gte: Time\n  lt: Time\n  lte: Time\n  neq: Time\n}\n\nscalar UUID\n\n\"\"\"\nBoolean expression comparing fields on type \"UUID\"\n\"\"\"\ninput UUIDFilter {\n  eq: UUID\n  neq: UUID\n}\n\ntype Vote {\n  id: BigInt!\n  createdAt: Datetime\n  updatedAt: Datetime\n  profileId: UUID!\n  postId: BigInt!\n  direction: String!\n  post: Post\n  profile: Profile\n}\n\ntype VoteConnection {\n  edges: [VoteEdge!]!\n  pageInfo: PageInfo!\n\n  \"\"\"The total number of records matching the `filter` criteria\"\"\"\n  totalCount: Int!\n}\n\ntype VoteDeleteResponse {\n  \"\"\"Count of the records impacted by the mutation\"\"\"\n  affectedCount: Int!\n\n  \"\"\"Array of records impacted by the mutation\"\"\"\n  records: [Vote!]!\n}\n\ntype VoteEdge {\n  cursor: String!\n  node: Vote\n}\n\ninput VoteFilter {\n  id: BigIntFilter\n  createdAt: DatetimeFilter\n  updatedAt: DatetimeFilter\n  profileId: UUIDFilter\n  postId: BigIntFilter\n  direction: StringFilter\n}\n\ninput VoteInsertInput {\n  createdAt: Datetime\n  updatedAt: Datetime\n  profileId: UUID\n  postId: BigInt\n  direction: String\n}\n\ntype VoteInsertResponse {\n  \"\"\"Count of the records impacted by the mutation\"\"\"\n  affectedCount: Int!\n\n  \"\"\"Array of records impacted by the mutation\"\"\"\n  records: [Vote!]!\n}\n\ninput VoteOrderBy {\n  id: OrderByDirection\n  createdAt: OrderByDirection\n  updatedAt: OrderByDirection\n  profileId: OrderByDirection\n  postId: OrderByDirection\n  direction: OrderByDirection\n}\n\ninput VoteUpdateInput {\n  createdAt: Datetime\n  updatedAt: Datetime\n  profileId: UUID\n  postId: BigInt\n  direction: String\n}\n\ntype VoteUpdateResponse {\n  \"\"\"Count of the records impacted by the mutation\"\"\"\n  affectedCount: Int!\n\n  \"\"\"Array of records impacted by the mutation\"\"\"\n  records: [Vote!]!\n}"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"pg-graphql-example\",\n  \"workspaces\": [\n    \"app\"\n  ],\n  \"private\": true,\n  \"devDependencies\": {\n    \"@graphql-codegen/cli\": \"2.13.1\",\n    \"@graphql-codegen/gql-tag-operations-preset\": \"1.6.0\",\n    \"gradient-string\": \"2.0.2\",\n    \"graphql\": \"16.6.0\",\n    \"husky\": \"7.0.4\",\n    \"lint-staged\": \"12.5.0\",\n    \"prettier\": \"2.8.8\",\n    \"progress\": \"2.0.3\"\n  },\n  \"lint-staged\": {\n    \"*.{js,css,md,ts,tsx}\": \"prettier --write\"\n  },\n  \"scripts\": {\n    \"prepare\": \"husky install\",\n    \"codegen\": \"graphql-codegen\",\n    \"codegen:fetch\": \"node --no-warnings scripts/fetchGraphQLSchema \",\n    \"codegen:watch\": \"yarn run codegen -- --watch\",\n    \"prebuild\": \"yarn run codegen\",\n    \"build\": \"yarn workspaces run build\"\n  }\n}\n"
  },
  {
    "path": "renovate.json",
    "content": "{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"extends\": [\"github>the-guild-org/shared-config:renovate\"]\n}\n"
  },
  {
    "path": "scripts/fetchGraphQLSchema.js",
    "content": "require(\"dotenv\").config();\n\nconst fs = require(\"fs\");\nconst gradient = require(\"gradient-string\");\nconst path = require(\"path\");\nconst ProgressBar = require(\"progress\");\nconst { fetch } = require(\"cross-undici-fetch\");\n\nconst {\n  buildClientSchema,\n  getIntrospectionQuery,\n  printSchema,\n} = require(\"graphql\");\n\nconst supagradient = gradient([\"#00CB8A\", \"#78E0B8\"]);\n\nfunction fetchGraphQLSchema(url, options) {\n  options = options || {}; // eslint-disable-line no-param-reassign\n\n  const bar = new ProgressBar(\"🔦  Introspecting schema [:bar]\", 24);\n\n  const id = setInterval(function () {\n    bar.tick();\n    if (bar.complete) {\n      clearInterval(id);\n    }\n  }, 250);\n\n  return fetch(url, {\n    method: \"POST\",\n    headers: {\n      Accept: \"application/json\",\n      \"Content-Type\": \"application/json\",\n      apiKey: process.env.SUPABASE_ANON_KEY,\n    },\n    body: JSON.stringify({\n      query: getIntrospectionQuery(),\n    }),\n  })\n    .then((res) => res.json())\n    .then((schemaJSON) => {\n      if (options.readable) {\n        return printSchema(buildClientSchema(schemaJSON.data));\n      }\n\n      bar.complete();\n      return JSON.stringify(schemaJSON, null, 2);\n    });\n}\n\nconst filePath = path.join(__dirname, \"../graphql/schema/\", \"schema.graphql\");\n\nconsole.log();\n\nconsole.log(\n  supagradient(\n    `🗞   Fetching GraphQL Schema from ${process.env.SUPABASE_URL} ...`\n  )\n);\n\nfetchGraphQLSchema(`${process.env.SUPABASE_URL}/graphql/v1`, {\n  readable: true,\n}).then((schema) => {\n  fs.writeFileSync(filePath, schema, \"utf-8\");\n  console.log(supagradient(`✨  Saved to ${filePath}`));\n  console.log(\n    '💡  Be sure to run \"yarn run codegen\" to generate latest types.'\n  );\n});\n"
  }
]