diff --git a/README.md b/README.md index efb42be3d71..4dba9303a83 100644 --- a/README.md +++ b/README.md @@ -31,10 +31,10 @@ Keystone 6 is published to npm under the `@keystone-6/*` namespace. You can find our extended documentation on our [website](https://keystonejs.com/docs), but some quick links that might be helpful: - Read [Why Keystone](https://keystonejs.com/why-keystone) to learn about our vision and what's in the box. -- [Getting Started](https://keystonejs.com/docs/walkthroughs/getting-started-with-create-keystone-app) walks you through first steps with the `create-keystone-app` CLI. +- [Getting Started](https://keystonejs.com/docs/getting-started) walks you through first steps with the `create-keystone-app` CLI. - Our [Examples](./examples) contain a growing collection of projects you can run locally to learn more about a [Keystone feature](https://keystonejs.com/why-keystone#features). - An [API Reference](https://keystonejs.com/docs/apis) contains the details on Keystone's foundational building blocks. -- Some [Guides](https://keystonejs.com/docs/guides) offer practical walkthroughs on how to build with those blocks. +- Some [Guides](https://keystonejs.com/docs/guides/overview) offer practical walkthroughs on how to build with those blocks. > 💡 While our `API Reference` is generally complete, we are are still working hard on increasing the fidelity of our `guides` and `examples`. If you have an example you'd like see, please [open a GitHub discussion](https://github.com/keystonejs/keystone/discussions/new)! diff --git a/docs/components/Footer.tsx b/docs/components/Footer.tsx index ba1b72bc292..7ffa906d9df 100644 --- a/docs/components/Footer.tsx +++ b/docs/components/Footer.tsx @@ -90,7 +90,7 @@ export function Footer() {
  • - + Getting started
  • diff --git a/docs/components/MobileMenu.tsx b/docs/components/MobileMenu.tsx index 7dc940ada9e..5215030fbb3 100644 --- a/docs/components/MobileMenu.tsx +++ b/docs/components/MobileMenu.tsx @@ -9,7 +9,7 @@ import FocusLock from 'react-focus-lock'; import { useHeaderContext } from './Header'; import { Highlight } from './primitives/Highlight'; -import { DocsNavigation, NavItem, PrimaryNavItem } from './docs/Navigation'; +import { DocsNavigation, NavItem } from './docs/Navigation'; import { Keystone } from './icons/Keystone'; import { Close } from './icons/Close'; @@ -44,7 +44,7 @@ export function MobileMenu({ handleClose }: MobileMenuProps) { borderBottom: '1px solid var(--border)', }} > - Why Keystone + Why Keystone For Developers For Organisations @@ -56,11 +56,11 @@ export function MobileMenu({ handleClose }: MobileMenuProps) { borderBottom: '1px solid var(--border)', }} > - Updates - Roadmap - + Updates + Roadmap + GitHub Releases - +
    diff --git a/docs/components/Page.tsx b/docs/components/Page.tsx index b72b3ff064e..0c43112b98a 100644 --- a/docs/components/Page.tsx +++ b/docs/components/Page.tsx @@ -4,55 +4,18 @@ import { useRef, Fragment, ReactNode } from 'react'; import { useRouter } from 'next/router'; import { jsx } from '@emotion/react'; import Head from 'next/head'; -import Link from 'next/link'; import { useMediaQuery } from '../lib/media'; import type { Heading } from '../lib/getHeadings'; -import { Announce } from '../components/Announce'; import { TableOfContents } from './docs/TableOfContents'; import { Wrapper } from './primitives/Wrapper'; import { EditButton } from './primitives/EditButton'; -// import { Emoji } from './primitives/Emoji'; import { Breadcrumbs } from './Breadcrumbs'; import { Sidebar } from './docs/Sidebar'; import { Stack } from './primitives/Stack'; import { Header } from './Header'; import { Footer } from './Footer'; -function Announcement() { - // special announcement - // return ( - // - // {' '} - // - // Join us - // {' '} - // for our first Community Q&A next{' '} - // Tuesday Sep 21st @ 3–4pm AEST –{' '} - // - // Register now - // - // ! - // - // ); - // standard announcement - return ( - - - Keystone 6 is now in General Availability! - - - ); -} - function OpenGraph({ title, description, @@ -121,7 +84,6 @@ export function DocsPage({ paddingBottom: 'var(--space-xxlarge)', }} > -
    -
    {children} diff --git a/docs/components/docs/ExamplesList.tsx b/docs/components/docs/ExamplesList.tsx index 902cbf2c79b..6c020bbada9 100644 --- a/docs/components/docs/ExamplesList.tsx +++ b/docs/components/docs/ExamplesList.tsx @@ -101,8 +101,7 @@ export function Examples() { target="_blank" rel="noopener noreferrer" > - Illustrates how to use the json field type. Builds on the Task - Manager starter project. + Illustrates how to use the json field type. Adds a custom Admin UI view to a json field which provides a - customised editing experience for users. Builds on the Task Manager starter project. + customised editing experience for users. Adds a custom field type based on the integer field type which lets - users rate items on a 5-star scale. Builds on the Blog starter project. + users rate items on a 5-star scale. - Adds a custom page in the Admin UI. Builds on the Task Manager starter project. + Adds a custom page in the Admin UI. - Adds a custom logo component in the Admin UI. Builds on the Task Manager starter project. + Adds a custom logo component in the Admin UI. - Adds a custom Navigation component to the Admin UI. Builds on the Task Manager starter - project. + Adds a custom Navigation component to the Admin UI. + + + Example to demonstrate customisation of Keystone's document field and document renderer.
    ); diff --git a/docs/components/docs/Navigation.tsx b/docs/components/docs/Navigation.tsx index 4841aa96eab..af72eb3e3ec 100644 --- a/docs/components/docs/Navigation.tsx +++ b/docs/components/docs/Navigation.tsx @@ -1,6 +1,13 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { AnchorHTMLAttributes, HTMLAttributes, ReactNode } from 'react'; +import { + AnchorHTMLAttributes, + ReactNode, + useState, + createContext, + useContext, + useMemo, +} from 'react'; import { useRouter } from 'next/router'; import { jsx } from '@emotion/react'; import Link from 'next/link'; @@ -8,34 +15,103 @@ import Link from 'next/link'; import { useMediaQuery } from '../../lib/media'; import { useHeaderContext } from '../Header'; import { Badge } from '../primitives/Badge'; -import { Type } from '../primitives/Type'; +import { ArrowR } from '../icons/ArrowR'; import { Emoji } from '../primitives/Emoji'; -type SectionProps = { label?: string; children: ReactNode }; -export function Section({ label, children }: SectionProps) { +type NavContext = { + isSectionCollapsed: (title: string) => boolean; + collapseSection: (title: string) => void; + expandSection: (title: string) => void; +}; + +const NavContext = createContext(undefined); + +/* Save section collapse/expand states */ +export const NavContextProvider = ({ children }: { children: ReactNode }) => { + const [collapsedSections, setCollapsedSections] = useState([]); + + const contextValue = useMemo(() => { + const collapseSection = (title: string) => { + const isSectionAlreadyCollapsed = collapsedSections.includes(title); + if (!isSectionAlreadyCollapsed) { + setCollapsedSections([...collapsedSections, title]); + } + }; + const expandSection = (title: string) => { + const isSectionAlreadyExpanded = !collapsedSections.includes(title); + if (!isSectionAlreadyExpanded) { + setCollapsedSections(collapsedSections.filter(cs => cs !== title)); + } + }; + const isSectionCollapsed = (title: string) => { + return collapsedSections.some(cs => cs === title); + }; + + return { isSectionCollapsed, collapseSection, expandSection }; + }, [collapsedSections, setCollapsedSections]); + + return {children}; +}; + +const useNavContext = () => { + const navContext = useContext(NavContext); + if (navContext === undefined) { + throw new Error('NavContextProvider is not wrapped in the tree'); + } + + return navContext; +}; + +type NavSectionProps = { + title: string; + children: ReactNode; +}; + +function NavSection({ title, children }: NavSectionProps) { + const { isSectionCollapsed, collapseSection, expandSection } = useNavContext(); + const isCollapsed = isSectionCollapsed(title); return ( -
    - {label && ( - +
    + /> + + +
    + {children} +
    + ); } @@ -53,9 +129,9 @@ export function NavItem({ alwaysVisible, ...props }: NavItemProps) { - const { pathname } = useRouter(); + const { asPath } = useRouter(); const mq = useMediaQuery(); - const isActive = _isActive || pathname === href; + const isActive = _isActive || asPath === href; const ctx = useHeaderContext(); const isMobileNavOpen = ctx ? ctx.mobileNavIsOpen : true; const desktopOpenState = ctx ? ctx.desktopOpenState : -1; @@ -67,12 +143,7 @@ export function NavItem({ css={mq({ display: 'block', textDecoration: 'none', - padding: [ - '0 0 var(--space-medium) 0 var(--space-medium)', - '0 0 var(--space-medium) var(--space-medium)', - null, - '0 0 var(--space-large) var(--space-medium)', - ], + paddingBottom: '1rem', color: isActive ? 'var(--link)' : `${isPlaceholder ? 'var(--text-disabled)' : 'var(--text)'}`, @@ -92,8 +163,8 @@ type PrimaryNavItemProps = { } & AnchorHTMLAttributes; export function PrimaryNavItem({ href, children }: PrimaryNavItemProps) { - const { pathname } = useRouter(); - const isActive = pathname === href; + const { asPath } = useRouter(); + const isActive = asPath === href; const ctx = useHeaderContext(); const isMobileNavOpen = ctx ? ctx.mobileNavIsOpen : true; const desktopOpenState = ctx ? ctx.desktopOpenState : -1; @@ -108,7 +179,7 @@ export function PrimaryNavItem({ href, children }: PrimaryNavItemProps) { color: isActive ? 'var(--link)' : 'var(--text-heading)', marginBottom: '1rem', alignItems: 'center', - fontWeight: 700, + fontWeight: 400, ':hover': { color: 'var(--link)', }, @@ -120,43 +191,20 @@ export function PrimaryNavItem({ href, children }: PrimaryNavItemProps) { ); } -function SubHeading(props: HTMLAttributes) { - return ( - - ); -} - export function DocsNavigation() { return ( + // + // ); } export function UpdatesNavigation() { return ( - + + + ); } diff --git a/docs/components/docs/Sidebar.tsx b/docs/components/docs/Sidebar.tsx index 01df727a57b..41e3657f488 100644 --- a/docs/components/docs/Sidebar.tsx +++ b/docs/components/docs/Sidebar.tsx @@ -26,6 +26,13 @@ export function Sidebar({ isUpdatesPage }: SidebarProps) { display: ['none', null, 'block'], padding: ['0 0 var(--space-large) var(--space-large)', null, 0], borderBottom: ['1px solid var(--muted)', null, 'none'], + position: 'sticky', + top: 16, + bottom: 16, + alignSelf: 'start', + overflow: 'auto', + height: '100vh', + paddingBottom: '2rem', })} > diff --git a/docs/components/docs/WalkthroughsList.tsx b/docs/components/docs/WalkthroughsList.tsx index 1e3d4a4f97f..377d535f0bc 100644 --- a/docs/components/docs/WalkthroughsList.tsx +++ b/docs/components/docs/WalkthroughsList.tsx @@ -18,10 +18,7 @@ export function Walkthroughs() { margin: '0 0 var(--space-xlarge) 0', })} > - + Take a tour of Keystone in minutes with our CLI starter project @@ -57,14 +54,6 @@ export function Walkthroughs() { Add a powerful document field to your app and learn how to configure it to meet your needs - - Learn how to run Keystone in the same folder as your frontend code and commit everything - to Git. You end up with a queryable GraphQL endpoint running live on Vercel. - ); diff --git a/docs/markdoc/config.ts b/docs/markdoc/config.ts index c1c995b7cb9..556b61a678d 100644 --- a/docs/markdoc/config.ts +++ b/docs/markdoc/config.ts @@ -1,6 +1,8 @@ import { Config, nodes, Tag, ValidationError, Node } from '@markdoc/markdoc'; import slugify from '@sindresorhus/slugify'; +export type Pages = Map }>; + export const markdocConfig: Config = { tags: { emoji: { @@ -64,17 +66,18 @@ export const markdocConfig: Config = { href: { type: String }, target: { type: String, matches: ['_blank'] }, }, + validate: validateLink, }, }, nodes: { document: { ...nodes.document, - validate(node) { + validate(document) { const errors: ValidationError[] = []; // we want good stable ids so we require documentation authors write ids // when they could be ambiguous rather than just adding an index const seenHeadings = new Map(); - for (const child of node.children) { + for (const child of document.children) { if (child.type === 'heading') { const id = getIdForHeading(child); // we report an error for this in the heading validation @@ -99,6 +102,19 @@ export const markdocConfig: Config = { errors.push(ambiguousHeadingError(child)); } } + for (const node of document.walk()) { + if (node.type === 'link' && node.attributes.href.startsWith('#')) { + const id = node.attributes.href.slice(1); + if (!seenHeadings.has(id)) { + errors.push({ + id: 'missing-heading-id', + level: 'error', + message: `The link "${node.attributes.href}" doesn't point to an id in this file`, + location: node.location, + }); + } + } + } return errors; }, }, @@ -144,6 +160,10 @@ export const markdocConfig: Config = { return new Tag(this.render, { ...attributes, id: getIdForHeading(node) }, children); }, }, + link: { + ...nodes.link, + validate: validateLink, + }, image: { ...nodes.image, attributes: { @@ -155,7 +175,45 @@ export const markdocConfig: Config = { }, }; -function getIdForHeading(node: Node): string { +function validateLink(node: Node, config: Config): ValidationError[] { + const link = node.attributes.href; + if ( + /https?:\/\//.test(link) || + // local # is validated in the document validation + link.startsWith('#') + ) { + return []; + } + const pages: Pages | undefined = (config as any).pages; + if (/\.?\.?\//.test(link)) { + if (!pages) return []; + const url = new URL( + link, + `https://example.com${node.location!.file!.replace(/^pages/, '').replace(/\.md$/, '')}` + ); + const id = url.hash ? url.hash.slice(1) : undefined; + if (!pages.has(url.pathname)) { + return [ + { + id: 'invalid-link', + level: 'error', + message: `${link} points to a page that does not exist`, + }, + ]; + } + if (id === undefined || pages.get(url.pathname)!.ids.has(id)) return []; + return [ + { + id: 'invalid-link', + level: 'error', + message: `${link} points to an id that does not exist`, + }, + ]; + } + return [{ id: 'invalid-link', level: 'error', message: 'Unknown link type' }]; +} + +export function getIdForHeading(node: Node): string { if (typeof node.attributes.id === 'string') { return node.attributes.id; } diff --git a/docs/markdoc/index.ts b/docs/markdoc/index.ts index 0a62774dd85..572d1c9ff36 100644 --- a/docs/markdoc/index.ts +++ b/docs/markdoc/index.ts @@ -7,6 +7,18 @@ import { assert } from 'emery/assertions'; import { load } from 'js-yaml'; import { markdocConfig } from './config'; +export function printValidationError(error: ValidateError) { + const location = error.error.location || error.location; + // the filepath is intentionally duplicated here so that there is one thing you can copy to refer to the error position + return `${location?.file ?? '(unknown file)'}:${ + // the +1 is because location.start.line is 0-based + // but tools generally use 1-based line numbers + location?.start.line !== undefined ? location.start.line + 1 : '(unknown line)' + }${location?.start.character !== undefined ? `:${location.start.character}` : ''}: ${ + error.error.message + }`; +} + class MarkdocValidationFailure extends Error { constructor(errors: [ValidateError, ...ValidateError[]], errorReportingFilepath: string) { super(); @@ -15,17 +27,7 @@ class MarkdocValidationFailure extends Error { // so this separator makes it easier to find the actual problem const separator = `⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯`; this.message = `Errors in ${errorReportingFilepath}:\n${separator}\n${errors - .map(error => { - const location = error.error.location || error.location; - // the filepath is intentionally duplicated here so that there is one thing you can copy to refer to the error position - return `${errorReportingFilepath}:${ - // the +1 is because location.start.line is 0-based - // but tools generally use 1-based line numbers - location?.start.line !== undefined ? location.start.line + 1 : '(unknown line)' - }${location?.start.character !== undefined ? `:${location.start.character}` : ''}: ${ - error.error.message - }`; - }) + .map(error => printValidationError(error)) .join('\n')}\n${separator}`; } } diff --git a/docs/package.json b/docs/package.json index 365d3f77fd9..0bdb3416b0c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -5,9 +5,10 @@ "license": "MIT", "scripts": { "dev": "next -p 8000", - "build": "next build && yarn sitemap", + "build": "yarn validate-links && next build && yarn sitemap", "start": "next start -p 8000", - "sitemap": "yarn next-sitemap" + "sitemap": "next-sitemap", + "validate-links": "tsx validate-links.ts" }, "dependencies": { "@babel/runtime": "^7.16.3", @@ -48,7 +49,8 @@ "react-dom": "^18.1.0", "react-focus-lock": "^2.7.1", "remark-gfm": "^1.0.0", - "remark-hint": "^1.0.10" + "remark-hint": "^1.0.10", + "tsx": "^3.9.0" }, "devDependencies": { "@types/lodash.debounce": "^4.0.6", diff --git a/docs/pages/_app.tsx b/docs/pages/_app.tsx index 8d01ccf7c13..817f2285e3e 100644 --- a/docs/pages/_app.tsx +++ b/docs/pages/_app.tsx @@ -7,6 +7,7 @@ import { cache } from '@emotion/css'; import Head from 'next/head'; import { proseStyles } from '../lib/prose-lite'; import { Theme } from '../components/Theme'; +import { NavContextProvider } from '../components/docs/Navigation'; import { SkipLinks } from '../components/SkipLinks'; export default function App({ Component, pageProps }: AppProps) { @@ -99,7 +100,9 @@ export default function App({ Component, pageProps }: AppProps) { /> - + + + ); } diff --git a/docs/pages/docs/apis/fields.md b/docs/pages/docs/apis/fields.md deleted file mode 100644 index 8db5beeca8e..00000000000 --- a/docs/pages/docs/apis/fields.md +++ /dev/null @@ -1,1038 +0,0 @@ ---- -title: "Fields API" -description: "A reference of Keystone’s field types, and the configuration options they accept." ---- - -{% hint kind="warn" %} -We recently improved this API. If you were using it prior to October 5th 2021, [read this guide](/releases/2021-10-05#upgrade-guide) for details on how to upgrade. -{% /hint %} - -The `fields` option of a [list configuration](./schema) defines the names, types, and configuration of the fields in the list. -This configuration option takes an object with field names as keys, and configured field types as values. - -This document covers the different field types which are available and the configuration options they accept. -To see how to access fields in the GraphQL API please see the [GraphQL API](./graphql) docs. - -```typescript -import { config, list } from '@keystone-6/core'; -import { - // Scalar types - checkbox, - integer, - json, - float, - password, - select, - text, - timestamp, - - // Relationship type - relationship, - - // Virtual type - virtual, - - // File types - file, - image, -} from '@keystone-6/core/fields'; - -// Complex types -import { document } from '@keystone-6/fields-document'; -import { cloudinaryImage } from '@keystone-6/cloudinary'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: text({ /* ... */ }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -## Common configuration - -All field types accept a common set of configuration options. -All options are optional. - -Options: - -- `isFilterable` (default: `true`): If `false`, the GraphQL API and admin UI will not support filtering by this field. - If `true` (default), the GraphQL API and Admin UI will support filtering by this field. - If a function is provided, it will be evaluated dynamically each time this field is used as a filter in a GraphQL operation. - If the function returns `false`, the operation will return an error indicating that filtering on this field is not allowed. -- `isOrderable` (default: `true`): If `false`, the GraphQL API and admin UI will not support ordering by this field. - If `true` (default), the GraphQL API and Admin UI will support ordering by this field. - If a function is provided, it will be evaluated dynamically each time this field is used as an ordering field in a GraphQL operation. - If the function returns `false`, the operation will return an error indicating this ordering by this field is not allowed. -- `access`: Defines the [Access Control](../guides/auth-and-access-control) rules for the field. - See the [Access Control API](./access-control) for full details on the available access control options. -- `hooks`: The `hooks` option defines [hook](../guides/hooks) functions for the field. - Hooks allow you to execute code at different stages of the mutation lifecycle. - See the [Hooks API](./hooks) for full details on the available hook options. -- `label`: The label displayed for this field in the Admin UI. Defaults to a human readable version of the field name. -- `ui`: Controls how the field is displayed in the Admin UI. - - `views`: A module path that is resolved from where `keystone start` is run, resolving to a module containing code to replace or extend the Admin UI components for this field. See the [Custom Field Views](../guides/custom-field-views) guide for details on how to use this option. - - `createView.fieldMode` (default: `'edit'`): Controls the create view page of the Admin UI. - Can be one of `['edit', 'hidden']`, or an async function with an argument `{ session, context }` that returns one of `['edit', 'hidden']`. - Defaults to the list's `ui.createView.defaultFieldMode` config if defined. - See the [Lists API](./schema#ui) for details. - - `itemView.fieldMode` (default: `'edit'`): Controls the item view page of the Admin UI. - Can be one of `['edit', 'read', 'hidden']`, or an async function with an argument `{ session, context, item }` that returns one of `['edit', 'read', 'hidden']`. - Defaults to the list's `ui.itemView.defaultFieldMode` config if defined. - See the [Lists API](./schema#ui) for details. - - `listView.fieldMode` (default: `'read'`): Controls the list view page of the Admin UI. - Can be one of `['read', 'hidden']`, or an async function with an argument `{ session, context }` that returns one of `['read', 'hidden']`. - Defaults to the list's `ui.listView.defaultFieldMode` config if defined. - See the [Lists API](./schema#ui) for details. -- `graphql`: Configures certain aspects of the GraphQL API. - - `cacheHint` (default: `undefined`): Allows you to specify the [dynamic cache control hints](https://www.apollographql.com/docs/apollo-server/performance/caching/#in-your-resolvers-dynamic) used for queries to this list. - - `omit` (default: 'undefined'): Controls whether this field appears in the autogenerated types of the GraphQL API - This option accepts either `true`, or an array of the values `read`, `create`, or `update`. - If you specify `true` then the field will be excluded from all input and output types in the GraphQL API. - If you provide an array of `read`, `create`, or `update` the field will be omitted from the corresponding input and output types in the GraphQL API. - -```typescript -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: text({ - isFilterable: ({ context, session, fieldKey, listKey }) => true, - isOrderable: ({ context, session, fieldKey, listKey }) => true, - access: { /* ... */ }, - hooks: { /* ... */ }, - label: '...', - ui: { - views: './path/to/viewsModule', - createView: { - fieldMode: ({ session, context }) => 'edit', - }, - itemView: { - fieldMode: ({ session, context, item }) => 'read', - }, - listView: { - fieldMode: ({ session, context }) => 'read', - }, - }, - graphql: { - cacheHint: { maxAge: 60, scope: CacheScope.Private }, - omit: ['read', 'create', 'update'], - } - }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -## Scalar types - -### checkbox - -A `checkbox` field represents a boolean (`true`/`false`) value. - -Options: - -- `defaultValue` (default: `false`): This value will be used for the field when creating items if no explicit value is set. -- `db.map`: Adds a [Prisma `@map`](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map) attribute to this field which changes the column name in the database -- `graphql.read.isNonNull` (default: `false`): If you have no read access control and you don't intend to add any in the future, - you can set this to true and the output field will be non-nullable. This is only allowed when you have no read access control because otherwise, - when access is denied, `null` will be returned which will cause an error since the field is non-nullable and the error - will propagate up until a nullable field is found which means the entire item will be unreadable and when doing an `items` query, all the items will be unreadable. -- `graphql.create.isNonNull` (default: `false`): If you have no create access control and you want to explicitly show that this is field is non-nullable in the create input - you can set this to true and the create field will be non-nullable and have a default value at the GraphQL level. - This is only allowed when you have no create access control because otherwise, the item will always fail access control - if a user doesn't have access to create the particular field regardless of whether or not they specify the field in the create. - -```typescript -import { config, list } from '@keystone-6/core'; -import { checkbox } from '@keystone-6/core/fields'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: checkbox({ - defaultValue: true, - db: { map: 'my_checkbox' }, - graphql: { - read: { - isNonNull: true - }, - create: { - isNonNull: true - }, - } - }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -### integer - -An `integer` field represents a 32 bit signed integer value. - -Options: - -- `defaultValue` (default: `undefined`): Can be either an integer value or `{ kind: 'autoincrement' }`. - This value will be used for the field when creating items if no explicit value is set. - `{ kind: 'autoincrement' }` is only supported on PostgreSQL. -- `db.isNullable` (default: `validation.isRequired ? false : true`): If `false` then this field will be made non-nullable in the database and it will never be possible to set as `null`. -- `db.map`: Adds a [Prisma `@map`](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map) attribute to this field which changes the column name in the database -- `validation.isRequired` (default: `false`): If `true` then this field can never be set to `null`. - It validate this when creating and updating an item through the GraphQL API or the Admin UI. - It will also default `db.isNullable` to false. -- `validation.min` (default: `-2147483648`): This describes the minimum number allowed. If you attempt to submit a number under this, you will get a validation error. -- `validation.max` (default: `2147483647`): This describes the maximum number allowed. If you attempt to submit a number over this, you will get a validation error. - - If you want to specify a range within which the numbers must fall, specify both a minimum and a maximum value. -- `isIndexed` (default: `false`) - - If `true` then this field will be indexed by the database. - - If `'unique'` then all values of this field must be unique. -- `graphql.read.isNonNull` (default: `false`): If you have no read access control and you don't intend to add any in the future, - you can set this to true and the output field will be non-nullable. This is only allowed when you have no read access control because otherwise, - when access is denied, `null` will be returned which will cause an error since the field is non-nullable and the error - will propagate up until a nullable field is found which means the entire item will be unreadable and when doing an `items` query, all the items will be unreadable. -- `graphql.create.isNonNull` (default: `false`): If you have no create access control and you want to explicitly show that this is field is non-nullable in the create input - you can set this to true and the create field will be non-nullable and have a default value at the GraphQL level. - This is only allowed when you have no create access control because otherwise, the item will always fail access control - if a user doesn't have access to create the particular field regardless of whether or not they specify the field in the create. - -```typescript -import { config, list } from '@keystone-6/core'; -import { integer } from '@keystone-6/core/fields'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: integer({ - defaultValue: 0, - db: { map: 'my_integer' }, - validation: { - isRequired: true, - }, - isIndexed: 'unique', - }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -### bigInt - -A `bigInt` field represents a 64 bit signed integer value. -When interacting with the field with GraphQL, values will be strings. -When interacting with the field in hooks, values will be [Javascript `BigInt`s](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#bigint_type). -Javascript `BigInt`s are used since [integers in Javascript are unsafe beyond 2{% sup %}53{% /sup %}](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER). - -Options: - -- `defaultValue` (default: `undefined`): Can be either a bigint value or `{ kind: 'autoincrement' }`. - This value will be used for the field when creating items if no explicit value is set. - `{ kind: 'autoincrement' }` is only supported on PostgreSQL. -- `db.isNullable` (default: `validation.isRequired ? false : true`): If `false` then this field will be made non-nullable in the database and it will never be possible to set as `null`. -- `db.map`: Adds a [Prisma `@map`](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map) attribute to this field which changes the column name in the database -- `validation.isRequired` (default: `false`): If `true` then this field can never be set to `null`. - It validate this when creating and updating an item through the GraphQL API or the Admin UI. - It will also default `db.isNullable` to false. -- `validation.min`(default: `(-2n) ** 63n`): This describes the minimum number allowed. If you attempt to submit a number under this, you will get a validation error. -- `validation.max`(default: `2n ** 63n - 1n`): This describes the maximum number allowed. If you attempt to submit a number over this, you will get a validation error. - - If you want to specify a range within which the numbers must fall, specify both a minimum and a maximum value. -- `isIndexed` (default: `false`) - - If `true` then this field will be indexed by the database. - - If `'unique'` then all values of this field must be unique. -- `graphql.read.isNonNull` (default: `false`): If you have no read access control and you don't intend to add any in the future, - you can set this to true and the output field will be non-nullable. This is only allowed when you have no read access control because otherwise, - when access is denied, `null` will be returned which will cause an error since the field is non-nullable and the error - will propagate up until a nullable field is found which means the entire item will be unreadable and when doing an `items` query, all the items will be unreadable. -- `graphql.create.isNonNull` (default: `false`): If you have no create access control and you want to explicitly show that this is field is non-nullable in the create input - you can set this to true and the create field will be non-nullable and have a default value at the GraphQL level. - This is only allowed when you have no create access control because otherwise, the item will always fail access control - if a user doesn't have access to create the particular field regardless of whether or not they specify the field in the create. - -```typescript -import { config, list } from '@keystone-6/core'; -import { bigInt } from '@keystone-6/core/fields'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: bigInt({ - defaultValue: 0n, - db: { map: 'my_bigint' }, - validation: { - isRequired: true, - }, - isIndexed: 'unique', - }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -### json - -A `json` field represents a JSON blob. -Currently the `json` field is non-orderable and non-filterable. - -- `defaultValue` (default: `null`): Can be set to any JSON value. - This value will be used for the field when creating items if no explicit value is set. -- `db.map`: Adds a [Prisma `@map`](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map) attribute to this field which changes the column name in the database - -```typescript -import { config, list } from '@keystone-6/core'; -import { json } from '@keystone-6/core/fields'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: json({ - defaultValue: { something: true }, - db: { map: 'my_json' }, - }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -### float - -A `float` field represents a floating point value. - -Options: - -- `defaultValue` (default: `undefined`): Can be a finite float value. - This value will be used for the field when creating items if no explicit value is set. -- `db.map`: Adds a [Prisma `@map`](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map) attribute to this field which changes the column name in the database -- `db.isNullable` (default: `validation.isRequired ? false : true`): If `false` then this field will be made non-nullable in the database and it will never be possible to set as `null`. -- `validation.isRequired` (default: `false`): If `true` then this field can never be set to `null`. - It validate this when creating and updating an item through the GraphQL API or the Admin UI. - It will also default `db.isNullable` to false. -- `validation.min` (default: `undefined`): This describes the minimum number allowed. If you attempt to submit a number under this, you will get a validation error. -- `validation.max` (default: `undefined`): This describes the maximum number allowed. If you attempt to submit a number over this, you will get a validation error. -- `isIndexed` (default: `false`) - - If `true` then this field will be indexed by the database. - - If `'unique'` then all values of this field must be unique. -- `graphql.read.isNonNull` (default: `false`): If you have no read access control and you don't intend to add any in the future, - you can set this to true and the output field will be non-nullable. This is only allowed when you have no read access control because otherwise, - when access is denied, `null` will be returned which will cause an error since the field is non-nullable and the error - will propagate up until a nullable field is found which means the entire item will be unreadable and when doing an `items` query, all the items will be unreadable. -- `graphql.create.isNonNull` (default: `false`): If you have no create access control and you want to explicitly show that this is field is non-nullable in the create input - you can set this to true and the create field will be non-nullable and have a default value at the GraphQL level. - This is only allowed when you have no create access control because otherwise, the item will always fail access control - if a user doesn't have access to create the particular field regardless of whether or not they specify the field in the create. - -```typescript -import { config, list } from '@keystone-6/core'; -import { float } from '@keystone-6/core/fields'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: float({ - defaultValue: 3.14159, - db: { map: 'my_float' }, - validation: { - isRequired: true, - }, - isIndexed: 'unique', - }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -### decimal - -A `decimal` field represents a decimal value. - -Options: - -- `defaultValue` (default: `undefined`): Can be a decimal value written as a string - This value will be used for the field when creating items if no explicit value is set. -- `precision` (default: `18`): Maximum number of digits that are present in the number. -- `scale` (default: `4`): Maximum number of decimal places. -- `db.map`: Adds a [Prisma `@map`](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map) attribute to this field which changes the column name in the database -- `db.isNullable` (default: `validation.isRequired ? false : true`): If `false` then this field will be made non-nullable in the database and it will never be possible to set as `null`. -- `validation.isRequired` (default: `false`): If `true` then this field can never be set to `null`. - It validate this when creating and updating an item through the GraphQL API or the Admin UI. - It will also default `db.isNullable` to false. -- `validation.min` (default: `undefined`): This describes the minimum number allowed. If you attempt to submit a number under this, you will get a validation error. -- `validation.max` (default: `undefined`): This describes the maximum number allowed. If you attempt to submit a number over this, you will get a validation error. - - If you want to specify a range within which the numbers must fall, specify both a minimum and a maximum value. -- `isIndexed` (default: `false`) - - If `true` then this field will be indexed by the database. - - If `'unique'` then all values of this field must be unique. -- `graphql.read.isNonNull` (default: `false`): If you have no read access control and you don't intend to add any in the future, - you can set this to true and the output field will be non-nullable. This is only allowed when you have no read access control because otherwise, - when access is denied, `null` will be returned which will cause an error since the field is non-nullable and the error - will propagate up until a nullable field is found which means the entire item will be unreadable and when doing an `items` query, all the items will be unreadable. -- `graphql.create.isNonNull` (default: `false`): If you have no create access control and you want to explicitly show that this is field is non-nullable in the create input - you can set this to true and the create field will be non-nullable and have a default value at the GraphQL level. - This is only allowed when you have no create access control because otherwise, the item will always fail access control - if a user doesn't have access to create the particular field regardless of whether or not they specify the field in the create. - -```typescript -import { config, list } from '@keystone-6/core'; -import { decimal } from '@keystone-6/core/fields'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: decimal({ - defaultValue: '3.142', - precision: 12, - scale: 3, - db: { map: 'my_decimal' }, - validation: { - isRequired: true, - max: '10000', - min: '2', - }, - isIndexed: 'unique', - }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -### password - -A `password` field represents an encrypted password value. - -Options: - -- `db.map`: Adds a [Prisma `@map`](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map) attribute to this field which changes the column name in the database -- `db.isNullable` (default: `validation.isRequired ? false : true`): If `false` then this field will be made non-nullable in the database and it will never be possible to set as `null`. -- `validation.isRequired` (default: `false`): If `true` then this field can never be set to `null`. - It validate this when creating and updating an item through the GraphQL API or the Admin UI. - It will also default `db.isNullable` to false. -- `validation.length.min` (default: `8`): This describes the minimum length allowed. If you attempt to submit a string shorter than this, you will get a validation error. -- `validation.length.max` (default: `undefined`): This describes the maximum length allowed. If you attempt to submit a string longer than this, you will get a validation error. -- `validation.match` (default: `undefined`): This describes a pattern that values for this field must match - - `validation.match.regex`: The regular expression - - `validation.match.explanation` (default: `${fieldLabel} must match ${validation.match.regex}`): A message shown in the Admin when a value doesn't match the regex and returned as a validation error from the GraphQL API -- `validation.rejectCommon` (default: `false`): Rejects passwords from a list of commonly used passwords. -- `bcrypt` (default: `require('bcryptjs')`): A module which implements the same interface as the [`bcryptjs`](https://www.npmjs.com/package/bcryptjs) package, such as the native [`bcrypt`](https://www.npmjs.com/package/bcrypt) package. - This module will be used for all encryption routines in the `password` field. - -```typescript -import { config, list } from '@keystone-6/core'; -import { password } from '@keystone-6/core/fields'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: password({ - db: { map: 'password_field' }, - validation: { - length: { min: 10, max: 1000 }, - isRequired: true, - rejectCommon: true, - }, - bcrypt: require('bcrypt'), - }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -### select - -A `select` field represents the selection of one of fixed set of values. -Values can be either strings, integers, or enum values, as determined by the `type` option. -This will determine their GraphQL data type, as well as their database storage type except for `enum` on SQLite -where the GraphQL type will be an enum but it will be represented as a string in the database. - -Options: - -- `type` (default: `'string'`): Sets the type of the values of this field. - Must be one of `['string', 'enum', 'integer']`. -- `options`: An array of `{ label, value }`. - `label` is a string to be displayed in the Admin UI. - `value` is either a `string` (for `{ type: 'string' }` or `{ type: 'enum' }`), or a `number` (for `{ type: 'integer' }`). - The `value` will be used in the GraphQL API and stored in the database. -- `defaultValue` (default: `undefined`): This value will be used for the field when creating items if no explicit value is set. -- `db.map`: Adds a [Prisma `@map`](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map) attribute to this field which changes the column name in the database -- `db.isNullable` (default: `validation.isRequired ? false : true`): If `false` then this field will be made non-nullable in the database and it will never be possible to set as `null`. -- `validation.isRequired` (default: `false`): If `true` then this field can never be set to `null`. - It validate this when creating and updating an item through the GraphQL API or the Admin UI. - It will also default `db.isNullable` to false. -- `isIndexed` (default: `false`) - - If `true` then this field will be indexed by the database. - - If `'unique'` then all values of this field must be unique. -- `ui.displayMode` (default: `'select'`): Configures the display mode of the field in the Admin UI. - Can be one of `['select', 'segmented-control', 'radio']`. -- `graphql.read.isNonNull` (default: `false`): If you have no read access control and you don't intend to add any in the future, - you can set this to true and the output field will be non-nullable. This is only allowed when you have no read access control because otherwise, - when access is denied, `null` will be returned which will cause an error since the field is non-nullable and the error - will propagate up until a nullable field is found which means the entire item will be unreadable and when doing an `items` query, all the items will be unreadable. -- `graphql.create.isNonNull` (default: `false`): If you have no create access control and you want to explicitly show that this is field is non-nullable in the create input - you can set this to true and the create field will be non-nullable and have a default value at the GraphQL level. - This is only allowed when you have no create access control because otherwise, the item will always fail access control - if a user doesn't have access to create the particular field regardless of whether or not they specify the field in the create. - -```typescript -import { config, list } from '@keystone-6/core'; -import { select } from '@keystone-6/core/fields'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: select({ - type: 'enum', - options: [ - { label: '...', value: '...' }, - /* ... */ - ], - defaultValue: '...', - db: { map: 'my_select' }, - validation: { isRequired: true, }, - isIndexed: 'unique', - ui: { displayMode: 'select' }, - }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -### multiselect - -A `multiselect` field represents the selection of a set of values from the defined `options`. -Values can be either strings, integers, or enum values, as determined by the `type` option. -This will determine their GraphQL data type. -Unlike the `select` field, the `type` will not change the database type, `multiselect` fields are always stored as a json array in the database. - -Options: - -- `type` (default: `'string'`): Sets the type of the values of this field. - Must be one of `['string', 'enum', 'integer']`. -- `options`: An array of `{ label, value }`. - `label` is a string to be displayed in the Admin UI. - `value` is either a `string` (for `{ type: 'string' }` or `{ type: 'enum' }`), or a `number` (for `{ type: 'integer' }`). - The `value` will be used in the GraphQL API and stored in the database. -- `defaultValue` (default: `[]`): This value will be used for the field when creating items if no explicit value is set. -- `db.map`: Adds a [Prisma `@map`](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map) attribute to this field which changes the column name in the database -- `graphql.read.isNonNull` (default: `false`): If you have no read access control and you don't intend to add any in the future, - you can set this to true and the output field will be non-nullable. This is only allowed when you have no read access control because otherwise, - when access is denied, `null` will be returned which will cause an error since the field is non-nullable and the error - will propagate up until a nullable field is found which means the entire item will be unreadable and when doing an `items` query, all the items will be unreadable. -- `graphql.create.isNonNull` (default: `false`): If you have no create access control and you want to explicitly show that this is field is non-nullable in the create input - you can set this to true and the create field will be non-nullable and have a default value at the GraphQL level. - This is only allowed when you have no create access control because otherwise, the item will always fail access control - if a user doesn't have access to create the particular field regardless of whether or not they specify the field in the create. - -```typescript -import { config, list } from '@keystone-6/core'; -import { multiselect } from '@keystone-6/core/fields'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: multiselect({ - type: 'enum', - options: [ - { label: '...', value: '...' }, - /* ... */ - ], - defaultValue: ['...'], - db: { map: 'my_multiselect' }, - }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -### text - -A `text` field represents a string value. - -Options: - -- `defaultValue` (default: `db.isNullable === true ? undefined : ''`): This value will be used for the field when creating items if no explicit value is set. -- `db.map`: Adds a [Prisma `@map`](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map) attribute to this field which changes the column name in the database -- `db.isNullable` (default: `false`\*): If `true` then this field will be made nullable in the database and it will be possible to set as `null`. -- `db.nativeType`: Changes the [Prisma Native database type attibute](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string) from the default Prisma type for your database. - For more information see the [Choosing a Database Guide](../guides/choosing-a-database). -- `validation.isRequired` (default: `false`\*\*): If `true` then this field can never be set to `null` or an empty string. - Unlike `db.isNullable`, this will require that a value with at least 1 character is provided in the Admin UI. - It will also validate this when creating and updating an item through the GraphQL API but it will not enforce it at the database level. -- `validation.length.min` (default: `0`): This describes the minimum number allowed. If you attempt to submit a string shorter than this, you will get a validation error. -- `validation.length.max` (default: `undefined`): This describes the maximum length allowed. If you attempt to submit a string longer than this, you will get a validation error. -- `validation.match` (default: `undefined`): This describes a pattern that values for this field must match - - `validation.match.regex`: The regular expression - - `validation.match.explanation` (default: `${fieldLabel} must match ${validation.match.regex}`): A message shown in the Admin when a value doesn't match the regex and returned as a validation error from the GraphQL API -- `isIndexed` (default: `false`) - - If `true` then this field will be indexed by the database. - - If `'unique'` then all values of this field must be unique. -- `ui` (default: `{ displayMode: 'input' }`): Configures the display mode of the field in the Admin UI. - Can be one of `['input', 'textarea']`. -- `graphql.read.isNonNull` (default: `false`): If you have no read access control and you don't intend to add any in the future, - you can set this to true and the output field will be non-nullable. This is only allowed when you have no read access control because otherwise, - when access is denied, `null` will be returned which will cause an error since the field is non-nullable and the error - will propagate up until a nullable field is found which means the entire item will be unreadable and when doing an `items` query, all the items will be unreadable. -- `graphql.create.isNonNull` (default: `false`): If you have no create access control and you want to explicitly show that this is field is non-nullable in the create input - you can set this to true and the create field will be non-nullable and have a default value at the GraphQL level. - This is only allowed when you have no create access control because otherwise, the item will always fail access control - if a user doesn't have access to create the particular field regardless of whether or not they specify the field in the create. - -{% hint kind="tip" %} -**\*Warning** Unlike with other `keystone` fields, `db.isNullable` is defaulted to `false` for the text field. -This is primarily in the interest of not having to make assumptions about how a `null` value can be represented in a text field in the Admin-UI in the default case. -These differences, and the rationale for them, are examined in detail [on GitHub](https://github.com/keystonejs/keystone/discussions/7158). -You can opt into this behaviour by explicitly setting `isNullable: true`. -{% /hint %} - -```typescript -import { config, list } from '@keystone-6/core'; -import { text } from '@keystone-6/core/fields'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: text({ - defaultValue: '...', - db: { map: 'my_text', nativeType: 'VarChar(40)' }, - validation: { isRequired: true }, - isIndexed: 'unique', - ui: { displayMode: 'textarea' }, - }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -### timestamp - -A `timestamp` field represents a date time value in ISO8601 format. - -Options: - -- `defaultValue` (default: `undefined`): Can be either a string value with a date time string in ISO8601 format or `{ kind: 'now' }`. - This value will be used for the field when creating items if no explicit value is set. -- `db.map`: Adds a [Prisma `@map`](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map) attribute to this field which changes the column name in the database -- `db.isNullable` (default: `validation.isRequired ? false : true`): If `false` then this field will be made non-nullable in the database and it will never be possible to set as `null`. -- `validation.isRequired` (default: `false`): If `true` then this field can never be set to `null`. - It validate this when creating and updating an item through the GraphQL API or the Admin UI. - It will also default `db.isNullable` to false. -- `db.updatedAt` (default: `false`) If `true` then this field will add the `@updatedAt` attribute to this field in the Prisma schema. - This will update this field to the current time whenever an item is created/updated with the GraphQL API or any other usage of the Prisma Client if this field is not explicitly set in the request. - Note this happens at the Prisma Client level, not at the database so if you update an item in your database directly, fields with `db.updatedAt: true` will not automatically update. -- `isIndexed` (default: `false`) - - If `true` then this field will be indexed by the database. - - If `'unique'` then all values of this field must be unique. -- `graphql.read.isNonNull` (default: `false`): If you have no read access control and you don't intend to add any in the future, - you can set this to true and the output field will be non-nullable. This is only allowed when you have no read access control because otherwise, - when access is denied, `null` will be returned which will cause an error since the field is non-nullable and the error - will propagate up until a nullable field is found which means the entire item will be unreadable and when doing an `items` query, all the items will be unreadable. -- `graphql.create.isNonNull` (default: `false`): If you have no create access control and you want to explicitly show that this is field is non-nullable in the create input - you can set this to true and the create field will be non-nullable and have a default value at the GraphQL level. - This is only allowed when you have no create access control because otherwise, the item will always fail access control - if a user doesn't have access to create the particular field regardless of whether or not they specify the field in the create. - -```typescript -import { config, list } from '@keystone-6/core'; -import { timestamp } from '@keystone-6/core/fields'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: timestamp({ - defaultValue: '1970-01-01T00:00:00.000Z', - db: { map: 'my_timestamp' }, - validation: { isRequired: true }, - isIndexed: 'unique', - }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -### calendarDay - -A `calendarDay` field represents a date value only in ISO8601 format. - -On PostgreSQL and MySQL this is represented with the native date type. -On SQLite this is represented as a string. - -Options: - -- `defaultValue` (default: `undefined`): Can be a string value with a date string in ISO8601 format. - This value will be used for the field when creating items if no explicit value is set. -- `db.map`: Adds a [Prisma `@map`](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map) attribute to this field which changes the column name in the database -- `db.isNullable` (default: `validation.isRequired ? false : true`): If `false` then this field will be made non-nullable in the database and it will never be possible to set as `null`. -- `validation.isRequired` (default: `false`): If `true` then this field can never be set to `null`. - It validate this when creating and updating an item through the GraphQL API or the Admin UI. - It will also default `db.isNullable` to false. -- `isIndexed` (default: `false`) - - If `true` then this field will be indexed by the database. - - If `'unique'` then all values of this field must be unique. -- `graphql.read.isNonNull` (default: `false`): If you have no read access control and you don't intend to add any in the future, - you can set this to true and the output field will be non-nullable. This is only allowed when you have no read access control because otherwise, - when access is denied, `null` will be returned which will cause an error since the field is non-nullable and the error - will propagate up until a nullable field is found which means the entire item will be unreadable and when doing an `items` query, all the items will be unreadable. -- `graphql.create.isNonNull` (default: `false`): If you have no create access control and you want to explicitly show that this is field is non-nullable in the create input - you can set this to true and the create field will be non-nullable and have a default value at the GraphQL level. - This is only allowed when you have no create access control because otherwise, the item will always fail access control - if a user doesn't have access to create the particular field regardless of whether or not they specify the field in the create. - -```typescript -import { config, list } from '@keystone-6/core'; -import { calendarDay } from '@keystone-6/core/fields'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: calendarDay({ - defaultValue: '1970-01-01', - db: { map: 'my_date' }, - validation: { isRequired: true }, - isIndexed: 'unique', - }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -## Relationship type - -### relationship - -A `relationship` field represents a relationship between two lists. - -Read our [relationships guide](../guides/relationships) for details on Keystone’s relationship model and how to configure them in your project. - -- `ref` (required): A string of the form `` or `.`. -- `many` (default: `false`): Configures the cardinality of the relationship. -- `db.foreignKey`: When `true` or an object, ensures the foreign Key for two-sided relationships is stored in the table for this list (only available on single relationships, and not on both sides of a 1:1 relationship) - - `map`: Changes the column name in the database -- `ui` (default: `{ hideCreate: false, displayMode: 'select' }`): Configures the display mode of the field in the Admin UI. - - `hideCreate` (default: `false`). If `true`, the "Create related item" button is not shown in the item view. - - `displayMode` (default: `'select'`): Controls the mode used to display the field in the item view. The mode `'select'` displays related items in a select component, while `'cards'` displays the related items in a card layout. Each display mode supports further configuration. -- `ui.displayMode === 'select'` options: - - `labelField`: The field path from the related list to use for item labels in the select. Defaults to the `labelField` configured on the related list. -- `ui.displayMode === 'cards'` options: - - `cardFields`: A list of field paths from the related list to render in the card component. Defaults to `'id'` and the `labelField` configured on the related list. - - `linkToItem` (default `false`): If `true`, the default card component will render as a link to navigate to the related item. - - `removeMode` (default: `'disconnect'`): Controls whether the `Remove` button is present in the card. If `'disconnect'`, the button will be present. If `'none'`, the button will not be present. - - `inlineCreate` (default: `null`): If not `null`, an object of the form `{ fields: [...] }`, where `fields` is a list of field paths from the related list should be provided. An inline `Create` button will be included in the cards allowing a new related item to be created based on the configured field paths. - - `inlineEdit` (default: `null`): If not `null`, an object of the form `{ fields: [...] }`, where `fields` is a list of field paths from the related list should be provided. An `Edit` button will be included in each card, allowing the configured fields to be edited for each related item. - - `inlineConnect` (default: `false`): If `true`, an inline `Link existing item` button will be present, allowing existing items of the related list to be connected in this field. -- `ui.displayMode === 'count'` only supports `many` relationships - -```typescript -import { config, list } from '@keystone-6/core'; -import { relationship } from '@keystone-6/core/fields'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: relationship({ - ref: '...', - many: false, - db: { - foreignKey: { - map: 'foreign_id', - }, - }, - ui: { - hideCreate: false, - // Display mode: 'select' - displayMode: 'select', - labelField: 'name', - // Display mode: 'cards' - displayMode: 'cards', - cardFields: [...], - linkToItem: true, - removeMode: 'disconnect', - inlineCreate: { fields: [...] }, - inlineEdit: { fields: [...] }, - inlineConnect: true, - // Display mode: 'count' - // requires many: true above - displayMode: 'count', - }, - }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -## Virtual type - -### virtual - -A `virtual` field represents a value which is computed at read time, rather than stored in the database. -See the [virtual fields guide](../guides/virtual-fields) for details on how to use virtual fields. - -Options: - -- `field` (required): The GraphQL field that defines the type, resolver and arguments. -- `ui.query` (default: `''` ): - Defines what the Admin UI should fetch from this field, it's interpolated into a query like this: - ```graphql - query { - item(where: { id: "..." }) { - field${ui.query} - } - } - ``` - This is only needed when you your field returns a GraphQL type other than a scalar(String and etc.) - or an enum or you need to provide arguments to the field. - -```typescript -import { config, createSchema, graphql, list } from '@keystone-6/core'; -import { virtual } from '@keystone-6/core/fields'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: virtual({ - field: graphql.field({ - type: graphql.String, - args: { something: graphql.arg({ type: graphql.Int }) }, - resolve(item, args, context, info) { - - } - }) - }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -## File types - -File types allow you to upload different types of files to your Keystone system. - -### file - -A `file` field represents a file of any type. - -See [`config.storage`](./config#storage) for details on how to configure your Keystone system with support for the `file` field type. - -```typescript -import { config, list } from '@keystone-6/core'; -import { file } from '@keystone-6/core/fields'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - repo: file({ storage: 'my_file_storage' }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -Options: - -- `storage`(required): A string that is the key for one of the entries in the storage object. This - is used to determine what storage config will be used. - -### image - -An `image` field represents an image file, i.e. `.jpg`, `.png`, `.webp`, or `.gif`. - -See [`config.storage`](./config#storage) for details on how to configure your Keystone system with support for the `image` field type. - -```typescript -import { config, list } from '@keystone-6/core'; -import { image } from '@keystone-6/core/fields'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - avatar: image({ storage: 'my_image_storage' }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -Options: - -- `storage`(required): A string that is the key for one of the entries in the storage object. This - is used to determine what storage config will be used. - -## Complex types - -### document - -A highly customizable, [Slate](https://docs.slatejs.org/)-based, rich text editor that lets content creators quickly and easily edit content in your system. -See the [Document Field guide](https://keystonejs.com/docs/guides/document-fields), -[demo](https://keystonejs.com/docs/guides/document-field-demo) and -[example project](https://github.com/keystonejs/keystone/tree/main/examples/document-field) for details. - -Options: - -- `relationships` -- `componentBlocks` -- `formatting` -- `links` -- `dividers` -- `layouts` - -```typescript -import { config, list } from '@keystone-6/core'; -import { document } from '@keystone-6/fields-document'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: document({ - relationships: { /* ... */ }, - componentBlocks: { - block: { /* ... */ }, - /* ... */ - }, - formatting: { /* ... */ }, - links: true, - dividers: true, - layouts: [/* ... */], - }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -### cloudinaryImage - -Upload images to your Cloudinary account via Keystone's Admin UI. - -- `cloudinary`: Configuration for the connected Cloudinary account. - - `cloudName` - TODO - - `apiKey` - TODO - - `apiSecret` - TODO - - `folder` - TODO - -```typescript -import { config, list } from '@keystone-6/core'; -import { cloudinaryImage } from '@keystone-6/cloudinary'; - -export default config({ - lists: { - SomeListName: list({ - fields: { - someFieldName: cloudinaryImage({ - cloudinary: { - cloudName: process.env.CLOUDINARY_CLOUD_NAME, - apiKey: process.env.CLOUDINARY_API_KEY, - apiSecret: process.env.CLOUDINARY_API_SECRET, - folder: process.env.CLOUDINARY_API_FOLDER, - }, - }), - /* ... */ - }, - }), - /* ... */ - }, - /* ... */ -}); -``` - -## Related resources - -{% related-content %} -{% well -heading="Lists API Reference" -href="/docs/apis/schema" %} -The API to configure your options used with the `list()` function. -{% /well %} -{% well -heading="GraphQL API Reference" -href="/docs/apis/graphql" %} -A complete CRUD (create, read, update, delete) GraphQL API derived from the list and field names you configure in your system. -{% /well %} -{% /related-content %} diff --git a/docs/pages/docs/apis/index.tsx b/docs/pages/docs/apis/index.tsx deleted file mode 100644 index 242b64f9a79..00000000000 --- a/docs/pages/docs/apis/index.tsx +++ /dev/null @@ -1,109 +0,0 @@ -/** @jsxRuntime classic */ -/** @jsx jsx */ -import { jsx } from '@emotion/react'; - -import { CommunitySlackCTA } from '../../../components/docs/CommunitySlackCTA'; -import { Type } from '../../../components/primitives/Type'; -import { Well } from '../../../components/primitives/Well'; -import { DocsPage } from '../../../components/Page'; -import { useMediaQuery } from '../../../lib/media'; - -export default function Docs() { - const mq = useMediaQuery(); - - return ( - - - API Reference - - - - - - Configuration - - -
    - - Keystone’s config function accepts an object representing all the configurable parts of - your backend system. - - - This is where you define the data model, or schema, of your Keystone system. - - - Defines the names, types, and configuration of the fields in a Keystone list. - - - Configures who can read, create, update, and delete items in your Keystone system - - - Let you execute code at different stages of the mutation lifecycle when performing create, - update, and delete operations. - - - Lets you configure session management in your Keystone system. - - - Supports authentication against a password field, creating initial items, password resets, - and one-time authentication tokens. - -
    - - - Context - - -
    - - The primary API entry point for all of the run-time functionally of your Keystone system. - - - A programmatic API for running CRUD operations against your GraphQL API. - - - A programmatic API for running CRUD operations against the internal GraphQL resolvers in - your system. - -
    - - - GraphQL - - -
    - - Generates a CRUD (create, read, update, delete) GraphQL API based on the schema definition - provided in your system configuration. - - - A list of the filters you can query against for each field type. - -
    -
    - ); -} diff --git a/docs/pages/docs/apis/access-control.md b/docs/pages/docs/config/access-control.md similarity index 93% rename from docs/pages/docs/apis/access-control.md rename to docs/pages/docs/config/access-control.md index 92a35a48b7b..b8efa812c2d 100644 --- a/docs/pages/docs/apis/access-control.md +++ b/docs/pages/docs/config/access-control.md @@ -1,5 +1,5 @@ --- -title: "Access Control API" +title: "Access Control" description: "Complete reference docs for Keystone’s Access Control API. Configure who can read, create, update, and delete items in your Keystone system." --- @@ -7,8 +7,8 @@ description: "Complete reference docs for Keystone’s Access Control API. Confi We recently improved this API so it’s easier to program, and makes it harder to introduce security gaps in your system. If you were using it prior to September 1st 2022, you will need to now configure access control for your operations. {% /hint %} -The `access` property of the [list configuration](./schema) object configures who can query, create, update, and delete items in your Keystone system. -The `access` property of the [field configuration](./fields) object configures who can read, create, and update specific field values of an item. +The `access` property of the [list configuration](./lists) object configures who can query, create, update, and delete items in your Keystone system. +The `access` property of the [field configuration](../fields/overview) object configures who can read, create, and update specific field values of an item. ```typescript import { config, list } from '@keystone-6/core'; @@ -33,7 +33,7 @@ Keystone provides support for access control and filtering on a per-list basis. There are three types of access control that can be configured on the `access` object: - [`operation`](#operation), functions that provide the `context` and `session` to help decide if a request should be granted access to the list; this happens prior to any GraphQL query being executed. -- [`filter`](#filter), functions which return a [filter](./filters) that is applied to database queries on this list. +- [`filter`](#filter), functions which return a [filter](../graphql/filters) that is applied to database queries on this list. - [`item`](#item-mutations-only), functions that provide the `context` and `session` to determine if a request can execute the respective mutative action. Each of these types of access control are applied before [hooks](./hooks). @@ -141,12 +141,12 @@ export default config({ {% hint kind="warn" %} The `query` access control is applied only when running GraphQL query operations. A user can still **read** fields as part of a return query when using a mutation `operation` (`create`, `update` or `delete`). -If you want to limit access to fields, use [field access control](https://keystonejs.com/docs/apis/access-control#field-access-control). +If you want to limit access to fields, use [field access control](https://keystonejs.com/docs/config/access-control#field-access-control). {% /hint %} ### Filter -Filter-level access control lets you restrict which items can be operated on by providing a function which returns a [GraphQL filter](./filters). +Filter-level access control lets you restrict which items can be operated on by providing a function which returns a [GraphQL filter](../graphql/filters). - For **mutations**, the access control filter will be combined with the unique identifier provided to the operation, and access will be denied if no item is found with this combined filter. - For **queries**, the access control filter will be combined with the query filter and only items which match both filters will be returned. @@ -244,7 +244,7 @@ List-level access control functions are passed a collection of arguments which c | Argument | Description | | ----------- | ------------------------------------------------------------------------------------------------------------- | | `session` | The current session object. See the [Sessions API](./session) for details. | -| `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | +| `context` | The [`KeystoneContext`](../context/overview) object of the originating GraphQL operation. | | `listKey` | The key of the list being operated on. | | `operation` | The operation being performed (`'query'`, `'create'`, `'update'`, `'delete'`). | | `inputData` | For `create` and `update` operations, this is the value of `data` passed into the mutation. (Item level only) | @@ -308,7 +308,7 @@ Field-level access control functions are passed a collection of arguments which | Argument | Description | | ----------- | ------------------------------------------------------------------------------------------- | | `session` | The current session object. See the [Sessions API](./session) for details. | -| `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | +| `context` | The [`KeystoneContext`](../context/overview) object of the originating GraphQL operation. | | `listKey` | The key of the list being operated on. | | `fieldKey` | The key of the field being operated on. | | `operation` | The operation being performed (`'read'`, `'create'`, `'update'`). | diff --git a/docs/pages/docs/apis/auth.md b/docs/pages/docs/config/auth.md similarity index 98% rename from docs/pages/docs/apis/auth.md rename to docs/pages/docs/config/auth.md index 6b5249e61c0..5c8d685f569 100644 --- a/docs/pages/docs/apis/auth.md +++ b/docs/pages/docs/config/auth.md @@ -1,5 +1,5 @@ --- -title: "Authentication API" +title: "Authentication" description: "API reference for supporting authentication against a password field using the createAuth() function in the `@keystone-6/auth` package." --- @@ -238,7 +238,7 @@ It is expected that you will use these mutations as part of a password reset wor - `itemId`: The ID of the user requesting the password reset. - `identity`: The identity value provided to the `sendUserPasswordResetLink` mutation. - `token`: The token the user must supply to use `redeemUserPasswordResetToken`. - - `context`: A [`KeystoneContext`](./context) object. + - `context`: A [`KeystoneContext`](../context/overview) object. - `tokensValidForMins` (default: `10`, max: `24 * 60` (1 day), min: `0.16` (10 seconds)): The length of time, in minutes, that the token is valid for. ```typescript @@ -361,7 +361,7 @@ It is expected that you will use these mutations as part of a one-time authentic - `itemId`: The ID of the user requesting the one-time authentication link. - `identity`: The identity value provided to the `sendUserMagicAuthLink` mutation. - `token`: The token the user must supply to use `redeemUserMagicAuthToken`. - - `context`: A [`KeystoneContext`](./context) object. + - `context`: A [`KeystoneContext`](../context/overview) object. - `tokensValidForMins` (default: `10`, max: `24 * 60` (1 day), min: `0.16` (10 seconds)): The length of time, in minutes, that the token is valid for. ```typescript @@ -459,7 +459,7 @@ The authenticated item will be returned as `item`. {% related-content %} {% well heading="Example Project: Authentication" -href="https://github.com/keystonejs/keystone/tree/main/examples/with-auth" %} +href="" %} Adds password-based authentication to the Task Manager starter project. {% /well %} {% /related-content %} diff --git a/docs/pages/docs/apis/config.md b/docs/pages/docs/config/config.md similarity index 96% rename from docs/pages/docs/apis/config.md rename to docs/pages/docs/config/config.md index 7f9981fab7e..b80c49c75c3 100644 --- a/docs/pages/docs/apis/config.md +++ b/docs/pages/docs/config/config.md @@ -1,5 +1,5 @@ --- -title: "System Configuration API" +title: "System Configuration" description: "API reference for configuring your Keystone system: Lists, Database, Admin UI, Server, Sessions, GraphQl, Files, Images, and experimental options." --- @@ -37,7 +37,7 @@ This type definition should be considered the source of truth for the available The `lists` config option is where you define the data model, or schema, of the Keystone system. It has a TypeScript type of `ListSchemaConfig`. This is where you define and configure the `lists` and their `fields` of the data model. -See the [Lists API](./schema) docs for details on how to use this function. +See the [Lists API](./lists) docs for details on how to use this function. ```typescript import type { ListSchemaConfig } from '@keystone-6/core/types'; @@ -62,7 +62,7 @@ These database types are powered by their corresponding Prisma database provider - `provider`: The database provider to use, it can be one of `postgresql`, `mysql` or `sqlite`. - `url`: The connection URL for your database -- `onConnect`: which takes a [`KeystoneContext`](./context) object, and lets perform any actions you might need at startup, such as data seeding +- `onConnect`: which takes a [`KeystoneContext`](../context/overview) object, and lets perform any actions you might need at startup, such as data seeding - `enableLogging` (default: `false`): Enable logging from the Prisma client. - `useMigrations` (default: `false`): Determines whether to use migrations or automatically force-update the database with the latest schema and potentially lose data. - `idField` (default: `{ kind: "cuid" }`): The kind of id field to use, it can be one of: `cuid`, `uuid` or `autoincrement`. @@ -144,13 +144,13 @@ import type { AdminUIConfig } from '@keystone-6/core/types'; The `ui` config option configures the Admin UI which is provided by Keystone. It has a TypeScript type of `AdminUIConfig`. This config option is for top level configuration of the Admin UI. -Fine grained configuration of how lists and fields behave in the Admin UI is handled in the `lists` definition (see the [Lists API](./schema) for more details). +Fine grained configuration of how lists and fields behave in the Admin UI is handled in the `lists` definition (see the [Lists API](./lists) for more details). Options: - `isDisabled` (default: `false`): If `isDisabled` is set to `true` then the Admin UI will be completely disabled. - `isAccessAllowed` (default: `(context) => !!context.session`): This function controls whether a user is able to access the Admin UI. - It takes a [`KeystoneContext`](./context) object as an argument. + It takes a [`KeystoneContext`](../context/overview) object as an argument. Advanced configuration: @@ -387,7 +387,7 @@ Options: - `debug` (default: `process.env.NODE_ENV !== 'production'`): If `true`, stacktraces from both Apollo errors and Keystone errors will be included in the errors returned from the GraphQL API. These can be filtered out with `apolloConfig.formatError` if you need to process them, but do not want them returned over the GraphQL API. - `queryLimits` (default: `undefined`): Allows you to limit the total number of results returned from a query to your GraphQL API. - See also the per-list `graphql.queryLimits` option in the [Lists API](./schema). + See also the per-list `graphql.queryLimits` option in the [Lists API](./lists). - `path` (default: `'/api/graphql'`): The path of the GraphQL API endpoint. - `playground` (default: `process.env.NODE_ENV !== 'production'`) - `true` - Add `ApolloServerPluginLandingPageGraphQLPlayground` to the Apollo Server plugins @@ -438,8 +438,8 @@ See the [schema extension guide](../guides/schema-extension) for more details on import type { StorageConfig } from '@keystone-6/core/types' ``` -The `storage` config option provides configuration which is used by the [`file`](./fields#file) field type or the -[`image`](./fields#image) field type. You provide an object whose property is a `StorageConfig` object, fields then reference this `storage` by the key. +The `storage` config option provides configuration which is used by the [`file`](../fields/file) field type or the +[`image`](../fields/image) field type. You provide an object whose property is a `StorageConfig` object, fields then reference this `storage` by the key. Each storage is configured separately using the options below. A single storage may be used by multiple file or image fields, but only for files or images. @@ -551,7 +551,7 @@ Options: {% related-content %} {% well heading="Lists API Reference" -href="/docs/apis/schema" %} +href="/docs/config/lists" %} The API to configure your options used with the `list` function. {% /well %} {% /related-content %} diff --git a/docs/pages/docs/apis/hooks.md b/docs/pages/docs/config/hooks.md similarity index 86% rename from docs/pages/docs/apis/hooks.md rename to docs/pages/docs/config/hooks.md index fd4195d4d0c..9c44c4ef2f8 100644 --- a/docs/pages/docs/apis/hooks.md +++ b/docs/pages/docs/config/hooks.md @@ -1,5 +1,5 @@ --- -title: "Hooks API" +title: "Hooks" description: "Hooks let you to execute code at different stages of the mutation lifecycle when performing create, update, and delete operations." --- @@ -55,15 +55,15 @@ For field hooks, the return value should be an updated value for that specific f For list hooks, the return value should be a [`resolved data`](#resolved-data-stages) object. The result of `resolveInput` will be passed as `resolvedData` into the next stages of the operation. -| Argument | Description | -| :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `listKey` | The key of the list being operated on. | -| `fieldKey` | The key of the field being operated on (field hooks only). | -| `operation` | The operation being performed (`'create'` or `'update'`). | -| `inputData` | The value of `data` passed into the mutation. | -| `item` | The currently stored item (`undefined` for `create` operations). This object is an internal database item. [DB API](./db-items) for more details on internal database items. | -| `resolvedData` | A [`resolved data`](#resolved-data-stages) object. The resolved data value after default values, relationship resolvers, and field resolvers have been applied. | -| `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | +| Argument | Description | +| :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `listKey` | The key of the list being operated on. | +| `fieldKey` | The key of the field being operated on (field hooks only). | +| `operation` | The operation being performed (`'create'` or `'update'`). | +| `inputData` | The value of `data` passed into the mutation. | +| `item` | The currently stored item (`undefined` for `create` operations). This object is an internal database item. [DB API](../context/db-items) for more details on internal database items. | +| `resolvedData` | A [`resolved data`](#resolved-data-stages) object. The resolved data value after default values, relationship resolvers, and field resolvers have been applied. | +| `context` | The [`KeystoneContext`](../context/overview) object of the originating GraphQL operation. | ```typescript import { config, list } from '@keystone-6/core'; @@ -117,16 +117,16 @@ It is invoked after the `resolveInput` hooks have been run. If the `resolvedData` is invalid then the function should report validation errors with `addValidationError(msg)`. These error messages will be returned as a `ValidationFailureError` from the GraphQL API, and the operation will not be completed. -| Argument | Description | -| :------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `listKey` | The key of the list being operated on. | -| `fieldKey` | The key of the field being operated on (field hooks only). | -| `operation` | The operation being performed (`'create'` or `'update'`). | -| `inputData` | The value of `data` passed into the mutation. | -| `item` | The current value of the item being updated (`undefined` for `create` operations). This object is an internal database item. [DB API](./db-items) for more details on internal database items. | -| `resolvedData` | A [`resolved data`](#resolved-data-stages) object. The resolved data value after all data resolver stages have been completed. | -| `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | -| `addValidationError(msg)` | Used to set a validation error. | +| Argument | Description | +| :------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `listKey` | The key of the list being operated on. | +| `fieldKey` | The key of the field being operated on (field hooks only). | +| `operation` | The operation being performed (`'create'` or `'update'`). | +| `inputData` | The value of `data` passed into the mutation. | +| `item` | The current value of the item being updated (`undefined` for `create` operations). This object is an internal database item. [DB API](../context/db-items) for more details on internal database items. | +| `resolvedData` | A [`resolved data`](#resolved-data-stages) object. The resolved data value after all data resolver stages have been completed. | +| `context` | The [`KeystoneContext`](../context/overview) object of the originating GraphQL operation. | +| `addValidationError(msg)` | Used to set a validation error. | ```typescript import { config, list } from '@keystone-6/core'; @@ -176,14 +176,14 @@ It is invoked after access control has been applied. If the delete operation is invalid then the function should report validation errors with `addValidationError(msg)`. These error messages will be returned as a `ValidationFailureError` from the GraphQL API. -| Argument | Description | -| :------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------- | -| `listKey` | The key of the list being operated on. | -| `fieldKey` | The key of the field being operated on (field hooks only). | -| `operation` | The operation being performed (`'delete'`). | -| `item` | The value of the item to be deleted. This object is an internal database item. [DB API](./db-items) for more details on internal database items. | -| `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | -| `addValidationError(msg)` | Used to set a validation error. | +| Argument | Description | +| :------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `listKey` | The key of the list being operated on. | +| `fieldKey` | The key of the field being operated on (field hooks only). | +| `operation` | The operation being performed (`'delete'`). | +| `item` | The value of the item to be deleted. This object is an internal database item. [DB API](../context/db-items) for more details on internal database items. | +| `context` | The [`KeystoneContext`](../context/overview) object of the originating GraphQL operation. | +| `addValidationError(msg)` | Used to set a validation error. | ```typescript import { config, list } from '@keystone-6/core'; @@ -226,15 +226,15 @@ The `beforeOperation` function is used to perform side effects just before the d It is invoked after all `validateInput`/`validateDelete` hooks have been run, but before the database is updated. -| Argument | Description | -| :------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `listKey` | The key of the list being operated on. | -| `fieldKey` | The key of the field being operated on (field hooks only). | -| `operation` | The operation being performed (`'create'`, `'update'`, or `'delete'`). | -| `inputData` | The value of `data` passed into the mutation. `undefined` for `delete` operations. | -| `item` | The current value of the item being updated, `undefined` for `create` operations. This object is an internal database item. [DB API](./db-items) for more details on internal database items. | -| `resolvedData` | A [`resolved data`](#resolved-data-stages) object. The resolved data value after all data resolver stages have been completed. `undefined` for `delete` operations. | -| `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | +| Argument | Description | +| :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `listKey` | The key of the list being operated on. | +| `fieldKey` | The key of the field being operated on (field hooks only). | +| `operation` | The operation being performed (`'create'`, `'update'`, or `'delete'`). | +| `inputData` | The value of `data` passed into the mutation. `undefined` for `delete` operations. | +| `item` | The current value of the item being updated, `undefined` for `create` operations. This object is an internal database item. [DB API](../context/db-items) for more details on internal database items. | +| `resolvedData` | A [`resolved data`](#resolved-data-stages) object. The resolved data value after all data resolver stages have been completed. `undefined` for `delete` operations. | +| `context` | The [`KeystoneContext`](../context/overview) object of the originating GraphQL operation. | ```typescript import { config, list } from '@keystone-6/core'; @@ -277,16 +277,16 @@ export default config({ The `afterOperation` function is used to perform side effects after the data has been saved to the database (for a `create` or `update` operation), or deleted from the database (for `delete` operations). -| Argument | Description | -| :------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `listKey` | The key of the list being operated on. | -| `fieldKey` | The key of the field being operated on (field hooks only). | -| `operation` | The operation being performed (`'create'`, `'update'`, or `'delete'`). | -| `inputData` | The value of `data` passed into the mutation. `undefined` for `delete` operations. | -| `originalItem` | The original value of the item being updated or deleted, `undefined` for `create` operations. This object is an internal database item. [DB API](./db-items) for more details on internal database items. | -| `item` | The new value of the item being updated or created, `undefined` for `delete` operations. This object is an internal database item. [DB API](./db-items) for more details on internal database items. | -| `resolvedData` | A [`resolved data`](#resolved-data-stages) object. The resolved data value after all data resolver stages have been completed. `undefined` for `delete` operations. | -| `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | +| Argument | Description | +| :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `listKey` | The key of the list being operated on. | +| `fieldKey` | The key of the field being operated on (field hooks only). | +| `operation` | The operation being performed (`'create'`, `'update'`, or `'delete'`). | +| `inputData` | The value of `data` passed into the mutation. `undefined` for `delete` operations. | +| `originalItem` | The original value of the item being updated or deleted, `undefined` for `create` operations. This object is an internal database item. [DB API](../context/db-items) for more details on internal database items. | +| `item` | The new value of the item being updated or created, `undefined` for `delete` operations. This object is an internal database item. [DB API](../context/db-items) for more details on internal database items. | +| `resolvedData` | A [`resolved data`](#resolved-data-stages) object. The resolved data value after all data resolver stages have been completed. `undefined` for `delete` operations. | +| `context` | The [`KeystoneContext`](../context/overview) object of the originating GraphQL operation. | ```typescript import { config, list } from '@keystone-6/core'; diff --git a/docs/pages/docs/apis/schema.md b/docs/pages/docs/config/lists.md similarity index 96% rename from docs/pages/docs/apis/schema.md rename to docs/pages/docs/config/lists.md index 70ec1791495..3d18f2877ea 100644 --- a/docs/pages/docs/apis/schema.md +++ b/docs/pages/docs/config/lists.md @@ -58,7 +58,7 @@ export default config({ }); ``` -For full details on the available field types and their configuration options please see the [Fields API](./fields). +For full details on the available field types and their configuration options please see the [Fields API](../fields/overview). ## access @@ -88,17 +88,17 @@ Options: - `createView`: Controls the create view page of the Admin UI. - `defaultFieldMode` (default: `'edit'`): Can be overridden by per-field values in the `field.ui.createView.fieldMode` config. - See the [Fields API](./fields#common-configuration) for details. + See the [Fields API](../fields/overview#common-configuration) for details. Can be one of `['edit', 'hidden']`, or an async function with an argument `{ session, context }` that returns one of `['edit', 'hidden']`. - `itemView`: Controls the item view page of the Admin UI. - `defaultFieldMode` (default: `'edit'`): Can be overridden by per-field values in the `field.ui.itemView.fieldMode` config. - See the [Fields API](./fields#common-configuration) for details. + See the [Fields API](../fields/overview#common-configuration) for details. Can be one of `['edit', 'read', 'hidden']`, or an async function with an argument `{ session, context, item }` that returns one of `['edit', 'read', 'hidden']`. - `listView`: Controls the list view page of the Admin UI. - `defaultFieldMode` (default: `'read'`): Controls the default mode of fields in the list view. Can be overridden by per-field values in the `field.ui.listView.fieldMode` config. - See the [Fields API](./fields#common-configuration) for details. + See the [Fields API](../fields/overview#common-configuration) for details. Can be one of `['read', 'hidden']`, or an async function with an argument `{ session, context }` that returns one of `['read', 'hidden']`. - `initialColumns` (default: The first three fields defined in the list). A list of field names to display in columns in the list view. By default only the label column, as determined by `labelField`, is shown. - `initialSort` (default: `undefined`): Sets the field and direction to be used to initially sort the data in the list view. @@ -235,12 +235,12 @@ This option can be individually overridden by the `graphql.description` or `ui.d {% related-content %} {% well heading="Fields API Reference" -href="/docs/apis/fields" %} +href="/docs/fields/overview" %} Defines the names, types, and configuration of Keystone fields. See all the fields and the configuration options they accept. {% /well %} {% well heading="Config API Reference" -href="/docs/apis/config" %} +href="/docs/config/overview" %} The API to configure all the parts parts of your Keystone system. {% /well %} {% well diff --git a/docs/pages/docs/config/overview.tsx b/docs/pages/docs/config/overview.tsx new file mode 100644 index 00000000000..e38245452b7 --- /dev/null +++ b/docs/pages/docs/config/overview.tsx @@ -0,0 +1,66 @@ +/** @jsxRuntime classic */ +/** @jsx jsx */ +import { jsx } from '@emotion/react'; + +import { CommunitySlackCTA } from '../../../components/docs/CommunitySlackCTA'; +import { Type } from '../../../components/primitives/Type'; +import { Well } from '../../../components/primitives/Well'; +import { DocsPage } from '../../../components/Page'; +import { useMediaQuery } from '../../../lib/media'; + +export default function Docs() { + const mq = useMediaQuery(); + + return ( + + + Configuration Overview + + + + + + Configuration + + +
    + + Keystone's config function accepts an object representing all the configurable parts of + your backend system. + + + This is where you define the data model, or schema, of your Keystone system. + + + Defines the names, types, and configuration of the fields in a Keystone list. + + + Configures who can read, create, update, and delete items in your Keystone system + + + Let you execute code at different stages of the mutation lifecycle when performing create, + update, and delete operations. + + + Lets you configure session management in your Keystone system. + + + Supports authentication against a password field, creating initial items, password resets, + and one-time authentication tokens. + +
    +
    + ); +} diff --git a/docs/pages/docs/apis/session.md b/docs/pages/docs/config/session.md similarity index 97% rename from docs/pages/docs/apis/session.md rename to docs/pages/docs/config/session.md index 3b6a644cf2c..7d5c0cd86c8 100644 --- a/docs/pages/docs/apis/session.md +++ b/docs/pages/docs/config/session.md @@ -1,5 +1,5 @@ --- -title: "Session API" +title: "Session" description: "Reference docs for the session property of Keystone’s system configuration object." --- @@ -114,7 +114,7 @@ export default config({ ## Session context -If you configure your Keystone session with session management then the [`KeystoneContext`](./context) type will include three session related properties. +If you configure your Keystone session with session management then the [`KeystoneContext`](../context/overview) type will include three session related properties. - `session`: An object representing the session data. The value will depend on the value passed into `context.startSession()`. - `startSession`: A function `data => {...}` which will start a new session using the provided `data` value. @@ -128,7 +128,7 @@ These mutations will set the value of `session` to include the values `{ listKey {% related-content %} {% well heading="Config API Reference" -href="/docs/apis/config" %} +href="/docs/config/config" %} The API to configure all the parts parts of your Keystone system. {% /well %} {% well diff --git a/docs/pages/docs/apis/db-items.md b/docs/pages/docs/context/db-items.md similarity index 85% rename from docs/pages/docs/apis/db-items.md rename to docs/pages/docs/context/db-items.md index 32ae47fc887..6d425dc12e8 100644 --- a/docs/pages/docs/apis/db-items.md +++ b/docs/pages/docs/context/db-items.md @@ -1,16 +1,14 @@ --- -title: "Database API" -description: "Keystone’s database API is a programmatic API for running CRUD operations against the internal GraphQL resolvers in your system. It bypasses the GraphQL Server itself, invoking resolver functions directly." +title: "Database" +description: "Keystone's database API is a programmatic API for running CRUD operations against the internal GraphQL resolvers in your system. It bypasses the GraphQL Server itself, invoking resolver functions directly." --- The database API provides a programmatic API for running CRUD operations against the internal GraphQL resolvers in your system. Importantly, this API bypasses the GraphQL Server itself, instead invoking the resolver functions directly. The return values of this API are **internal item** objects, which are suitable to be returned from GraphQL resolvers. -Refer to the [internal items guide](../guides/internal-items) for details on how to work with internal items in Keystone. - -This API executes the [`access control`](../guides/auth-and-access-control) rules and [`hooks`](../guides/hooks) defined in your system. -To bypass these, you can directly use the Prisma Client at [`context.prisma`](./context#database-access). +This API executes the [`access control`](../guides/auth-and-access-control) rules and [`hooks`](../config/hooks) defined in your system. +To bypass these, you can directly use the Prisma Client at [`context.prisma`](../context/overview#database-access). For each list in your system the following API is available at `context.db.`. @@ -28,7 +26,7 @@ For each list in your system the following API is available at `context.db.`. {% /well %} {% well heading="Context API Reference" -href="/docs/apis/context" %} +href="/docs/context/overview" %} The API for run-time functionality in your Keystone system. Use it to write business logic for access control, hooks, testing, GraphQL schema extensions, and more. {% /well %} {% /related-content %} diff --git a/docs/pages/docs/apis/context.md b/docs/pages/docs/context/overview.md similarity index 93% rename from docs/pages/docs/apis/context.md rename to docs/pages/docs/context/overview.md index aa7a89c2b49..37a437134e7 100644 --- a/docs/pages/docs/apis/context.md +++ b/docs/pages/docs/context/overview.md @@ -1,5 +1,5 @@ --- -title: "Context API" +title: "Context Overview" description: "The KeystoneContext object is the primary API entry point for all of the run-time functionality of your system. It's APIs can be used to write things like access control, hooks, testing and GraphQL schema extensions." --- @@ -93,7 +93,7 @@ See the [schema extension guide](../guides/schema-extension) for examples of usi ### Session API If you configure your Keystone system with session management then you will have access to the following properties. -See the [session API](./session#session-context) for more details. +See the [session API](../config/session#session-context) for more details. `session`: The current session data object. @@ -118,7 +118,7 @@ The `KeystoneContext` object exposes the underlying database driver directly via ### Images API -If [support for image fields](./config#images) is enabled in the system, then an `images` API will be made available on the `context` object. +If [support for image fields](../config/config#storage-images-and-files) is enabled in the system, then an `images` API will be made available on the `context` object. This API takes advantage of the following types: ``` @@ -146,9 +146,9 @@ type ImageData = { These properties are used internally by Keystone and generally do not need to be directly accessed. -`totalResults`: The cumulative total number of results returned by the current request. See [`config.graphql.queryLimits`](./config#graphql). +`totalResults`: The cumulative total number of results returned by the current request. See [`config.graphql.queryLimits`](../config/config#graphql). -`maxTotalResults`: The maximum number of results which can be returned before a query limit error is triggered. See [`config.graphql.queryLimits`](./config#graphql). +`maxTotalResults`: The maximum number of results which can be returned before a query limit error is triggered. See [`config.graphql.queryLimits`](../config/config#graphql). ### Deprecated @@ -162,12 +162,12 @@ They will be removed in future releases. {% related-content %} {% well heading="Query API Reference" -href="/docs/apis/query" %} +href="/docs/context/query" %} A programmatic API for running CRUD operations against your GraphQL API. For each list in your system you get an API at `context.query.` {% /well %} {% well heading="DB API Reference" -href="/docs/apis/db-items" %} +href="/docs/context/db-items" %} The API for running CRUD operations against the internal GraphQL resolvers in your system. It returns internal item objects, which can be returned from GraphQL resolvers. {% /well %} {% /related-content %} diff --git a/docs/pages/docs/apis/query.md b/docs/pages/docs/context/query.md similarity index 97% rename from docs/pages/docs/apis/query.md rename to docs/pages/docs/context/query.md index 2fb3a47371f..afc0f248a91 100644 --- a/docs/pages/docs/apis/query.md +++ b/docs/pages/docs/context/query.md @@ -1,5 +1,5 @@ --- -title: "Query API" +title: "Query" description: "Reference docs for Keystone‘s Query API: a programmatic API for running CRUD operations against your GraphQL API." --- @@ -150,12 +150,12 @@ const users = await context.query.User.deleteMany({ {% related-content %} {% well heading="Context API Reference" -href="/docs/apis/context" %} +href="/docs/context/overview" %} The API for run-time functionality in your Keystone system. Use it to write business logic for access control, hooks, testing, GraphQL schema extensions, and more. {% /well %} {% well heading="DB API Reference" -href="/docs/apis/db-items" %} +href="/docs/context/db-items" %} The API for running CRUD operations against the internal GraphQL resolvers in your system. It returns internal item objects, which can be returned from GraphQL resolvers. {% /well %} {% /related-content %} diff --git a/docs/pages/docs/examples.tsx b/docs/pages/docs/examples.tsx index f465c7abc0a..deb3a998db0 100644 --- a/docs/pages/docs/examples.tsx +++ b/docs/pages/docs/examples.tsx @@ -36,17 +36,13 @@ export default function Docs() { - - Base Projects + + Standalone Examples - Simple starters to get you up and running with a local Keystone instance and understand the - basics of designing a{' '} - - schema - {' '} - . + Standalone examples demonstrate how a particular feature works or how to solve a problem + with Keystone.
    A basic Blog schema with Posts and Authors. Use this as a starting place for learning how - to use Keystone. It’s also a starter for other feature projects. + to use Keystone. A basic Task Management app, with Tasks and People who can be assigned to tasks. Great for - learning how to use Keystone. It’s also a starter for other feature projects. + learning how to use Keystone. -
    - - Feature Projects - - - - Derived from the Base Projects, these examples demonstrate a particular feature of Keystone, - and show you best practice for implementing it. - - -
    - Adds a custom logo component in the Admin UI. Builds on the Task Manager starter project. + Adds a custom logo component in the Admin UI. - Adds a custom Navigation component to the Admin UI. Builds on the Task Manager starter - project. + Adds a custom Navigation component to the Admin UI. - Adds a custom page in the Admin UI. Builds on the Task Manager starter project. + Adds a custom page in the Admin UI. Adds a custom field type based on the integer field type which - lets users rate items on a 5-star scale. Builds on the Blog starter project. + lets users rate items on a 5-star scale. Adds a custom Admin UI view to a json field which provides a - customised editing experience for users. Builds on the Task Manager starter project. + customised editing experience for users. - Demonstrates how to use default values for fields. Builds upon the Task Manager starter - project. + Demonstrates how to use default values for fields. Illustrates how to configure document fields in your Keystone - system and render their data in a frontend application. Builds on the Blog starter - project. + system and render their data in a frontend application. - Shows you how to extend the Keystone GraphQL API with custom queries and mutations. Builds - upon the Blog starter project. + Shows you how to extend the Keystone GraphQL API with custom queries and mutations. @@ -221,28 +196,54 @@ export default function Docs() { the Query API to execute queries against the schema. - Shows you how to write tests against the GraphQL API to your Keystone system. Builds on - the Authentication example project. + Shows you how to write tests against the GraphQL API to your Keystone system. - Implements virtual fields in a Keystone list. Builds on the Blog starter project. + Implements virtual fields in a Keystone list. + +
    + + + End-to-End Examples + + + + End to end examples demonstrate how a feature works or how to solve a problem with an + independent frontend application and a Keystone server. + + +
    + + Example to demonstrate customisation of Keystone's document field and document renderer.
    - - Deployment Projects + + Deployment Examples @@ -275,7 +276,7 @@ export default function Docs() { true, + isOrderable: ({ context, session, fieldKey, listKey }) => true, + access: { /* ... */ }, + hooks: { /* ... */ }, + label: '...', + ui: { + views: './path/to/viewsModule', + createView: { + fieldMode: ({ session, context }) => 'edit', + }, + itemView: { + fieldMode: ({ session, context, item }) => 'read', + }, + listView: { + fieldMode: ({ session, context }) => 'read', + }, + }, + graphql: { + cacheHint: { maxAge: 60, scope: CacheScope.Private }, + omit: ['read', 'create', 'update'], + } + }), + /* ... */ + }, + }), + /* ... */ + }, + /* ... */ +}); +``` + +## Scalar types + +- [BigInt](./bigint) +- [Calendar Day](./calendarday) +- [Checkbox](./checkbox) +- [Decimal](./decimal) +- [Float](./float) +- [Integer](./integer) +- [JSON](./json) +- [Multiselect](./multiselect) +- [Password](./password) +- [Select](./select) +- [Text](./text) +- [Timestamp](./timestamp) + +## Relationship type + +- [Relationship](./relationship) + +## Virtual type + +- [Virtual](./virtual) + +## File types + +- [File](./file) +- [Image](./image) + +## Complex types + +- [Document](./document) +- [Cloudinary Image](./cloudinaryimage) + +## Related resources + +{% related-content %} +{% well +heading="Lists API Reference" +href="/docs/config/lists" %} +The API to configure your options used with the `list()` function. +{% /well %} +{% well +heading="GraphQL API Reference" +href="/docs/graphql/overview" %} +A complete CRUD (create, read, update, delete) GraphQL API derived from the list and field names you configure in your system. +{% /well %} +{% /related-content %} diff --git a/docs/pages/docs/fields/password.md b/docs/pages/docs/fields/password.md new file mode 100644 index 00000000000..9c63184f211 --- /dev/null +++ b/docs/pages/docs/fields/password.md @@ -0,0 +1,48 @@ +--- +title: "Password" +description: "A reference of Keystone's password field type, configuration and options." +--- + +A `password` field represents an encrypted password value. + +Options: + +- `db.map`: Adds a [Prisma `@map`](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map) attribute to this field which changes the column name in the database +- `db.isNullable` (default: `validation.isRequired ? false : true`): If `false` then this field will be made non-nullable in the database and it will never be possible to set as `null`. +- `validation.isRequired` (default: `false`): If `true` then this field can never be set to `null`. + It validate this when creating and updating an item through the GraphQL API or the Admin UI. + It will also default `db.isNullable` to false. +- `validation.length.min` (default: `8`): This describes the minimum length allowed. If you attempt to submit a string shorter than this, you will get a validation error. +- `validation.length.max` (default: `undefined`): This describes the maximum length allowed. If you attempt to submit a string longer than this, you will get a validation error. +- `validation.match` (default: `undefined`): This describes a pattern that values for this field must match + - `validation.match.regex`: The regular expression + - `validation.match.explanation` (default: `${fieldLabel} must match ${validation.match.regex}`): A message shown in the Admin when a value doesn't match the regex and returned as a validation error from the GraphQL API +- `validation.rejectCommon` (default: `false`): Rejects passwords from a list of commonly used passwords. +- `bcrypt` (default: `require('bcryptjs')`): A module which implements the same interface as the [`bcryptjs`](https://www.npmjs.com/package/bcryptjs) package, such as the native [`bcrypt`](https://www.npmjs.com/package/bcrypt) package. + This module will be used for all encryption routines in the `password` field. + +```typescript +import { config, list } from '@keystone-6/core'; +import { password } from '@keystone-6/core/fields'; + +export default config({ + lists: { + SomeListName: list({ + fields: { + someFieldName: password({ + db: { map: 'password_field' }, + validation: { + length: { min: 10, max: 1000 }, + isRequired: true, + rejectCommon: true, + }, + bcrypt: require('bcrypt'), + }), + /* ... */ + }, + }), + /* ... */ + }, + /* ... */ +}); +``` diff --git a/docs/pages/docs/fields/relationship.md b/docs/pages/docs/fields/relationship.md new file mode 100644 index 00000000000..db4a485c238 --- /dev/null +++ b/docs/pages/docs/fields/relationship.md @@ -0,0 +1,67 @@ +--- +title: "Relationship" +description: "A reference of Keystone's relationship field type, configuration and options." +--- + +A `relationship` field represents a relationship between two lists. + +Read our [relationships guide](../guides/relationships) for details on Keystone’s relationship model and how to configure them in your project. + +- `ref` (required): A string of the form `` or `.`. +- `many` (default: `false`): Configures the cardinality of the relationship. +- `db.foreignKey`: When `true` or an object, ensures the foreign Key for two-sided relationships is stored in the table for this list (only available on single relationships, and not on both sides of a 1:1 relationship) + - `map`: Changes the column name in the database +- `ui` (default: `{ hideCreate: false, displayMode: 'select' }`): Configures the display mode of the field in the Admin UI. + - `hideCreate` (default: `false`). If `true`, the "Create related item" button is not shown in the item view. + - `displayMode` (default: `'select'`): Controls the mode used to display the field in the item view. The mode `'select'` displays related items in a select component, while `'cards'` displays the related items in a card layout. Each display mode supports further configuration. +- `ui.displayMode === 'select'` options: + - `labelField`: The field path from the related list to use for item labels in the select. Defaults to the `labelField` configured on the related list. +- `ui.displayMode === 'cards'` options: + - `cardFields`: A list of field paths from the related list to render in the card component. Defaults to `'id'` and the `labelField` configured on the related list. + - `linkToItem` (default `false`): If `true`, the default card component will render as a link to navigate to the related item. + - `removeMode` (default: `'disconnect'`): Controls whether the `Remove` button is present in the card. If `'disconnect'`, the button will be present. If `'none'`, the button will not be present. + - `inlineCreate` (default: `null`): If not `null`, an object of the form `{ fields: [...] }`, where `fields` is a list of field paths from the related list should be provided. An inline `Create` button will be included in the cards allowing a new related item to be created based on the configured field paths. + - `inlineEdit` (default: `null`): If not `null`, an object of the form `{ fields: [...] }`, where `fields` is a list of field paths from the related list should be provided. An `Edit` button will be included in each card, allowing the configured fields to be edited for each related item. + - `inlineConnect` (default: `false`): If `true`, an inline `Link existing item` button will be present, allowing existing items of the related list to be connected in this field. +- `ui.displayMode === 'count'` only supports `many` relationships + +```typescript +import { config, list } from '@keystone-6/core'; +import { relationship } from '@keystone-6/core/fields'; + +export default config({ + lists: { + SomeListName: list({ + fields: { + someFieldName: relationship({ + ref: '...', + many: false, + db: { + foreignKey: { + map: 'foreign_id', + }, + }, + ui: { + hideCreate: false, + displayMode: 'select', + labelField: 'name', + displayMode: 'cards', + cardFields: [...], + linkToItem: true, + removeMode: 'disconnect', + inlineCreate: { fields: [...] }, + inlineEdit: { fields: [...] }, + inlineConnect: true, + // Display mode: 'count' + // requires many: true above + displayMode: 'count', + }, + }), + /* ... */ + }, + }), + /* ... */ + }, + /* ... */ +}); +``` diff --git a/docs/pages/docs/fields/select.md b/docs/pages/docs/fields/select.md new file mode 100644 index 00000000000..89a83c581e0 --- /dev/null +++ b/docs/pages/docs/fields/select.md @@ -0,0 +1,66 @@ +--- +title: "Select" +description: "A reference of Keystone's select field type, configuration and options." +--- + +A `select` field represents the selection of one of fixed set of values. +Values can be either strings, integers, or enum values, as determined by the `type` option. +This will determine their GraphQL data type, as well as their database storage type except for `enum` on SQLite +where the GraphQL type will be an enum but it will be represented as a string in the database. + +Options: + +- `type` (default: `'string'`): Sets the type of the values of this field. + Must be one of `['string', 'enum', 'integer']`. +- `options`: An array of `{ label, value }`. + `label` is a string to be displayed in the Admin UI. + `value` is either a `string` (for `{ type: 'string' }` or `{ type: 'enum' }`), or a `number` (for `{ type: 'integer' }`). + The `value` will be used in the GraphQL API and stored in the database. +- `defaultValue` (default: `undefined`): This value will be used for the field when creating items if no explicit value is set. +- `db.map`: Adds a [Prisma `@map`](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map) attribute to this field which changes the column name in the database +- `db.isNullable` (default: `validation.isRequired ? false : true`): If `false` then this field will be made non-nullable in the database and it will never be possible to set as `null`. +- `validation.isRequired` (default: `false`): If `true` then this field can never be set to `null`. + It validate this when creating and updating an item through the GraphQL API or the Admin UI. + It will also default `db.isNullable` to false. +- `isIndexed` (default: `false`) + - If `true` then this field will be indexed by the database. + - If `'unique'` then all values of this field must be unique. +- `ui.displayMode` (default: `'select'`): Configures the display mode of the field in the Admin UI. + Can be one of `['select', 'segmented-control', 'radio']`. +- `graphql.read.isNonNull` (default: `false`): If you have no read access control and you don't intend to add any in the future, + you can set this to true and the output field will be non-nullable. This is only allowed when you have no read access control because otherwise, + when access is denied, `null` will be returned which will cause an error since the field is non-nullable and the error + will propagate up until a nullable field is found which means the entire item will be unreadable and when doing an `items` query, all the items will be unreadable. +- `graphql.create.isNonNull` (default: `false`): If you have no create access control and you want to explicitly show that this is field is non-nullable in the create input + you can set this to true and the create field will be non-nullable and have a default value at the GraphQL level. + This is only allowed when you have no create access control because otherwise, the item will always fail access control + if a user doesn't have access to create the particular field regardless of whether or not they specify the field in the create. + +```typescript +import { config, list } from '@keystone-6/core'; +import { select } from '@keystone-6/core/fields'; + +export default config({ + lists: { + SomeListName: list({ + fields: { + someFieldName: select({ + type: 'enum', + options: [ + { label: '...', value: '...' }, + /* ... */ + ], + defaultValue: '...', + db: { map: 'my_select' }, + validation: { isRequired: true, }, + isIndexed: 'unique', + ui: { displayMode: 'select' }, + }), + /* ... */ + }, + }), + /* ... */ + }, + /* ... */ +}); +``` diff --git a/docs/pages/docs/fields/text.md b/docs/pages/docs/fields/text.md new file mode 100644 index 00000000000..dcd92e1b9ac --- /dev/null +++ b/docs/pages/docs/fields/text.md @@ -0,0 +1,66 @@ +--- +title: "Text" +description: "A reference of Keystone's text field type, configuration and options." +--- + +A `text` field represents a string value. + +Options: + +- `defaultValue` (default: `db.isNullable === true ? undefined : ''`): This value will be used for the field when creating items if no explicit value is set. +- `db.map`: Adds a [Prisma `@map`](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map) attribute to this field which changes the column name in the database +- `db.isNullable` (default: `false`\*): If `true` then this field will be made nullable in the database and it will be possible to set as `null`. +- `db.nativeType`: Changes the [Prisma Native database type attibute](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string) from the default Prisma type for your database. + For more information see the [Choosing a Database Guide](../guides/choosing-a-database). +- `validation.isRequired` (default: `false`\*\*): If `true` then this field can never be set to `null` or an empty string. + Unlike `db.isNullable`, this will require that a value with at least 1 character is provided in the Admin UI. + It will also validate this when creating and updating an item through the GraphQL API but it will not enforce it at the database level. +- `validation.length.min` (default: `0`): This describes the minimum number allowed. If you attempt to submit a string shorter than this, you will get a validation error. +- `validation.length.max` (default: `undefined`): This describes the maximum length allowed. If you attempt to submit a string longer than this, you will get a validation error. +- `validation.match` (default: `undefined`): This describes a pattern that values for this field must match + - `validation.match.regex`: The regular expression + - `validation.match.explanation` (default: `${fieldLabel} must match ${validation.match.regex}`): A message shown in the Admin when a value doesn't match the regex and returned as a validation error from the GraphQL API +- `isIndexed` (default: `false`) + - If `true` then this field will be indexed by the database. + - If `'unique'` then all values of this field must be unique. +- `ui` (default: `{ displayMode: 'input' }`): Configures the display mode of the field in the Admin UI. + Can be one of `['input', 'textarea']`. +- `graphql.read.isNonNull` (default: `false`): If you have no read access control and you don't intend to add any in the future, + you can set this to true and the output field will be non-nullable. This is only allowed when you have no read access control because otherwise, + when access is denied, `null` will be returned which will cause an error since the field is non-nullable and the error + will propagate up until a nullable field is found which means the entire item will be unreadable and when doing an `items` query, all the items will be unreadable. +- `graphql.create.isNonNull` (default: `false`): If you have no create access control and you want to explicitly show that this is field is non-nullable in the create input + you can set this to true and the create field will be non-nullable and have a default value at the GraphQL level. + This is only allowed when you have no create access control because otherwise, the item will always fail access control + if a user doesn't have access to create the particular field regardless of whether or not they specify the field in the create. + +{% hint kind="tip" %} +**\*Warning** Unlike with other `keystone` fields, `db.isNullable` is defaulted to `false` for the text field. +This is primarily in the interest of not having to make assumptions about how a `null` value can be represented in a text field in the Admin-UI in the default case. +These differences, and the rationale for them, are examined in detail [on GitHub](https://github.com/keystonejs/keystone/discussions/7158). +You can opt into this behaviour by explicitly setting `isNullable: true`. +{% /hint %} + +```typescript +import { config, list } from '@keystone-6/core'; +import { text } from '@keystone-6/core/fields'; + +export default config({ + lists: { + SomeListName: list({ + fields: { + someFieldName: text({ + defaultValue: '...', + db: { map: 'my_text', nativeType: 'VarChar(40)' }, + validation: { isRequired: true }, + isIndexed: 'unique', + ui: { displayMode: 'textarea' }, + }), + /* ... */ + }, + }), + /* ... */ + }, + /* ... */ +}); +``` diff --git a/docs/pages/docs/fields/timestamp.md b/docs/pages/docs/fields/timestamp.md new file mode 100644 index 00000000000..877f26c0c0a --- /dev/null +++ b/docs/pages/docs/fields/timestamp.md @@ -0,0 +1,53 @@ +--- +title: "Timestamp" +description: "A reference of Keystone's timestamp field type, configuration and options." +--- + +A `timestamp` field represents a date time value in ISO8601 format. + +Options: + +- `defaultValue` (default: `undefined`): Can be either a string value with a date time string in ISO8601 format or `{ kind: 'now' }`. + This value will be used for the field when creating items if no explicit value is set. +- `db.map`: Adds a [Prisma `@map`](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#map) attribute to this field which changes the column name in the database +- `db.isNullable` (default: `validation.isRequired ? false : true`): If `false` then this field will be made non-nullable in the database and it will never be possible to set as `null`. +- `validation.isRequired` (default: `false`): If `true` then this field can never be set to `null`. + It validate this when creating and updating an item through the GraphQL API or the Admin UI. + It will also default `db.isNullable` to false. +- `db.updatedAt` (default: `false`) If `true` then this field will add the `@updatedAt` attribute to this field in the Prisma schema. + This will update this field to the current time whenever an item is created/updated with the GraphQL API or any other usage of the Prisma Client if this field is not explicitly set in the request. + Note this happens at the Prisma Client level, not at the database so if you update an item in your database directly, fields with `db.updatedAt: true` will not automatically update. +- `isIndexed` (default: `false`) + - If `true` then this field will be indexed by the database. + - If `'unique'` then all values of this field must be unique. +- `graphql.read.isNonNull` (default: `false`): If you have no read access control and you don't intend to add any in the future, + you can set this to true and the output field will be non-nullable. This is only allowed when you have no read access control because otherwise, + when access is denied, `null` will be returned which will cause an error since the field is non-nullable and the error + will propagate up until a nullable field is found which means the entire item will be unreadable and when doing an `items` query, all the items will be unreadable. +- `graphql.create.isNonNull` (default: `false`): If you have no create access control and you want to explicitly show that this is field is non-nullable in the create input + you can set this to true and the create field will be non-nullable and have a default value at the GraphQL level. + This is only allowed when you have no create access control because otherwise, the item will always fail access control + if a user doesn't have access to create the particular field regardless of whether or not they specify the field in the create. + +```typescript +import { config, list } from '@keystone-6/core'; +import { timestamp } from '@keystone-6/core/fields'; + +export default config({ + lists: { + SomeListName: list({ + fields: { + someFieldName: timestamp({ + defaultValue: '1970-01-01T00:00:00.000Z', + db: { map: 'my_timestamp' }, + validation: { isRequired: true }, + isIndexed: 'unique', + }), + /* ... */ + }, + }), + /* ... */ + }, + /* ... */ +}); +``` diff --git a/docs/pages/docs/fields/virtual.md b/docs/pages/docs/fields/virtual.md new file mode 100644 index 00000000000..5b86d7720bf --- /dev/null +++ b/docs/pages/docs/fields/virtual.md @@ -0,0 +1,48 @@ +--- +title: "Virtual" +description: "A reference of Keystone's virtual field type, configuration and options." +--- + +A `virtual` field represents a value which is computed at read time, rather than stored in the database. +See the [virtual fields guide](../guides/virtual-fields) for details on how to use virtual fields. + +Options: + +- `field` (required): The GraphQL field that defines the type, resolver and arguments. +- `ui.query` (default: `''` ): + Defines what the Admin UI should fetch from this field, it's interpolated into a query like this: + ```graphql + query { + item(where: { id: "..." }) { + field${ui.query} + } + } + ``` + This is only needed when you your field returns a GraphQL type other than a scalar(String and etc.) + or an enum or you need to provide arguments to the field. + +```typescript +import { config, createSchema, graphql, list } from '@keystone-6/core'; +import { virtual } from '@keystone-6/core/fields'; + +export default config({ + lists: { + SomeListName: list({ + fields: { + someFieldName: virtual({ + field: graphql.field({ + type: graphql.String, + args: { something: graphql.arg({ type: graphql.Int }) }, + resolve(item, args, context, info) { + + } + }) + }), + /* ... */ + }, + }), + /* ... */ + }, + /* ... */ +}); +``` diff --git a/docs/pages/docs/walkthroughs/getting-started-with-create-keystone-app.md b/docs/pages/docs/getting-started.md similarity index 77% rename from docs/pages/docs/walkthroughs/getting-started-with-create-keystone-app.md rename to docs/pages/docs/getting-started.md index 5d61e84d557..d0770020092 100644 --- a/docs/pages/docs/walkthroughs/getting-started-with-create-keystone-app.md +++ b/docs/pages/docs/getting-started.md @@ -3,10 +3,10 @@ title: "Getting started" description: "Learn how to get your first Keystone project up and running using the `create-keystone-app` Command Line Interface." --- -![A terminal with the output of create-keystone-app](/assets/walkthroughs/getting-started/cover.svg) +![A terminal with the output of create-keystone-app](/assets/getting-started/cover.svg) [`create-keystone-app`](https://github.com/keystonejs/create-keystone-app) is a CLI app that makes it easier for you initiate a Keystone project. -It generates some files for you and installs all the dependencies you need to run the Admin UI and start using the [GraphQL API](/docs/apis/graphql). +It generates some files for you and installs all the dependencies you need to run the Admin UI and start using the [GraphQL API](/docs/graphql/overview). ## Quick Start @@ -61,7 +61,7 @@ npx create-keystone-app The CLI will ask you to name your app. Once named, it will create a new SQLite database. {% hint kind="warn" %} -You can switch to another database such as PostgreSQL once your project is created, check out the docs on [Database Setup](https://keystonejs.com/docs/apis/config#db). +You can switch to another database such as PostgreSQL once your project is created, check out the docs on [Database Setup](https://keystonejs.com/docs/config/config#db). {% /hint %} ## Opening your shiny new Admin UI @@ -73,18 +73,18 @@ cd my-app yarn dev ``` -This will generate the Admin UI pages via [Next.js](https://nextjs.org/) on [http://localhost:3000](http://localhost:3000). When you visit the Admin UI for the first time you will be presented with a handy screen that asks you to create a user: +This will generate the Admin UI pages via [Next.js](https://nextjs.org/) on . When you visit the Admin UI for the first time you will be presented with a handy screen that asks you to create a user: -![The welcome screen giving you the ability the create a new user to log into the AdminUI](/assets/walkthroughs/getting-started/welcome-screen.png) +![The welcome screen giving you the ability the create a new user to log into the AdminUI](/assets/getting-started/welcome-screen.png) -Go ahead and create your first user. The email address and password will be used to login to Keystone’s Admin UI. Once you've created your user, you’ll be logged in to a new Keystone Admin UI that comes with two [lists](/docs/apis/config#lists). -From here you can explore and interact with the data in your system, and understand how Keystone’s schema relates to your GraphQL API which you can explore at [http://localhost:3000/api/graphql](http://localhost:3000/api/graphql). +Go ahead and create your first user. The email address and password will be used to login to Keystone’s Admin UI. Once you've created your user, you’ll be logged in to a new Keystone Admin UI that comes with two [lists](/docs/config/config#lists). +From here you can explore and interact with the data in your system, and understand how Keystone’s schema relates to your GraphQL API which you can explore at . -![The AdminUI of Keystone showing the two lists: User and Posts](/assets/walkthroughs/getting-started/adminui.png) +![The AdminUI of Keystone showing the two lists: User and Posts](/assets/getting-started/adminui.png) ## Output -Keytone creates the following files in your newly generated folder. The most important ones are [`keystone.ts`](/docs/apis/config) and [`schema.ts`](/docs/apis/Schema). +Keytone creates the following files in your newly generated folder. The most important ones are [`keystone.ts`](/docs/config/config) and [`schema.ts`](/docs/config/lists). ```sh . @@ -104,20 +104,20 @@ Keytone creates the following files in your newly generated folder. The most imp `package.json` includes the following npm scripts you can run locally: -- [`dev`](/docs/guides/cli#dev) runs Keystone in **development** mode at [http://localhost:3000](http://localhost:3000). +- [`dev`](/docs/guides/cli#dev) runs Keystone in **development** mode at . - [`start`](/docs/guides/cli#start) runs Keystone in **production** mode. - [`build`](/docs/guides/cli#build) will build the project and is required to be run before `start`. - [`postinstall`](/docs/guides/cli#postinstall) ensures files that Keystone generates exist and are kept up to date. {% hint kind="tip" %} -Read more about the CLI in our [command line guides](/guides/cli). +Read more about the CLI in our [command line guides](/docs/guides/cli). {% /hint %} ## Where to next? -- Customise Keystone with the [System Configuration API](/apis/config). -- Add fields and relationships using [Lists API](/apis/schema). -- Use a different database with the [Config API](/docs/apis/config#db). +- Customise Keystone with the [System Configuration API](./config/config). +- Add fields and relationships using [Lists API](/docs/config/lists). +- Use a different database with the [Config API](/docs/config/config#db). ## Related resources @@ -129,17 +129,17 @@ Keystone’s CLI helps you develop, build, and deploy projects. This guide expla {% /well %} {% well heading="Lists API Reference" -href="/docs/apis/schema" %} +href="/docs/config/lists" %} The API to configure your options used with the `list()` function. {% /well %} {% well heading="Config API Reference" -href="/docs/apis/config" %} +href="/docs/config/config" %} The API to configure all the parts parts of your Keystone system. {% /well %} {% well heading="DB API Reference" -href="/docs/apis/config#db" %} +href="/docs/config/config#db" %} Configure Keystone to use another database to store data in your system. {% /well %} {% /related-content %} diff --git a/docs/pages/docs/apis/filters.md b/docs/pages/docs/graphql/filters.md similarity index 88% rename from docs/pages/docs/apis/filters.md rename to docs/pages/docs/graphql/filters.md index 738ed31f71a..b3ada4b793c 100644 --- a/docs/pages/docs/apis/filters.md +++ b/docs/pages/docs/graphql/filters.md @@ -1,5 +1,5 @@ --- -title: "Query Filter API" +title: "GraphQL Query Filters" description: "A reference list of every filters available for every Keystone field type. Keystone filters are typically named after the field they are filtering." --- @@ -7,7 +7,7 @@ description: "A reference list of every filters available for every Keystone fie We recently improved this API so it’s easier to program and reason about. If you were using it prior to August 17th 2021, [read this guide](/updates/new-graphql-api) for info on how to upgrade. {% /hint %} -Each field type provides its own set of filters which can be used with [queries](./graphql#all-users). +Each field type provides its own set of filters which can be used with [queries](./overview#users). This page lists all the filters available for each field type. For more details on how to use filters in queries please consult to the [GraphQL Queries - Filters](../guides/filters) guide. @@ -74,29 +74,29 @@ The `json` field type does not support filters. - If the `type` is `string`(the default), the same filters as `text` will be available. - If the `type` is `integer`, the same filters as `integer` will be available. - If the `type` is `enum`, the following filters will be available: - | **Filter name** | **Type** | **Description** | - | --------------- | ---------- | ------------------- | - | `equals` | `ListKeyFieldKeyType` | Equals | - | `in` | `[ListKeyFieldKeyType!]` | Is in the array | - | `notIn` | `[ListKeyFieldKeyType!]` | Is not in the array | - | `not` | `ListKeyFieldKeyTypeNullableFilter` | Does not match the inner filter | + \| **Filter name** \| **Type** \| **Description** \| + \| --------------- \| ---------- \| ------------------- \| + \| `equals` \| `ListKeyFieldKeyType` | Equals | + \| `in` \| `[ListKeyFieldKeyType!]` | Is in the array | + \| `notIn` \| `[ListKeyFieldKeyType!]` | Is not in the array | + \| `not` \| `ListKeyFieldKeyTypeNullableFilter` | Does not match the inner filter | ### text | **Filter name** | **Type** | **Description** | **Notes** | | --------------- | ---------------------------------------- | ----------------------------------------------------- | --------- | -| `equals` | `String` | Equals | -| `lt` | `String` | Less than | -| `lte` | `String` | Less than or equal | -| `gt` | `String` | Greater than | -| `gte` | `String` | Greater than or equal | +| `equals` | `String` | Equals | | +| `lt` | `String` | Less than | | +| `lte` | `String` | Less than or equal | | +| `gt` | `String` | Greater than | | +| `gte` | `String` | Greater than or equal | | | `contains` | `String` | Contains | [1] | | `startsWith` | `String` | Starts with | [1] | | `endsWith` | `String` | Ends with | [1] | -| `in` | `[String!]` | Is in the array | -| `notIn` | `[String!]` | Is not in the array | +| `in` | `[String!]` | Is in the array | | +| `notIn` | `[String!]` | Is not in the array | | | `mode` | `QueryMode` (`default` or `insensitive`) | Whether the filters should be case insensitive or not | [2] | -| `not` | `NestedStringNullableFilter` | Does not match the inner filter | +| `not` | `NestedStringNullableFilter` | Does not match the inner filter | | #### Notes diff --git a/docs/pages/docs/apis/graphql.md b/docs/pages/docs/graphql/overview.md similarity index 94% rename from docs/pages/docs/apis/graphql.md rename to docs/pages/docs/graphql/overview.md index 9b63bad91a5..d576c456a72 100644 --- a/docs/pages/docs/apis/graphql.md +++ b/docs/pages/docs/graphql/overview.md @@ -1,13 +1,13 @@ --- -title: "GraphQL API" +title: "GraphQL Overview" description: "Reference docs for Keystone’s CRUD (create, read, update, delete) GraphQL API. Based on the schema definitions outlined in your system config." --- {% hint kind="warn" %} -We recently improved this API so it’s easier to program and reason about. If you were using it prior to August 17th 2021, [read this guide](/updates/new-graphql-api) for info on how to upgrade. +We recently improved this API so it's easier to program and reason about. If you were using it prior to August 17th 2021, [read this guide](/updates/new-graphql-api) for info on how to upgrade. {% /hint %} -Keystone generates a CRUD (create, read, update, delete) GraphQL API based on the [schema](./schema) definition provided in the system [config](./config). +Keystone generates a CRUD (create, read, update, delete) GraphQL API based on the [schema](../config/lists) definition provided in the system [config](../config/config). ## Using the API @@ -26,7 +26,7 @@ const client = new ApolloClient({ }); ``` -If you don't like the default path you can control where the GraphQL API and playground are published by setting `config.graphql.path` in the [Keystone configuration](https://keystonejs.com/docs/apis/config#graphql). +If you don't like the default path you can control where the GraphQL API and playground are published by setting `config.graphql.path` in the [Keystone configuration](https://keystonejs.com/docs/config/config#graphql). For security through obscurity, the playground and [introspection](https://graphql.org/learn/introspection/) is disabled when running Keystone with `NODE_ENV=production`. You can modify this behaviour using the `config.graphql.playground` and `config.graphql.apolloConfig` options. @@ -447,10 +447,10 @@ These error codes and messages can be used to provide useful feedback to users, The following error codes can be returned from the Keystone GraphQL API. - `KS_USER_INPUT_ERROR`: The input to the operation is syntactically correct GraphQL, but the values provided are invalid. E.g, an `orderBy` input without any keys. -- `KS_ACCESS_DENIED`: The operation is not allowed because either an [Access Control](./access-control) rule prevents it, or the item does not exist. -- `KS_FILTER_DENIED`: The filter or ordering operation is not allowed because of [`isFilterable` or `isOrderable`](fields#common-configuration) rules. +- `KS_ACCESS_DENIED`: The operation is not allowed because either an [Access Control](../config/access-control) rule prevents it, or the item does not exist. +- `KS_FILTER_DENIED`: The filter or ordering operation is not allowed because of [`isFilterable` or `isOrderable`](../fields/overview#common-configuration) rules. - `KS_VALIDATION_FAILURE`: The operation is not allowed because of a [validation](../guides/hooks#validating-inputs) rule. -- `KS_LIMITS_EXCEEDED`: The user has exceeded their [query limits](./schema#graphql). +- `KS_LIMITS_EXCEEDED`: The user has exceeded their [query limits](../config/lists#graphql). - `KS_EXTENSION_ERROR`: An error was thrown while excuting a system extension function, such as a hook or an access control function. - `KS_ACCESS_RETURN_ERROR`: An invalid value was returned from an access control function. - `KS_RESOLVER_ERROR`: An error occured while resolving the input for a field. @@ -464,12 +464,12 @@ The following error codes can be returned from the Keystone GraphQL API. {% related-content %} {% well heading="Lists API Reference" -href="/docs/apis/schema" %} +href="/docs/config/lists" %} The API to configure your options used with the `list()` function. {% /well %} {% well heading="Config API Reference" -href="/docs/apis/config" %} +href="/docs/config/config" %} The API to configure all the parts parts of your Keystone system. {% /well %} {% /related-content %} diff --git a/docs/pages/docs/guides/auth-and-access-control.md b/docs/pages/docs/guides/auth-and-access-control.md index 5e741acc143..6080c416fd0 100644 --- a/docs/pages/docs/guides/auth-and-access-control.md +++ b/docs/pages/docs/guides/auth-and-access-control.md @@ -5,10 +5,10 @@ description: "Learn how to use Keystone's built-in Authentication and Access Con Keystone comes with several features that work together to control access to the Admin UI and GraphQL API: -- **Session Management** – a set of APIs for starting and ending user sessions, as well as initialising the session data for each request ([docs](../apis/session)) -- **The `auth` package** – an opinionated implementation of authentication features for Keystone apps ([docs](../apis/auth)) -- **Access Control** – a powerful framework for restricting access to specific lists, operations, and fields ([docs](../apis/access-control)) -- **Dynamic UI Config and Field Modes** – options for the Admin UI that work similarly to Access Control, and let you dyamically configure the Admin UI based on user permissions ([docs](../apis/schema#ui)) +- **Session Management** – a set of APIs for starting and ending user sessions, as well as initialising the session data for each request ([docs](../config/session)) +- **The `auth` package** – an opinionated implementation of authentication features for Keystone apps ([docs](../config/auth)) +- **Access Control** – a powerful framework for restricting access to specific lists, operations, and fields ([docs](../config/access-control)) +- **Dynamic UI Config and Field Modes** – options for the Admin UI that work similarly to Access Control, and let you dyamically configure the Admin UI based on user permissions ([docs](../config/lists#ui)) Session Management and Auth are extremely flexible in Keystone, and it's possible to replace the default implementations we provide with your own (or integrate an entirely separate auth system), but in this guide we'll focus on how all these features are designed to work together. @@ -38,7 +38,7 @@ const Person = list({ ``` {% hint kind="tip" %} -Read more about creating lists in the [schema](../apis/schema) and [fields](../apis/schema) API Docs. +Read more about creating lists in the [schema](../config/lists) and [fields](../fields/overview) API Docs. {% /hint %} ### Configure authentication @@ -58,7 +58,7 @@ const { withAuth } = createAuth({ The `createAuth` function returns another function called `withAuth` that will automatically extend Keystone's config to set up everything we need. Behind the scenes, the `auth` package is just using lower-level Keystone APIs to do everything, which means if you want to do something differently, you can fork our implementation of `auth` and build your own (this is true for session management as well) {% hint kind="tip" %} -Read more about `createAuth` in the [Auth API Docs](../apis/auth). +Read more about `createAuth` in the [Auth API Docs](../config/auth). {% /hint %} ### Configure sessions @@ -74,7 +74,7 @@ const session = statelessSessions({ Keystone also comes with a Redis session adapter, which uses a cookie to store a session ID that is looked up in a Redis database; or you can use your own session adapter (for example, if you are using OAuth sessions). {% hint kind="tip" %} -Read more about [Session Stores in the Session API Docs](../apis/session#session-stores). +Read more about [Session Stores in the Session API Docs](../config/session#session-stores). {% /hint %} ### Putting it all together @@ -484,7 +484,7 @@ You can provide field-level rules for: If you want to completely block users from setting a field's value, make sure you set both the `create` and `update` rules. {% /hint %} -For more information about the arguments provided to field rules, see the [Access Control API Docs](../apis/access-control#field-access-control) +For more information about the arguments provided to field rules, see the [Access Control API Docs](../config/access-control#field-access-control) ### People Example @@ -558,12 +558,12 @@ const Person = list({ {% related-content %} {% well heading="Authentication" -href="../apis/auth" %} +href="../config/auth" %} Documentation for the Auth Package API {% /well %} {% well heading="Access Control" -href="../apis/access-control" %} +href="../config/access-control" %} Documentation for the Access Control API {% /well %} {% /related-content %} diff --git a/docs/pages/docs/guides/choosing-a-database.md b/docs/pages/docs/guides/choosing-a-database.md index 89bdf3e4db4..880396e8c7f 100644 --- a/docs/pages/docs/guides/choosing-a-database.md +++ b/docs/pages/docs/guides/choosing-a-database.md @@ -3,7 +3,7 @@ title: "Choosing the right Database" description: "How to choose the right database for your Keystone project" --- -Keystone supports [Postgres](https://www.postgresql.org), [MySQL](https://www.mysql.com) and [SQLite](https://www.sqlite.org/index.html) database [providers](../apis/config#db). This guide highlights the differences between these providers to help you choose the right one for your project. +Keystone supports [Postgres](https://www.postgresql.org), [MySQL](https://www.mysql.com) and [SQLite](https://www.sqlite.org/index.html) database [providers](../config/config#db). This guide highlights the differences between these providers to help you choose the right one for your project. {% hint kind="tip" %} **Note:** SQLite is not recommended in production except for scenarios like the [Embedded Keystone](../walkthroughs/embedded-mode-with-sqlite-nextjs) example @@ -26,11 +26,11 @@ Prisma has different default types for each database used, for example, the Keys for Postgres, Prisma uses the `text` column type, and for MySQL, it uses the `varchar(191)` column type. For more details on the `field` type differences see [Primsa Schema Reference](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#model-field-scalar-types). -The Keystone `text` field supports the `db.nativeType` option, allowing you to override this - [Fields API](../apis/fields). Over time this option will be added to other field types. +The Keystone `text` field supports the `db.nativeType` option, allowing you to override this - [Fields API](../fields/overview). Over time this option will be added to other field types. ## Auto Increment Integer Fields -When using an [Integer field](../apis/fields#integer) with the `defaultValue: { kind: 'autoincrement' }` MySQL also requires this field to be indexed using the `isIndexed: true` or `isIndexed: 'unique'`. +When using an [Integer field](../fields/integer) with the `defaultValue: { kind: 'autoincrement' }` MySQL also requires this field to be indexed using the `isIndexed: true` or `isIndexed: 'unique'`. ## Supported Database Versions @@ -41,12 +41,12 @@ For supported database provider versions for Postgres and MySQL see [Prisma Supp {% related-content %} {% well heading="Fields API" -href="../apis/fields" %} +href="../fields/overview" %} Documentation for the Fields API {% /well %} {% well heading="DB Config API" -href="../apis/config#db" %} +href="../config/config#db" %} Documentation for the DB Config API {% /well %} {% /related-content %} diff --git a/docs/pages/docs/guides/cli.md b/docs/pages/docs/guides/cli.md index f8d005e00bb..c4498968891 100644 --- a/docs/pages/docs/guides/cli.md +++ b/docs/pages/docs/guides/cli.md @@ -21,7 +21,7 @@ Commands ``` {% hint kind="tip" %} -All the commands expect to find a module called `keystone.js` (or `.ts`) with a default export that returns a Keystone System `config()` from `@keystone-6/core`. See [System Configuration](../apis/config) for details. +All the commands expect to find a module called `keystone.js` (or `.ts`) with a default export that returns a Keystone System `config()` from `@keystone-6/core`. See [System Configuration](../config/config) for details. {% /hint %} ## Setting up package.json @@ -196,7 +196,7 @@ yarn keystone start - These examples use `yarn` as the package manager, you can use others like `npm` or `pnpm` if you prefer. - The commands above are included in the `package.json` reference at the top of this page. We recommend using package scripts so your build and start commands are centralised in source control. -- If you promote your build through separate environments in a pipeline (e.g testing → staging → production) you should run migrations during the **promote** step and **not** as part of the build script. +- If you promote your build through separate environments in a pipeline (e.g testing → staging → production) you should run migrations during the **promote** step and **not** as part of the build script. - It is important you do **not run migrations against your production database from staging builds**. If you have staging or preview environments set up in production, make sure they are not pointed to your production database. ## Related resources @@ -204,7 +204,7 @@ yarn keystone start {% related-content %} {% well heading="Getting Started with create-keystone-app" -href="/docs/walkthroughs/getting-started-with-create-keystone-app" %} +href="/docs/getting-started" %} How to use Keystone's CLI app to standup a new local project with an Admin UI & the GraphQL Playground. {% /well %} {% /related-content %} diff --git a/docs/pages/docs/guides/custom-fields.md b/docs/pages/docs/guides/custom-fields.md index e19778ce7ae..831443cc6b2 100644 --- a/docs/pages/docs/guides/custom-fields.md +++ b/docs/pages/docs/guides/custom-fields.md @@ -3,7 +3,7 @@ title: "Custom Fields" description: "Learn how to expand Keystone with your own custom fields. Guidance on backend setup, and frontend implementation in Keystone‘s Admin UI." --- -Keystone provides a collection of [field types](../apis/fields) which you can use to build your system. +Keystone provides a collection of [field types](../fields/overview) which you can use to build your system. If you need a field type which isn't provided, or you need a specialised version of an existing field type, you can define your own custom field type. There are two parts to a field type: diff --git a/docs/pages/docs/guides/document-field-demo.tsx b/docs/pages/docs/guides/document-field-demo.tsx index 5e1102568af..fa83955a021 100644 --- a/docs/pages/docs/guides/document-field-demo.tsx +++ b/docs/pages/docs/guides/document-field-demo.tsx @@ -41,7 +41,7 @@ export default function DocumentFieldDemo() {

    {title}

    The{' '} - + document {' '} field type is a highly customisable rich text editor that lets content creators quickly diff --git a/docs/pages/docs/guides/document-fields.md b/docs/pages/docs/guides/document-fields.md index e5bf62032df..3f934c74377 100644 --- a/docs/pages/docs/guides/document-fields.md +++ b/docs/pages/docs/guides/document-fields.md @@ -3,7 +3,7 @@ title: "How To Use Document Fields" description: "Learn how to configure Keystone’s highly customizable Rich Text editor. The Document field is built with Slate and stores your content as JSON-structured data." --- -The [`document`](../apis/fields#document) field type is a highly customizable rich text editor that lets content creators quickly and easily edit content in your system. +The [`document`](../fields/document) field type is a highly customizable rich text editor that lets content creators quickly and easily edit content in your system. It's built with [Slate](https://docs.slatejs.org/), stores your content as JSON-structured data, and lets you do things like: @@ -201,7 +201,7 @@ You can then select an item from the list specified by `listKey` from the inline ![The Admin UI showing the select field used to choose a related item](/assets/guides/document-fields/inline-relationship-select.png) {% hint kind="tip" %} -**Tip**: The select component will use the [`ui.labelField`](../apis/schema#ui) of the related list in its options list. +**Tip**: The select component will use the [`ui.labelField`](../config/lists#ui) of the related list in its options list. Make sure you have this value configured to make finding related items easier for your users. {% /hint %} diff --git a/docs/pages/docs/guides/filters.md b/docs/pages/docs/guides/filters.md index e12f6145387..bc9fd6997b5 100644 --- a/docs/pages/docs/guides/filters.md +++ b/docs/pages/docs/guides/filters.md @@ -75,7 +75,7 @@ Different field types support different filters. The field `finishBy: timestamp( } ``` -For a full list of the different filters provided by each field type, please check the [Query Filter API](../apis/filters). +For a full list of the different filters provided by each field type, please check the [Query Filter API](../graphql/filters). For more complex queries, you can combine multiple filters, and only those items which match all conditions will be returned. @@ -340,7 +340,7 @@ that should be {% related-content %} {% well heading="Query Filters API Reference" -href="/docs/apis/filters" %} +href="/docs/graphql/filters" %} The complete list of filters available to Keystone field types. {% /well %} {% /related-content %} diff --git a/docs/pages/docs/guides/hooks.md b/docs/pages/docs/guides/hooks.md index b126e63ffd8..30197c97140 100644 --- a/docs/pages/docs/guides/hooks.md +++ b/docs/pages/docs/guides/hooks.md @@ -7,11 +7,11 @@ Keystone provides a powerful CRUD GraphQL API which lets you perform basic opera As your system evolves you'll find that you need to include business logic alongside these operations. In this guide we'll show you how to use `hooks` to enhance the core operations in different ways. -For full details of the function signatures, please check out the [Hooks API](../apis/hooks). +For full details of the function signatures, please check out the [Hooks API](../config/hooks). ## What is a hook? -A hook is a function you define as part of your [schema configuration](../apis/schema) which is executed when a GraphQL operation is performed. +A hook is a function you define as part of your [schema configuration](../config/lists) which is executed when a GraphQL operation is performed. Let's look at a basic example to log a message to the console whenever a new user is created. ```typescript @@ -94,7 +94,7 @@ If you just want to see what the original input was, before the field type resol If you're performing an update operation, you might also want to access the current value of the item stored in the database. This is available as the `item` argument. -Finally, all hooks are provided with a `context` argument, which gives you access to the full [context API](../apis/context). +Finally, all hooks are provided with a `context` argument, which gives you access to the full [context API](../context/overview). ## Validating inputs @@ -139,7 +139,7 @@ Keystone will abort the operation and convert these error messages into GraphQL The `validateInput` hook also receives the `operation`, `inputData`, `item` and `context` arguments if you want to perform more advanced checks. {% hint kind="warn" %} -Don't confuse data **validation** with **access control**. If you want to check whether a user is **allowed** to do something, you should set up [access control rules](./access-control). +Don't confuse data **validation** with **access control**. If you want to check whether a user is **allowed** to do something, you should set up [access control rules](../config/access-control). {% /hint %} ## Triggering side-effects @@ -218,12 +218,12 @@ export default config({ }); ``` -See the [Hooks API](../apis/hooks) for the details of all the arguments available for all the different hook functions. +See the [Hooks API](../config/hooks) for the details of all the arguments available for all the different hook functions. ## Related resources {% related-content %} -{% well heading="Hooks API Reference" href="/docs/apis/hooks" %} +{% well heading="Hooks API Reference" href="/docs/config/hooks" %} The complete reference for executing code at different stages of the mutation lifecycle {% /well %} {% /related-content %} diff --git a/docs/pages/docs/guides/images-and-files.md b/docs/pages/docs/guides/images-and-files.md index 748e557b593..2376ebfdd93 100644 --- a/docs/pages/docs/guides/images-and-files.md +++ b/docs/pages/docs/guides/images-and-files.md @@ -3,11 +3,11 @@ title: "Images and Files" description: "Learn how to add Images and Files to your project using Keystone’s Storage configuration" --- -Keystone [fields](../apis/fields) include the `image` and `file` types. You can use them to reference and (if required) serve images and/or files from Keystone. This guide will show you how to configure images and files in your Keystone system so you can store assets either locally or [Amazon S3 storage](https://aws.amazon.com/s3/). +Keystone [fields](../fields/overview) include the `image` and `file` types. You can use them to reference and (if required) serve images and/or files from Keystone. This guide will show you how to configure images and files in your Keystone system so you can store assets either locally or [Amazon S3 storage](https://aws.amazon.com/s3/). ## How asset storage works in Keystone -Keystone manages file and image assets through a `storage` object you define in Keystone’s [configuration file](/docs/apis/config). Any number of stores can be set up within the `storage` object, and you can mix and match between `local` and `s3` (by [Amazon](https://aws.amazon.com/s3/)) depending on your use case. +Keystone manages file and image assets through a `storage` object you define in Keystone’s [configuration file](/docs/config/config). Any number of stores can be set up within the `storage` object, and you can mix and match between `local` and `s3` (by [Amazon](https://aws.amazon.com/s3/)) depending on your use case. The `storage` object defines how and where the assets are stored and accessed by both Keystone and the client frontend. This object defines: @@ -48,7 +48,7 @@ dotenv.config(); We can then add an `s3` `storage` object, the object below is called `my_s3_files` and this is the name that we will use in our `field` config later. This can be called any name that makes sense to your use case. -In the [config](../apis/config) object in your `keystone.ts` file... +In the [config](../config/config) object in your `keystone.ts` file... ```typescript /** config */ @@ -191,9 +191,9 @@ You can define as many stores as required for your use case ## Using Images and Files in Lists -Once you have your `storage` configuration in Keystone you can then use the `image` and `file` [field types](../apis/fields). +Once you have your `storage` configuration in Keystone you can then use the `image` and `file` [field types](../fields/overview). -Within an existing [list](../apis/schema) use the `image` of `file` field as follows: +Within an existing [list](../config/lists) use the `image` of `file` field as follows: ```typescript lists: { @@ -255,19 +255,19 @@ This means that for images the extension can be trusted, but for files, it can n ## Related Resources {% related-content %} -{% well heading="Config API Reference" href="/docs/apis/config" %} +{% well heading="Config API Reference" href="/docs/config/config" %} The complete reference for the base keystone configuration {% /well %} -{% well heading="Fields API Reference" href="/docs/apis/fields" %} +{% well heading="Fields API Reference" href="/docs/fields/overview" %} The complete reference for Field configuration {% /well %} -{% well heading="Relationship Guide" href="/docs/apis/fields" %} +{% well heading="Relationship Guide" href="/docs/fields/relationship" %} Learn how to reason about and configure relationships in Keystone so you can bring value to your project through structured content. {% /well %} -{% well heading="Example Project: S3 Assets" href="https://github.com/keystonejs/keystone/tree/main/examples/assets-s3" %} +{% well heading="Example Project: S3 Assets" href="" %} A full keystone project illustrating how to configure `storage` using `kind: 's3'` and then uses both an `image` and `file` field types within a list. {% /well %} -{% well heading="Example Project: Local Assets" href="https://github.com/keystonejs/keystone/tree/main/examples/assets-local" %} +{% well heading="Example Project: Local Assets" href="" %} A full keystone project illustrating how to configure `storage` using `kind: 'local'` and then uses both an `image` and `file` field types within a list. {% /well %} {% /related-content %} diff --git a/docs/pages/docs/guides/internal-items.md b/docs/pages/docs/guides/internal-items.md deleted file mode 100644 index 658c5033d1e..00000000000 --- a/docs/pages/docs/guides/internal-items.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: "Internal Items" -description: "We've planned this page but not had a chance to write it yet." ---- - -{% coming-soon /%} diff --git a/docs/pages/docs/guides/index.tsx b/docs/pages/docs/guides/overview.tsx similarity index 100% rename from docs/pages/docs/guides/index.tsx rename to docs/pages/docs/guides/overview.tsx diff --git a/docs/pages/docs/guides/relationships.md b/docs/pages/docs/guides/relationships.md index f621e1a6b3f..d4d1a37ef45 100644 --- a/docs/pages/docs/guides/relationships.md +++ b/docs/pages/docs/guides/relationships.md @@ -23,7 +23,7 @@ These topics are easier to understand by example. We’ll explore them, as well ## How to define a relationship in Keystone -Relationships are made using the [`relationship`](../apis/fields#relationship) field type within a [`list()`](../apis/schema). In our blog example we can connect a blog `post` to some `users` using the relationship field’s `ref` configuration option like so: +Relationships are made using the [`relationship`](../fields/relationship) field type within a [`list()`](../config/lists). In our blog example we can connect a blog `post` to some `users` using the relationship field’s `ref` configuration option like so: ```typescript{11} import { config, list } from '@keystone-6/core'; @@ -344,14 +344,14 @@ Note that we have used `many: true` in both the authors and posts fields. ## Summary -Keystone relationships are managed using the [relationship](../apis/fields#relationship) field type. They can be configured as one-sided or two-sided by the `ref` config option. Their cardinality can be set using the `many` flag. Keystone gives you the flexibility to choose what you want based on what you need to achieve. +Keystone relationships are managed using the [relationship](../fields/relationship) field type. They can be configured as one-sided or two-sided by the `ref` config option. Their cardinality can be set using the `many` flag. Keystone gives you the flexibility to choose what you want based on what you need to achieve. ## Related resources {% related-content %} {% well heading="Relationship Field API Reference" -href="/docs/apis/fields#relationship" %} +href="/docs/fields/relationship" %} Defines the names, types, and configuration of Keystone fields. See all the fields and the configuration options they accept. {% /well %} {% /related-content %} diff --git a/docs/pages/docs/guides/testing.md b/docs/pages/docs/guides/testing.md index 6071e1f9f5b..1776b04b773 100644 --- a/docs/pages/docs/guides/testing.md +++ b/docs/pages/docs/guides/testing.md @@ -53,7 +53,7 @@ This ensures that all tests are run in a known state. The test runner then sets up a partial Keystone system for you, including an Apollo server to handle GraphQL requests. The system does not include an Admin UI, and does not open a network port to listen for requests. -Finally, the runner sets up three APIs for you to use in your test. The first is a `KeystoneContext` object, which lets you use any of the functions in the [context API](../apis/context). +Finally, the runner sets up three APIs for you to use in your test. The first is a `KeystoneContext` object, which lets you use any of the functions in the [context API](../context/overview). The second is a `graphQLRequest` function, which lets you run GraphQL requests over HTTP using the [`supertest`](https://github.com/visionmedia/supertest) library. The third is an [`express.Express`](https://expressjs.com/) value named `app` which lets you access any of the endpoints of the Express server using `supertest`. @@ -68,8 +68,8 @@ This includes things like access control, hooks, virtual fields, and GraphQL API ### Context API -The [context API](../apis/context) lets you easily manipulate data in your system. -We can use the [Query API](../apis/query) to ensure that we can do basic CRUD operations. +The [context API](../context/overview) lets you easily manipulate data in your system. +We can use the [Query API](../context/query) to ensure that we can do basic CRUD operations. ```typescript runner(async ({ context }) => { @@ -254,12 +254,12 @@ Shows you how to write tests against the GraphQL API to your Keystone system. Bu {% /well %} {% well heading="Context API Reference" -href="/docs/apis/context" %} +href="/docs/context/overview" %} The API for run-time functionality in your Keystone system. Use it to write business logic for access control, hooks, testing, GraphQL schema extensions, and more. {% /well %} {% well heading="Query API Reference" -href="/docs/apis/query" %} +href="/docs/context/query" %} A programmatic API for running CRUD operations against your GraphQL API. For each list in your system you get an API at `context.query.`. {% /well %} {% /related-content %} diff --git a/docs/pages/docs/guides/virtual-fields.md b/docs/pages/docs/guides/virtual-fields.md index 2e002c5642c..34a04e3b7fe 100644 --- a/docs/pages/docs/guides/virtual-fields.md +++ b/docs/pages/docs/guides/virtual-fields.md @@ -4,10 +4,10 @@ description: "Learn how to extend your GraphQL API in powerful ways with the Vir --- Keystone lets you define your data model in terms of `lists`, which have `fields`. -Most lists will have some [scalar fields](../apis/fields#scalar-types), such as `text` and `integer` fields, which are stored in your database. +Most lists will have some [scalar fields](../fields/overview#scalar-types), such as `text` and `integer` fields, which are stored in your database. It can also be helpful to have read-only fields which are computed on the fly when you query them. -Keystone lets you do this with the [`virtual`](../apis/fields#virtual-type) field type. +Keystone lets you do this with the [`virtual`](../fields/virtual) field type. Virtual fields provide a powerful way to extend your GraphQL API. In this guide we'll introduce the syntax for adding virtual fields, and show how to build up from a simple to a complex example. @@ -75,9 +75,8 @@ The `graphql` API provides support for the built in GraphQL scalar types `Int`, The `resolve` function accepts arguments which let you write more sophisticated virtual fields. The arguments are `(item, args, context, info)`. The `item` argument is the **internal item** representing the list item being queried. -Refer to the [internal items guide](../guides/internal-items) for details on how to work with internal items in Keystone. The `args` argument represents the arguments passed to the field itself in the query. -The `context` argument is a [`KeystoneContext`](../apis/context) object. +The `context` argument is a [`KeystoneContext`](../context/overview) object. The `info` argument holds field-specific information relevant to the current query as well as the schema details. We can use the `item` and `context` arguments to query data in our Keystone system. @@ -312,7 +311,7 @@ Virtual fields provide a powerful way to extend your GraphQL API, however there The virtual field executes its resolver every time the field is requested. For trivial calculations this isn't a problem, but for more complex calculations this can lead to performance issues. In this case you can consider memoising the value to avoid recalculating it for each query. -Another way to address this is to use a [scalar field](../apis/fields#scalar-types) and to populate its value each time the item is updated using a [hook](./hooks). +Another way to address this is to use a [scalar field](../fields/overview#scalar-types) and to populate its value each time the item is updated using a [hook](./hooks). The other main consideration is that it is not possible to filter on a virtual field, as each item calcutes its value dynamically, rather than having it stored in the database. Using a pre-calculated scalar field is the best solution to use if you need filtering for your field. @@ -328,7 +327,7 @@ A demo project that shows you how to add virtual fields to a Keystone list. {% /well %} {% well heading="Virtual Fields: API Reference" -href="/docs/apis/fields#virtual-type" %} +href="/docs/fields/virtual" %} A virtual field represents a value which is computed a read time, rather than stored in the database. {% /well %} {% /related-content %} diff --git a/docs/pages/docs/index.tsx b/docs/pages/docs/index.tsx index f55e1cb45a9..1b54154c63e 100644 --- a/docs/pages/docs/index.tsx +++ b/docs/pages/docs/index.tsx @@ -314,89 +314,6 @@ export default function Docs() { - - API references - - - - Configuration - - -

    - - Keystone’s config function accepts an object representing all the configurable parts of - your backend system. - - - This is where you define the data model, or schema, of your Keystone system. - - - Defines the names, types, and configuration of the fields in a Keystone list. - - - Configures who can read, create, update, and delete items in your Keystone system - - - Let you execute code at different stages of the mutation lifecycle when performing create, - update, and delete operations. - - - Lets you configure session management in your Keystone system. - - - Supports authentication against a password field, creating initial items, password resets, - and one-time authentication tokens. - -
    - - - Context - - -
    - - The primary API entry point for all of the run-time functionally of your Keystone system. - - - A programmatic API for running CRUD operations against your GraphQL API. - - - A programmatic API for running CRUD operations against the internal GraphQL resolvers in - your system. - -
    - - - GraphQL - - -
    - - Generates a CRUD (create, read, update, delete) GraphQL API based on the schema definition - provided in your system configuration. - - - A list of the filters you can query against for each field type. - -
    ); diff --git a/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.md b/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.md index 2e8b4fd7868..a45d2fb7e4f 100644 --- a/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.md +++ b/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.md @@ -13,7 +13,7 @@ If you’re happy to write content in a local-only environment, and don't need a --- -## Explaining “modes” +## Explaining "modes" As a Headless CMS, by default Keystone works in **Standalone** mode. Where you host your Content API separately from your frontend(s). While this is great for scale, it complicates developing and deploying simple apps and websites. @@ -37,7 +37,7 @@ Here's what we're going to do: - Create a Next.js app - Embed Keystone, and run an Admin UI you can read and write to locally -- Add a simple Keystone [Schema](/apis/schema) with a `Post` List +- Add a simple Keystone [Schema](../config/lists) with a `Post` List - Setup a secure read-only GraphQL API endpoint (and GraphQL Playground) that you can access in production - Deploy the app to Vercel 🚀 @@ -69,7 +69,7 @@ It is recommended that you use the same major version of `next` as used internal Run `yarn dev` at the root of your project. -Next.js will start a local server for you at [http://localhost:3000](http://localhost:3000) +Next.js will start a local server for you at ![A browser showing the Home page of the default Next.js app](/assets/walkthroughs/embedded-nextjs/localhost-home-1.png) @@ -90,14 +90,13 @@ yarn add @keystone-6/core Add the `.keystone` directory to your `.gitignore` file. The contents of `.keystone` are generated at build time. You’ll never have to change them. ```bash - # In your .gitignore .keystone ``` ### Create your Keystone config -To create and edit blog records in Keystone’s Admin UI, add a `keystone.ts` [configuration file](/apis/config) to your project root with a simple `Post` [list](/apis/schema) containing fields for a Title, Slug, and some Content. +To create and edit blog records in Keystone’s Admin UI, add a `keystone.ts` [configuration file](../config/config) to your project root with a simple `Post` [list](../config/lists) containing fields for a Title, Slug, and some Content. {% hint kind="warn" %} **Note:** We're enabling experimental features to generate the APIs that make embedded mode work. These may change in future versions. @@ -129,7 +128,7 @@ export default config({ ``` {% hint kind="tip" %} -For simplicity we set all Post fields as [`text`](/apis/fields#text) above. For a highly customisable rich text editor use the [`document`](/guides/document-fields) field type. +For simplicity we set all Post fields as [`text`](../fields/text) above. For a highly customisable rich text editor use the [`document`](../guides/document-fields) field type. {% /hint %} ### Add Keystone to Next.js config @@ -175,8 +174,8 @@ Running `yarn dev` again will do the following: - Provision a GraphQL schema based on the configuration of `keystone.ts` - Build a [Prisma.io](https://www.prisma.io/) schema (which Keystone uses to manage the database) - Create the database and run a migration to set up your schema -- Serve Keystone’s Admin UI at [http://localhost:8000](http://localhost:8000) -- Serve the Next.js frontend at [http://localhost:3000](http://localhost:3000) +- Serve Keystone’s Admin UI at +- Serve the Next.js frontend at - Add a `postinstall` script that ensures everything works if we install other dependencies later on Go ahead and add two post entries using your Admin UI, ensuring you only use `hyphens-and-lowercase-chars` in the slug field for permalinks. @@ -296,7 +295,7 @@ export async function getStaticProps({ params }: GetStaticPropsContext) { Run `yarn dev` again. -**Congratulations!** 🙌   You now have: +**Congratulations!** 🙌   You now have: - A Next.js frontend blending static pages from your frontend repo with dynamic content from your database - Dynamic pages powered by Keystone content that‘s editable in an intuitive Admin UI. @@ -313,7 +312,7 @@ To get a read-only GraphQL API and GraphQL Playground in production, add `/pages export { default, config } from '.keystone/next/graphql-api'; ``` -This takes the fully functional GraphQL API that Keystone is already generating and makes it available as an endpoint and GraphQL Playground within the Next.js frontend app at [http://localhost:3000/api/graphql](http://localhost:3000/api/graphql). +This takes the fully functional GraphQL API that Keystone is already generating and makes it available as an endpoint and GraphQL Playground within the Next.js frontend app at . ![A browser displaying the GraphQL playground](/assets/walkthroughs/embedded-nextjs/graphql-api.png) @@ -353,7 +352,7 @@ Keystone’s Embedded mode and SQLite support gives you the option to run a self {% related-content %} {% well heading="Getting Started with create-keystone-app" -href="/docs/walkthroughs/getting-started-with-create-keystone-app" %} +href="/docs/getting-started" %} How to use Keystone's CLI app to standup a new local project with an Admin UI & the GraphQL Playground. {% /well %} diff --git a/docs/pages/docs/walkthroughs/index.tsx b/docs/pages/docs/walkthroughs/index.tsx index 7b748cdfc1c..7e1f4d2484c 100644 --- a/docs/pages/docs/walkthroughs/index.tsx +++ b/docs/pages/docs/walkthroughs/index.tsx @@ -19,10 +19,7 @@ export function QuickStart() { gap: 'var(--space-xlarge)', })} > - + Take a tour of Keystone in minutes with our CLI starter project @@ -72,28 +69,6 @@ export function Foundations() { ); } -export function ExtendedLearning() { - const mq = useMediaQuery(); - return ( -
    - - Learn how to run Keystone in the same folder as your frontend code and commit everything to - Git. You end up with a queryable GraphQL endpoint running live on Vercel. - -
    - ); -} - export default function Docs() { return ( - - - Extended learning - - - ); } diff --git a/docs/pages/docs/walkthroughs/lesson-1.md b/docs/pages/docs/walkthroughs/lesson-1.md index 03d7914e6cf..d0bd0c9f9ee 100644 --- a/docs/pages/docs/walkthroughs/lesson-1.md +++ b/docs/pages/docs/walkthroughs/lesson-1.md @@ -12,7 +12,7 @@ Welcome to the Keystone getting started series! Together we’ll learn how to turn an empty folder into a database-backed Keystone instance with related content types, publishing workflows, password protection, an editing interface, and more. {% hint kind="tip" %} -Looking to demo Keystone in under 5 minutes? [Try the quick-start CLI](/docs/walkthroughs/getting-started-with-create-keystone-app) +Looking to demo Keystone in under 5 minutes? [Try the quick-start CLI](/docs/getting-started) {% /hint %} This series assumes you have some basic familiarity with: @@ -47,7 +47,6 @@ yarn add @keystone-6/core Keystone looks for a file named `keystone.ts` (or `keystone.js`) at the project root to handle configuration needs. Let's go ahead and set one up using TypeScript: ```js - // keystone.ts export default {}; ``` @@ -74,12 +73,12 @@ Your folder structure should now look like this: We now need to configure `keystone.ts` with two parts to get our project running: -- [`db`](/docs/apis/config#db) to define a database configuration -- [`list`](/docs/apis/schema) to define the shape of the information we put in that database +- [`db`](/docs/config/config#db) to define a database configuration +- [`list`](/docs/config/lists) to define the shape of the information we put in that database ### Add a Database -We’ll use [SQLite](/docs/apis/config#sqlite) in this project to keep things simple, but you can also use [Postgres](/docs/apis/config#postgresql). The minimum config for SQLite looks like this: +We’ll use [SQLite](/docs/config/config#sqlite) in this project to keep things simple, but you can also use [Postgres](/docs/config/config#postgresql). The minimum config for SQLite looks like this: ```ts import { config } from '@keystone-6/core'; @@ -102,7 +101,7 @@ Keystone uses [Prisma](https://www.prisma.io/) to take care of database admin in Now that we have a database configured, let’s connect some content to it! -We’re going to build a simple blog with **users** and **posts**. Let’s start with the `User` list using [`text`](/docs/apis/fields#text) fields for their `name` and `email`: +We’re going to build a simple blog with **users** and **posts**. Let’s start with the `User` list using [`text`](/docs/fields/text) fields for their `name` and `email`: ```js{2,9-15}[5-8] import { config, list } from '@keystone-6/core'; @@ -128,7 +127,7 @@ export default config({ For example, the `User` key becomes the name for the respective `User` list. This key will be used in Admin UI for the list’s default display name, and in Keystone’s auto-generated GraphQL API. -**Field** names are derived from the keys in the [`fields`](/docs/apis/fields#fields-api) object. +**Field** names are derived from the keys in the [`fields`](/docs/fields/overview) object. Like lists, they’ll be used in Admin UI for field label defaults, and in the GraphQL API. We've added validation to both our fields to say that they are required, and declared that emails must be unique, so there can only be one user with each email. @@ -144,11 +143,11 @@ We now have everything we need to start Keystone, so let’s do just that: yarn keystone dev ``` -In a few seconds your terminal will provide you with you a link to the Keystone Admin UI at [http://localhost:3000](http://localhost:3000) +In a few seconds your terminal will provide you with you a link to the Keystone Admin UI at ![Terminal dialog showing successful Keystone startup](https://keystonejs.s3.amazonaws.com/framework-assets/assets/walkthroughs/lesson-1/keystone-startup.png) -Head on over to [http://localhost:3000/users](http://localhost:3000/users) where you can create your first user with a `name` and `email`: +Head on over to where you can create your first user with a `name` and `email`: ![Adding a user record in Keystone Admin UI](https://keystonejs.s3.amazonaws.com/framework-assets/assets/walkthroughs/lesson-1/first-user-creation.gif) diff --git a/docs/pages/docs/walkthroughs/lesson-3.md b/docs/pages/docs/walkthroughs/lesson-3.md index 1a676c7c3f8..372c26b4d99 100644 --- a/docs/pages/docs/walkthroughs/lesson-3.md +++ b/docs/pages/docs/walkthroughs/lesson-3.md @@ -61,7 +61,7 @@ These will give us what we need to conditionally display and order posts in a fr ### Add a publish date -Keystone’s [`timestamp`](/docs/apis/fields#timestamp) field will let editors associate a date and time with the post: +Keystone’s [`timestamp`](/docs/fields/timestamp) field will let editors associate a date and time with the post: ```ts{2,15}[5-11,17-24,29-500] import { list, config } from '@keystone-6/core'; @@ -104,7 +104,7 @@ export default config({ ### Add a published status -Keystone’s [`select`](/docs/apis/fields#select) field gives editors the ability to choose a value from a predetermined set of options. Let’s use this to capture our post's publish status. +Keystone’s [`select`](/docs/fields/select) field gives editors the ability to choose a value from a predetermined set of options. Let’s use this to capture our post's publish status. To set the the field’s desired values we add `options` to the field’s configuration. They will be the only options available to editors in Admin UI and through Keystone’s auto-generated GraphQL types: @@ -223,7 +223,7 @@ Let's put it all together to see the changes: ![Post list type showing "status" select input as segmented control type with default value of "draft"](https://keystonejs.s3.amazonaws.com/framework-assets/assets/walkthroughs/lesson-3/status-segmented-control.png) {% hint kind="tip" %} -**Protip**: To take the editing experience even farther you can use [hooks](/docs/apis/hooks) to automatically update `publishedAt` when a post’s status moves from `draft` to `published`. +**Protip**: You can use [hooks](/docs/config/hooks) to automatically update `publishedAt` when a post’s status moves from `draft` to `published`. {% /hint %} ## Looking at the GraphQL API diff --git a/docs/pages/docs/walkthroughs/lesson-4.md b/docs/pages/docs/walkthroughs/lesson-4.md index dd0d69f55e2..710096080e9 100644 --- a/docs/pages/docs/walkthroughs/lesson-4.md +++ b/docs/pages/docs/walkthroughs/lesson-4.md @@ -48,12 +48,14 @@ export default config({ }); ``` -We’re now going to add auth to our app so that different types of users have access to different types of things. +We're now going to add auth to our app so that different types of users have access to different types of things. While Keystone has very granular permissions controls, which you can read about [here](/docs/guides/auth-and-access-control), this lesson will stay focused on securing our Admin UI behind a password. ## Add the Password field -Keystone’s [password](/docs/apis/fields#password) field takes care of hashing the password for storing in the database, as well as UI niceties such as making sure the password is obscured. Let’s add it to our `User` list so they can securely log in to Keystone: +Keystone's [password](/docs/fields/password) field adheres to typical password security recommendations like hashing the password in the database, and masking the password for AdminUI input fields. + +Let's add a password field to our `User` list so users can authenticate with Keystone: ```ts{2,10}[13-27,29-500] import { list, config } from '@keystone-6/core'; diff --git a/docs/pages/docs/walkthroughs/lesson-5.md b/docs/pages/docs/walkthroughs/lesson-5.md index 5b822af98d1..1c4f0f13d0a 100644 --- a/docs/pages/docs/walkthroughs/lesson-5.md +++ b/docs/pages/docs/walkthroughs/lesson-5.md @@ -60,7 +60,7 @@ Back in [Lesson 2](/docs/walkthroughs/lesson-4) we setup a `post` type, but we s ## Add the Document field -Keystone’s [document](https://keystonejs.com/docs/apis/fields#document) field is a highly customisable Rich Text editor that lets content creators quickly and easily edit content in your system. +Keystone’s [document](https://keystonejs.com/docs/fields/document) field is a highly customisable Rich Text editor that lets content creators quickly and easily edit content in your system. To implement the document field we start by adding the package to our project: @@ -125,7 +125,7 @@ good editor experience. ## Customise the Document field -Let’s start by adding four [formatting](docs/guides/document-fields#formatting) options available in the document field’s config: +Let’s start by adding four [formatting](/docs/guides/document-fields#formatting) options available in the document field’s config: - formatting (bold, underline, italics) - links @@ -264,7 +264,7 @@ This lesson marks the end of this learning series. To dive deeper into Keystone' {% well heading="Examples" href="/docs/examples" %} A growing collection of projects you can run locally to learn more about Keystone’s capabilities {% /well %} -{% well heading="Guides" href="/docs/guides/" %} -Practical explanations of Keystone’s fundamental building blocks +{% well heading="Guides" href="/docs/guides/overview" %} +Practical explanations of Keystone's fundamental building blocks {% /well %} {% /related-content %} diff --git a/docs/pages/for-content-management.tsx b/docs/pages/for-content-management.tsx index 8c7518aa7b2..8bf60cabde2 100644 --- a/docs/pages/for-content-management.tsx +++ b/docs/pages/for-content-management.tsx @@ -99,7 +99,7 @@ export default function ForOrganisations() { - + Access control API → @@ -168,7 +168,7 @@ export default function ForOrganisations() { - + Fields API → diff --git a/docs/pages/for-developers.tsx b/docs/pages/for-developers.tsx index b2077d49a3f..011fbcbc3e2 100644 --- a/docs/pages/for-developers.tsx +++ b/docs/pages/for-developers.tsx @@ -164,12 +164,12 @@ export default function ForDevelopers() { The APIs you want. Because you made them.
    - You can’t boilerplate your way towards a great user experience. That’s why Keystone - doesn’t limit what you can put in an API. It’s flexible by design: tell Keystone what + You can't boilerplate your way towards a great user experience. That’s why Keystone + doesn't limit what you can put in an API. It’s flexible by design: tell Keystone what you want in your schema and get the matching APIs you need in return. - + Lists API reference → @@ -301,7 +301,7 @@ export default function ForDevelopers() { roles you can configure.
    - + Access control API → @@ -371,11 +371,7 @@ export default function ForDevelopers() {
  • -
  • diff --git a/docs/pages/releases/2021-04-20.mdx b/docs/pages/releases/2021-04-20.mdx index 3dae3c770ff..0a79cf7c6d9 100644 --- a/docs/pages/releases/2021-04-20.mdx +++ b/docs/pages/releases/2021-04-20.mdx @@ -25,7 +25,7 @@ import { Markdown, getStaticProps } from '../../components/Markdown'; ## Improvements to the Lists API -To make the [Lists API](https://keystonejs.com/docs/apis/schema) (i.e `context.lists.{List}`) more intuitive to use, we **deprecated the `resolveFields` option** in favour of two new methods: +To make the [Lists API](https://keystonejs.com/docs/config/lists) (i.e `context.lists.{List}`) more intuitive to use, we **deprecated the `resolveFields` option** in favour of two new methods: ### 1. Specify a string of fields to return with the **new `query` option**: diff --git a/docs/pages/releases/2021-05-17.mdx b/docs/pages/releases/2021-05-17.mdx index 9868280cb2e..33f0cb3edf8 100644 --- a/docs/pages/releases/2021-05-17.mdx +++ b/docs/pages/releases/2021-05-17.mdx @@ -13,7 +13,7 @@ import { Emoji } from '../../components/primitives/Emoji'; ## What's New -Apollo [cache hinting](https://keystonejs.com/docs/apis/schema#graphql) can now be configured on a per list or field basis — which can dramatically improve your applications performance. +Apollo [cache hinting](https://keystonejs.com/docs/config/lists#graphql) can now be configured on a per list or field basis — which can dramatically improve your applications performance. Implementing basic authentication? We've got [another example](https://github.com/keystonejs/keystone/tree/main/examples/with-auth) using `withAuth` from the `auth` package to get you started . diff --git a/docs/pages/releases/2021-06-02.mdx b/docs/pages/releases/2021-06-02.mdx index 6f65e6373bb..55615c02157 100644 --- a/docs/pages/releases/2021-06-02.mdx +++ b/docs/pages/releases/2021-06-02.mdx @@ -41,8 +41,6 @@ In addition to the JSON one above, we added new examples for: - Setting [Default Values](https://github.com/keystonejs/keystone/tree/main/examples/default-values) for fields. - [Extending the GraphQL Schema](https://github.com/keystonejs/keystone/tree/main/examples/extend-graphql-schema) with custom queries and mutations. -We also published a tutorial that shows you [how to embed Keystone and SQLite in a Next.js app](https://keystonejs.com/tutorials/embedded-mode-with-sqlite-nextjs). The end result is an app with a queryable GraphQL endpoint based on your Keystone schema that you can run live on Vercel – for free! - ### sortBy deprecated with improvements to orderBy We deprecated the `sortBy` GraphQL filter and updated the `orderBy` GraphQL filter with an improved API. @@ -179,7 +177,7 @@ We've updated our Prisma dependency from `2.22.1` to `2.24.0`! Check out the [Pr - Thanks [@jonowu](https://github.com/jonowu) for adding a `sameSite` option to the session options for cookies. Can be one of true, false, 'strict', 'lax' or 'none' as per Mozilla docs. See the [PR](https://github.com/keystonejs/keystone/pull/5774) for more details! -- Thanks [@gabrielkuettel](https://github.com/gabrielkuettel) for fixing a typo [Database Items API](https://keystonejs.com/docs/apis/db-items) page! +- Thanks [@gabrielkuettel](https://github.com/gabrielkuettel) for fixing a typo [Database Items API](https://keystonejs.com/docs/context/db-items) page! You can also view the [verbose release notes](https://github.com/keystonejs/keystone/releases/tag/2021-06-02) on GitHub. diff --git a/docs/pages/releases/2021-09-06.mdx b/docs/pages/releases/2021-09-06.mdx index 88d0d5037b5..0802d6d1ef4 100644 --- a/docs/pages/releases/2021-09-06.mdx +++ b/docs/pages/releases/2021-09-06.mdx @@ -44,7 +44,7 @@ Access Control is now easier to program, and makes it harder to introduce securi ### How to upgrade 1. Follow the instructions in our [Access Control upgrade guide](https://keystonejs.com/updates/new-access-control). -2. Review our updated [Access Control API](https://keystonejs.com/docs/apis/access-control) docs. +2. Review our updated [Access Control API](https://keystonejs.com/docs/config/access-control) docs. !> If you have any questions, please don't hesitate to open a [GitHub discussion](https://github.com/keystonejs/keystone/discussions/new?category=questions). @@ -86,7 +86,7 @@ A long awaited feature, the Express App that Keystone creates is now customisabl - Host two apps on separate ports - And more... -Check out the [Server Config docs](https://keystonejs.com/docs/apis/config#server) for more information. +Check out the [Server Config docs](https://keystonejs.com/docs/config/config#server) for more information. ## Package Shuffle @@ -124,7 +124,7 @@ import { Unique fields marked as `isUnique: true` are now represented as `isIndexed: 'unique'`. This ensures that regular indexes and unique indexes aren't enabled at the same time. -`isIndexed` accepts the following options as per the [Fields API docs](https://keystonejs.com/docs/apis/fields) - +`isIndexed` accepts the following options as per the [Fields API docs](https://keystonejs.com/docs/fields/overview) - - If `true` then the field will be indexed by the database. - If `'unique'` then all values of the field must be unique. @@ -141,15 +141,15 @@ If you've using Virtual fields or custom field types, or if constructing GraphQL Filtering and ordering is no longer enabled by default, as they have the potential to expose data which would otherwise be protected by access control. To enable filtering and ordering you can set `isFilterable: true` and `isOrderable: true` on specific fields, or set `defaultIsFilterable: true` and `defaultIsOrderable: true` at the list level. -Check out our [Fields API docs](https://keystonejs.com/docs/apis/fields#common-configuration) for all field level options. +Check out our [Fields API docs](https://keystonejs.com/docs/fields/overview#common-configuration) for all field level options. ## Introspection -You can now enable `introspection` in the Apollo Server config. Introspection enables you to query a GraphQL server for information about the underlying schema. Check out the [GraphQL Config docs](https://keystonejs.com/docs/apis/config#graphql) for more information. +You can now enable `introspection` in the Apollo Server config. Introspection enables you to query a GraphQL server for information about the underlying schema. Check out the [GraphQL Config docs](https://keystonejs.com/docs/config/config#graphql) for more information. ## GraphQL Path Customisation -The GraphQL endpoint accessible by default at `/api/graphql` can now be customised with the new option `config.graphql.path`. You can find this and all other options in our [GraphQL API docs](https://keystonejs.com/docs/apis/config#graphql). +The GraphQL endpoint accessible by default at `/api/graphql` can now be customised with the new option `config.graphql.path`. You can find this and all other options in our [GraphQL API docs](https://keystonejs.com/docs/config/config#graphql). ## Admin UI Improvements diff --git a/docs/pages/releases/2021-10-05.mdx b/docs/pages/releases/2021-10-05.mdx index 23cd2cee380..faa7544016a 100644 --- a/docs/pages/releases/2021-10-05.mdx +++ b/docs/pages/releases/2021-10-05.mdx @@ -37,12 +37,12 @@ The main things to keep in mind are: - `defaultValue` config is now static, if you have dynamic defaults, use the `resolveInput` hook - `isRequired` for fields is now `validation: { isRequired }` and we have new validation options such as `min` and `max` for some fields - We've made it clearer which fields are nullable in the database and tweaked the defaults, you now have more control but may need to migrate your database (more details below) -- The `hooks` API has new arguments, and we’ve consolidated update and delete events into `beforeOperation` and `afterOperation` +- The `hooks` API has new arguments, and we've consolidated update and delete events into `beforeOperation` and `afterOperation` - `context.lists` has been renamed to `context.query` ## Fields Overhaul -Keystone’s field types have been given a big overhaul - including several breaking changes, read on to understand what has changed. +Keystone's field types have been given a big overhaul - including several breaking changes, read on to understand what has changed. ?> Some of these API changes are **breaking** and you will be required to update your project. @@ -266,7 +266,7 @@ Additionaly, we've renamed: - `updatedItem` for `afterOperation` to `item` -See the [Hooks API docs](https://keystonejs.com/docs/apis/hooks) for a complete reference for the updated API! +See the [Hooks API docs](https://keystonejs.com/docs/config/hooks) for a complete reference for the updated API! ## Removals @@ -376,7 +376,7 @@ Apollo Server has had a major upgrade to [Version 3](https://www.apollographql.c The Apollo documentation contains a full list of breaking changes introduced by this update. -You can configure the Apollo Server provided by Keystone using the [`graphql.apolloConfig`](https://keystonejs.com/docs/apis/config#graphql) configuration option. +You can configure the Apollo Server provided by Keystone using the [`graphql.apolloConfig`](https://keystonejs.com/docs/config/config#graphql) configuration option. The most prominent change for most users will be that the **GraphQL Playground** has been replaced by the **Apollo Sandbox**. diff --git a/docs/pages/updates/general-availability.mdx b/docs/pages/updates/general-availability.mdx index 4ceaee6f856..4fe817fe615 100644 --- a/docs/pages/updates/general-availability.mdx +++ b/docs/pages/updates/general-availability.mdx @@ -113,7 +113,7 @@ This field gives you the control you need to set your editors up for success wit ## More powerful APIs -Our [Fields](../docs/apis/fields), [Hooks](../docs/apis/hooks), [Access Control](../docs/apis/access-control), [GraphQL](../docs/apis/graphql), and [Query Filter](../docs/apis/filters) APIs are better than ever. They’re now much easier to program and have better naming parameters and more consistent authoring patterns in place so you’re less likely to need our docs the every time you use that one API. +Our [Fields](../docs/fields/overview), [Hooks](../docs/config/hooks), [Access Control](../docs/config/access-control), [GraphQL](../docs/graphql/overview), and [Query Filter](../docs/graphql/filters) APIs are better than ever. They’re now much easier to program and have better naming parameters and more consistent authoring patterns in place so you’re less likely to need our docs the every time you use that one API. ## Admin UI @@ -130,11 +130,11 @@ Here’s a few of the other cool things we shipped in Keystone this year: - More powerful Virtual Fields - New CLI and dev experience - [Server-side live reloading](/releases/2021-11-02#server-side-live-reloading) -- [JSON field](../docs/apis/fields#json) -- [Health check server endpoints](../docs/apis/config#health-check) +- [JSON field](../docs/fields/json) +- [Health check server endpoints](../docs/config/config#health-check) - [17 example projects](../docs/examples) to explore Keystone’s many features and get you up and running on the web -This release completes a body of work that make **Keystone 6 our best developer experience yet**. If you’ve been waiting to tryout Keystone 6 **there’s never been a better time**. Just yarn create keystone-app or read our [getting started guide](../docs/walkthroughs/getting-started-with-create-keystone-app) to take your first steps. +This release completes a body of work that make **Keystone 6 our best developer experience yet**. If you’ve been waiting to tryout Keystone 6 **there’s never been a better time**. Just yarn create keystone-app or read our [getting started guide](../docs/getting-started) to take your first steps. ## What's Next @@ -151,7 +151,7 @@ Thank you, and here’s to a feature rich 2022! ( - + {children} ); diff --git a/docs/pages/updates/index.tsx b/docs/pages/updates/index.tsx index 2bbfdf57561..fca54de62df 100644 --- a/docs/pages/updates/index.tsx +++ b/docs/pages/updates/index.tsx @@ -188,7 +188,7 @@ export default function WhatsNew() { /> - + We’ve added support for MySQL to Keystone's list of DB providers, bringing the total number of supported DB types to three. @@ -424,8 +424,8 @@ export default function WhatsNew() { - Keystone 6 is now in General Availability! Today’s Keystone is faster and more flexible - than it’s ever been, and is ready for you to build amazing things with{' '} + Keystone 6 is now in General Availability! Today's Keystone is faster and more flexible + than it's ever been, and is ready for you to build amazing things with{' '} {' '} Read the full story here. @@ -571,7 +571,7 @@ export default function WhatsNew() { Our CLI app now uses SQLite under the hood so you don’t have to spend time on DB config when trying out new ideas. We also updated the{' '} - + getting started walkthrough {' '} to reflect this improvement. @@ -650,7 +650,7 @@ export default function WhatsNew() { A long awaited feature, the Express App that Keystone creates is now{' '} - + customisable {' '} with the new extendExpressApp option: @@ -665,7 +665,7 @@ export default function WhatsNew() { The GraphQL endpoint accessible by default at `/api/graphql` can now be customised with the new option config.graphql.path. You can find this and all other options in our{' '} - + GraphQL API docs . @@ -718,7 +718,7 @@ export default function WhatsNew() { your organisation. - + We've added an optional /_healthcheck endpoint to Keystone's express server. Use it to ensure your Keystone instance is up and running with website monitoring solutions. @@ -762,14 +762,14 @@ export default function WhatsNew() {
    • Public{' '} - + auth {' '} and signup
    • Role-based{' '} - + access control
    • @@ -902,13 +902,13 @@ export default function WhatsNew() { A long awaited feature: you can now find an item by unique fields in your schema. It works for{' '} - + text {' '} and{' '} - + integer {' '} @@ -955,16 +955,6 @@ export default function WhatsNew() { comes with explainers on the how and why. Use them as a reference for best practice, and as a jumping off point when adding features to your own Keystone project. - - - You can now use SQLite to store data via Prisma. It includes support for the{' '} - file and cloudinary field types, and - lets you{' '} - - embed Keystone inside a Next.js frontend app - - . - We’ve pruned a lot of code to make way for a more efficient and productive core in diff --git a/docs/pages/updates/keystone-5-vs-keystone-6-preview.mdx b/docs/pages/updates/keystone-5-vs-keystone-6-preview.mdx index 1215ca4172c..eb672bcd9ee 100644 --- a/docs/pages/updates/keystone-5-vs-keystone-6-preview.mdx +++ b/docs/pages/updates/keystone-5-vs-keystone-6-preview.mdx @@ -17,7 +17,7 @@ x> **This article is now out of date**. If you're returning to it from an earlie There are a few major things that will change between versions 5 and 6 which we’re currently implementing in Keystone 6: - New field types. Including a new [Document field](../guides/document-fields) field which replaces the old Content field. -- New [configuration syntax](../apis/config) and [CLI](../guides/cli). +- New [configuration syntax](../config/config) and [CLI](../guides/cli). - New express-independent session system. - New internal APIs for querying lists. - Completely new Admin UI. diff --git a/docs/pages/updates/new-access-control.mdx b/docs/pages/updates/new-access-control.mdx index d80fae47d18..bf5e3031d03 100644 --- a/docs/pages/updates/new-access-control.mdx +++ b/docs/pages/updates/new-access-control.mdx @@ -4,7 +4,7 @@ import { Emoji } from '../../components/primitives/Emoji'; # A new & improved Access Control API Securing the data in your Keystone sytem is one of the most important steps in preparing your application for a production deployment. -To make this process simpler and safer, we've made some important changes to the [Access Control APIs](/docs/apis/access-control) from previous versions. +To make this process simpler and safer, we've made some important changes to the [Access Control APIs](/docs/config/access-control) from previous versions. This document outlines the motivation behind the changes, and shows you how to update your existing Access Control functions to use the new APIs. ## Control your GraphQL API @@ -28,7 +28,7 @@ export default config({ With the new API, access control will never have any effect on which operations are in your GraphQL API. -If you would like to exclude an operation from the GraphQL API, you can use the new [`config.graphql.omit`](/docs/apis/schema#graphql) API. +If you would like to exclude an operation from the GraphQL API, you can use the new [`config.graphql.omit`](/docs/config/lists#graphql) API. To exclude all `delete` operations, you would write: ```typescript @@ -67,7 +67,7 @@ In practice, these alternatives were not very intuitive to use, and often lead t The new API makes each rule much more explicit and supports fewer variations, making it easier to read, write, and maintain your access control rules. This in turn will reduce the risk of introducing security gaps in your system. -Before moving on, be sure to [read the docs](/docs/apis/access-control) for the new API. +Before moving on, be sure to [read the docs](/docs/config/access-control) for the new API. ### Updating static access control diff --git a/docs/pages/updates/new-graphql-api.mdx b/docs/pages/updates/new-graphql-api.mdx index 01d4cf6647a..2d43538de39 100644 --- a/docs/pages/updates/new-graphql-api.mdx +++ b/docs/pages/updates/new-graphql-api.mdx @@ -145,7 +145,7 @@ No filter functionality has been removed or added, however the individual filter !> See the [Filters Guide](/docs/guides/filters) for a detailed walk through the new filtering syntax. -!> See the [API docs](/docs/apis/filters) for a comprehensive list of all the new filters for each field type. +!> See the [API docs](/docs/graphql/filters) for a comprehensive list of all the new filters for each field type. ## Mutations @@ -398,7 +398,7 @@ If you have any questions, please don't hesitate to open a [GitHub discussion](h 3. Update mutation arguments to match the new input types. Make sure you replace `{ id: "..."}` with `{where: { id: "..."} }` in your `update` and `delete` operations. 4. Update relationship inputs to `create` and `update` operations. Ensure you've replaced usage of `{ disconnectAll: true }` with `{ set: [] }` in to-many relationships, and have used `{ disconnect: true }` rather than `{ disconnect: { id: "..."} }` in to-one relationships. -!> Finally, make sure you apply corresponding changes to filters and input arguments when using the [Query API](/docs/apis/query). +!> Finally, make sure you apply corresponding changes to filters and input arguments when using the [Query API](/docs/context/query). --- diff --git a/docs/pages/why-keystone.tsx b/docs/pages/why-keystone.tsx index 6c16705cfa3..b750ae53b02 100644 --- a/docs/pages/why-keystone.tsx +++ b/docs/pages/why-keystone.tsx @@ -336,7 +336,7 @@ export default function WhyKeystonePage() { Out of the box data ops for every field type. A powerful GraphQL API from day one. - + Access control API → @@ -384,7 +384,7 @@ export default function WhyKeystonePage() { Start and end sessions from the GraphQL API. Secure your data using access control. - + Session API → @@ -409,7 +409,7 @@ export default function WhyKeystonePage() { roles you can configure. - + Access Control API → @@ -461,7 +461,7 @@ export default function WhyKeystonePage() { Everything as you make it. - + Fields API → diff --git a/docs/public/assets/walkthroughs/getting-started/adminui.png b/docs/public/assets/getting-started/adminui.png similarity index 100% rename from docs/public/assets/walkthroughs/getting-started/adminui.png rename to docs/public/assets/getting-started/adminui.png diff --git a/docs/public/assets/walkthroughs/getting-started/cover.svg b/docs/public/assets/getting-started/cover.svg similarity index 100% rename from docs/public/assets/walkthroughs/getting-started/cover.svg rename to docs/public/assets/getting-started/cover.svg diff --git a/docs/public/assets/walkthroughs/getting-started/welcome-screen.png b/docs/public/assets/getting-started/welcome-screen.png similarity index 100% rename from docs/public/assets/walkthroughs/getting-started/welcome-screen.png rename to docs/public/assets/getting-started/welcome-screen.png diff --git a/docs/redirects.js b/docs/redirects.js index 5114468559a..cf9256ad6f2 100644 --- a/docs/redirects.js +++ b/docs/redirects.js @@ -10,11 +10,6 @@ const KEYSTONE_4 = [ destination: 'https://v4.keystonejs.com/api/field/options', permanent: true, }, - { - source: '/docs/getting-started', - destination: 'https://v4.keystonejs.com/getting-started', - permanent: true, - }, { source: '/documentation/configuration/project-options', destination: 'https://v4.keystonejs.com/documentation/configuration/project-options', @@ -25,11 +20,11 @@ const KEYSTONE_4 = [ destination: 'https://v4.keystonejs.com/documentation/database', permanent: true, }, - { - source: '/getting-started', - destination: 'https://v4.keystonejs.com/getting-started', - permanent: true, - }, + // { + // source: '/getting-started', + // destination: 'https://v4.keystonejs.com/getting-started', + // permanent: true, + // }, ]; /* URLs from v5.keystonejs.com */ @@ -95,7 +90,7 @@ const ORIGINAL_NEXT = [ }, { source: '/tutorials/getting-started-with-create-keystone-app', - destination: '/docs/walkthroughs/getting-started-with-create-keystone-app', + destination: '/docs/getting-started', permanent: true, }, { @@ -107,7 +102,21 @@ const ORIGINAL_NEXT = [ { source: '/whats-new', destination: '/updates/whats-new-in-v6', permanent: true }, ]; -/* URLs from the current website */ +/* Splitbee Proxy */ +const SPLITBEE = [ + { + source: '/sb.js', + destination: 'https://cdn.splitbee.io/sb.js', + permanent: false, + }, + { + source: '/_sb/:slug', + destination: 'https://hive.splitbee.io/:slug', + permanent: false, + }, +]; + +/* Current website redirections */ const CURRENT = [ { source: '/docs/guides/keystone-5-vs-keystone-next', @@ -127,18 +136,80 @@ const CURRENT = [ destination: '/docs/guides/keystone-5-vs-keystone-next', permanent: true, }, -]; + { + source: '/docs/walkthroughs/getting-started-with-create-keystone-app', + destination: '/docs/getting-started', + permanent: true, + }, + { + source: '/docs/guides', + destination: '/docs/guides/overview', + permanent: false, + }, + { + source: '/docs/apis/config', + destination: '/docs/config/config', + permanent: false, + }, + { + source: '/docs/apis/schema', + destination: '/docs/config/lists', + permanent: false, + }, + { + source: '/docs/apis/fields', + destination: '/docs/config/fields', + permanent: false, + }, + { + source: '/docs/apis/auth', + destination: '/docs/config/auth', + permanent: false, + }, + { + source: '/docs/apis/access-control', + destination: '/docs/config/access-control', + permanent: false, + }, + { + source: '/docs/apis/hooks', + destination: '/docs/config/hooks', + permanent: false, + }, + { + source: '/docs/apis/session', + destination: '/docs/config/session', + permanent: false, + }, + { + source: '/docs/apis/context', + destination: '/docs/context/overview', + permanent: false, + }, + { + source: '/docs/apis/query', + destination: '/docs/context/query', + permanent: false, + }, + { + source: '/docs/apis/db-items', + destination: '/docs/context/db-items', + permanent: false, + }, -/* Splitbee Proxy */ -const SPLITBEE = [ { - source: '/sb.js', - destination: 'https://cdn.splitbee.io/sb.js', + source: '/docs/apis/graphql', + destination: '/docs/graphql/overview', permanent: false, }, { - source: '/_sb/:slug', - destination: 'https://hive.splitbee.io/:slug', + source: '/docs/apis/filters', + destination: '/docs/graphql/filters', + permanent: false, + }, + { + source: '/docs/apis/fields', + destination: '/docs/fields/overview', permanent: false, }, ]; diff --git a/docs/validate-links.ts b/docs/validate-links.ts new file mode 100644 index 00000000000..aa6fd6bac0f --- /dev/null +++ b/docs/validate-links.ts @@ -0,0 +1,52 @@ +import fs from 'fs/promises'; +import globby from 'globby'; +import Markdoc from '@markdoc/markdoc'; +import { getIdForHeading, markdocConfig as baseMarkdocConfig, Pages } from './markdoc/config'; +import { printValidationError } from './markdoc'; + +// for the things that aren't Markdoc that are linked from Markdoc +const NON_MARKDOWN_PAGES = [ + '/updates/new-graphql-api', + '/docs/guides/document-field-demo', + '/releases/2021-10-05', + '/docs/examples', + '/docs/guides/overview', + '/docs/config/overview', +]; + +(async () => { + const files = await globby('pages/docs/**/*.md'); + const parsedFiles = await Promise.all( + files.map(async file => { + const contents = await fs.readFile(file, 'utf8'); + const root = Markdoc.parse(contents, file); + const ids = new Set(); + for (const node of root.walk()) { + if (node.type === 'heading') { + const id = getIdForHeading(node); + ids.add(id); + } + } + return { root, ids, path: file.replace(/\.md$/, '') }; + }) + ); + + const pages: Pages = new Map( + parsedFiles.map(({ path, ids }) => [path.replace(/^pages/, '').replace(/\.md$/, ''), { ids }]) + ); + for (const NON_MARKDOWN_PAGE of NON_MARKDOWN_PAGES) { + pages.set(NON_MARKDOWN_PAGE, { ids: new Set() }); + } + + const markdocConfig = { ...baseMarkdocConfig, pages }; + const errors = parsedFiles.flatMap(({ root }) => Markdoc.validate(root, markdocConfig)); + if (errors.length) { + for (const error of errors) { + console.error(printValidationError(error)); + } + process.exitCode = 1; + } +})().catch(err => { + console.error(err); + process.exitCode = 1; +}); diff --git a/examples/custom-session-validation/README.md b/examples/custom-session-validation/README.md index 51a6e233270..4607c72b961 100644 --- a/examples/custom-session-validation/README.md +++ b/examples/custom-session-validation/README.md @@ -19,7 +19,7 @@ You can also access a GraphQL Playground at [localhost:3000/api/graphql](http:// ## Features Based on the [Authentication example](../with-auth/), this project demonstrates how to customize the keystone session configuration in order to invalidate a session when a user's password is changed. -It uses the [`@keystone-6/auth`](https://keystonejs.com/docs/apis/auth) package, along with Keystone's [session management API](https://keystonejs.com/docs/apis/session), to add the following features: +It uses the [`@keystone-6/auth`](https://keystonejs.com/docs/config/auth) package, along with Keystone's [session management API](https://keystonejs.com/docs/config/session), to add the following features: - Adds a hook to the `password` field to set a timestamp field when the user changes their password - Changes the stateless session handling to set the time a session starts diff --git a/examples/extend-graphql-schema-graphql-ts/README.md b/examples/extend-graphql-schema-graphql-ts/README.md index 8ea8bcbbf62..3595535a9fc 100644 --- a/examples/extend-graphql-schema-graphql-ts/README.md +++ b/examples/extend-graphql-schema-graphql-ts/README.md @@ -19,7 +19,7 @@ You can also access a GraphQL Playground at [localhost:3000/api/graphql](http:// ## Features This project demonstrates how to extend the GraphQL API provided by Keystone with custom queries and mutations. -Schema extensions are set using the [`extendGraphqlSchema`](https://keystonejs.com/docs/apis/config#extend-graphql-schema) config option. +Schema extensions are set using the [`extendGraphqlSchema`](https://keystonejs.com/docs/config/config#extend-graphql-schema) config option. The `graphql.extend` function allows you to extend the existing query and mutation types and define new types or use existing types in your extension. diff --git a/examples/extend-graphql-schema/README.md b/examples/extend-graphql-schema/README.md index eabb06e744f..77313b93d5b 100644 --- a/examples/extend-graphql-schema/README.md +++ b/examples/extend-graphql-schema/README.md @@ -19,7 +19,7 @@ You can also access a GraphQL Playground at [localhost:3000/api/graphql](http:// ## Features This project demonstrates how to extend the GraphQL API provided by Keystone with custom queries and mutations. -Schema extensions are set using the [`extendGraphqlSchema`](https://keystonejs.com/docs/apis/config#extend-graphql-schema) config option. +Schema extensions are set using the [`extendGraphqlSchema`](https://keystonejs.com/docs/config/config#extend-graphql-schema) config option. The function `graphQLSchemaExtension` accepts a `typeDefs` string, which lets you define your GraphQL types, and a `resolvers` object, which lets your define resolvers for your types. diff --git a/examples/json/README.md b/examples/json/README.md index 352022bb1f7..16289364826 100644 --- a/examples/json/README.md +++ b/examples/json/README.md @@ -20,7 +20,7 @@ You can also access a GraphQL Playground at [localhost:3000/api/graphql](http:// ## Features -This example implements a `Packages` list. In this field we specify a `pkgjson` field which is a [`json` field type](https://keystonejs.com/docs/apis/fields#json). +This example implements a `Packages` list. In this field we specify a `pkgjson` field which is a [`json` field type](https://keystonejs.com/docs/config/fields#json). This accepts any valid JSON including: - string diff --git a/examples/task-manager/README.md b/examples/task-manager/README.md index 3c897d4c7a3..105c04b66d1 100644 --- a/examples/task-manager/README.md +++ b/examples/task-manager/README.md @@ -14,7 +14,7 @@ yarn dev This will start Keystone’s Admin UI at [localhost:3000](http://localhost:3000), where you can add items to an empty database. -You can also access Keystone’s GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql) to explore the GraphQL API, and run [queries](https://keystonejs.com/docs/guides/filters) and [mutations](https://keystonejs.com/docs/apis/graphql#mutations) on your data. +You can also access Keystone’s GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql) to explore the GraphQL API, and run [queries](https://keystonejs.com/docs/guides/filters) and [mutations](https://keystonejs.com/docs/graphql/overview#mutations) on your data. Congratulations, you’re now up and running with Keystone! 🚀 diff --git a/examples/testing/README.md b/examples/testing/README.md index 4cc9a330f75..acadf9a47d0 100644 --- a/examples/testing/README.md +++ b/examples/testing/README.md @@ -82,7 +82,7 @@ For each test, the runner will connect to the database and drop all the data so #### `context` -The test runner provides the test function with a [`KeystoneContext`](https://keystonejs.com/docs/apis/context) argument called `context`. This is the main API for interacting with the Keystone system. It can be used to read and write data to the system and verify that the system is behaving as expected. +The test runner provides the test function with a [`KeystoneContext`](https://keystonejs.com/docs/context/overview) argument called `context`. This is the main API for interacting with the Keystone system. It can be used to read and write data to the system and verify that the system is behaving as expected. ```typescript test( diff --git a/examples/with-auth/README.md b/examples/with-auth/README.md index 0245f2ec0f5..4c20896de99 100644 --- a/examples/with-auth/README.md +++ b/examples/with-auth/README.md @@ -19,7 +19,7 @@ You can also access a GraphQL Playground at [localhost:3000/api/graphql](http:// ## Features This project demonstrates how to add authentication to a Keystone system. -It uses the [`@keystone-6/auth`](https://keystonejs.com/docs/apis/auth) package, along with Keystone's [session management API](https://keystonejs.com/docs/apis/session), to add the following features to the Task Manager base: +It uses the [`@keystone-6/auth`](https://keystonejs.com/docs/config/auth) package, along with Keystone's [session management API](https://keystonejs.com/docs/config/session), to add the following features to the Task Manager base: - Configure which fields to use for signin - Set up stateless session handling to keep track of the signed in user diff --git a/yarn.lock b/yarn.lock index 0a5bcbd6964..5de4754fbd9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2612,6 +2612,30 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb" integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg== +"@esbuild-kit/cjs-loader@^2.3.3": + version "2.3.3" + resolved "https://registry.yarnpkg.com/@esbuild-kit/cjs-loader/-/cjs-loader-2.3.3.tgz#d65a8cc099d88ac58a571403428d82d1a791aefa" + integrity sha512-Rt4O1mXlPEDVxvjsHLgbtHVdUXYK9C1/6ThpQnt7FaXIjUOsI6qhHYMgALhNnlIMZffag44lXd6Dqgx3xALbpQ== + dependencies: + "@esbuild-kit/core-utils" "^2.1.0" + get-tsconfig "^4.1.0" + +"@esbuild-kit/core-utils@^2.1.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@esbuild-kit/core-utils/-/core-utils-2.3.0.tgz#b1e979fb19d23c71cf8815e3bcd0e792d9c9049d" + integrity sha512-JL73zt/LN/qqziHuod4/bM2xBNNofDZu1cbwT6KIn6B11lA4cgDXkoSHOfNCbZMZOnh0Aqf0vW/gNQC+Z18hKQ== + dependencies: + esbuild "~0.15.4" + source-map-support "^0.5.21" + +"@esbuild-kit/esm-loader@^2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@esbuild-kit/esm-loader/-/esm-loader-2.4.2.tgz#b358112c6592f422cc43c0439396537481518412" + integrity sha512-N9dPKAj8WOx6djVnStgILWXip4fjDcBk9L7azO0/uQDpu8Ee0eaL78mkN4Acid9BzvNAKWwdYXFJZnsVahNEew== + dependencies: + "@esbuild-kit/core-utils" "^2.1.0" + get-tsconfig "^4.1.0" + "@esbuild/linux-loong64@0.15.7": version "0.15.7" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.7.tgz#1ec4af4a16c554cbd402cc557ccdd874e3f7be53" @@ -6979,7 +7003,7 @@ esbuild-windows-arm64@0.15.7: resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.7.tgz#7d5e9e060a7b454cb2f57f84a3f3c23c8f30b7d2" integrity sha512-R06nmqBlWjKHddhRJYlqDd3Fabx9LFdKcjoOy08YLimwmsswlFBJV4rXzZCxz/b7ZJXvrZgj8DDv1ewE9+StMw== -esbuild@^0.15.5: +esbuild@^0.15.5, esbuild@~0.15.4: version "0.15.7" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.15.7.tgz#8a1f1aff58671a3199dd24df95314122fc1ddee8" integrity sha512-7V8tzllIbAQV1M4QoE52ImKu8hT/NLGlGXkiDsbEU5PS6K8Mn09ZnYoS+dcmHxOS9CRsV4IRAMdT3I67IyUNXw== @@ -7979,6 +8003,11 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" +get-tsconfig@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.2.0.tgz#ff368dd7104dab47bf923404eb93838245c66543" + integrity sha512-X8u8fREiYOE6S8hLbq99PeykTDoLVnxvF4DjWKJmz9xy2nNRdUcV8ZN9tniJFeKyTU3qnC9lL8n4Chd6LmVKHg== + get-uri@3: version "3.0.2" resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c" @@ -12935,7 +12964,7 @@ source-map-support@0.5.13: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-support@^0.5.16, source-map-support@~0.5.20: +source-map-support@^0.5.16, source-map-support@^0.5.21, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -13743,6 +13772,17 @@ tsutils@^3.17.1, tsutils@^3.21.0: dependencies: tslib "^1.8.1" +tsx@^3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/tsx/-/tsx-3.9.0.tgz#315738e2fa19dc5f2efd05517ed8fd3a52461acb" + integrity sha512-ofxsE+qjqCYYq4UBt5khglvb+ESgxef1YpuNcdQI92kvcAT2tZVrnSK3g4bRXTUhLmKHcC5q8vIZA47os/stng== + dependencies: + "@esbuild-kit/cjs-loader" "^2.3.3" + "@esbuild-kit/core-utils" "^2.1.0" + "@esbuild-kit/esm-loader" "^2.4.2" + optionalDependencies: + fsevents "~2.3.2" + tty-table@^4.1.5: version "4.1.6" resolved "https://registry.yarnpkg.com/tty-table/-/tty-table-4.1.6.tgz#6bd58338f36c94cce478c3337934d8a65ab40a73"