diff --git a/.changeset/blue-balloons-turn.md b/.changeset/blue-balloons-turn.md new file mode 100644 index 00000000000..a766f97f042 --- /dev/null +++ b/.changeset/blue-balloons-turn.md @@ -0,0 +1,5 @@ +--- +"@keystone-6/core": major +--- + +Update the `config` function to default any missing values to what is used internally; compatible with the internal type `ResolvedKeystoneConfig` diff --git a/.changeset/shaggy-beds-know.md b/.changeset/shaggy-beds-know.md new file mode 100644 index 00000000000..bbcebb23a5a --- /dev/null +++ b/.changeset/shaggy-beds-know.md @@ -0,0 +1,5 @@ +--- +"@keystone-6/auth": minor +--- + +Change the type of `withAuth`'s first parameter to be a `ResolvedKeystoneConfig`, rather than `KeystoneConfig` diff --git a/examples/assets-local/keystone.ts b/examples/assets-local/keystone.ts index de4cfc66bac..fc5a3f19c5f 100644 --- a/examples/assets-local/keystone.ts +++ b/examples/assets-local/keystone.ts @@ -5,14 +5,14 @@ import bytes from 'bytes' export default config({ db: { provider: 'sqlite', - url: process.env.DATABASE_URL || 'file:./keystone-example.db', + url: process.env.DATABASE_URL ?? 'file:./keystone-example.db', // WARNING: this is only needed for our monorepo examples, dont do this prismaClientPath: 'node_modules/myprisma', }, lists, server: { - maxFileSize: bytes('40Mb') + maxFileSize: bytes('40Mb')! }, storage: { my_images: { diff --git a/examples/assets-s3/keystone.ts b/examples/assets-s3/keystone.ts index c317b20e4e5..84ebc2ec254 100644 --- a/examples/assets-s3/keystone.ts +++ b/examples/assets-s3/keystone.ts @@ -13,14 +13,14 @@ const { export default config({ db: { provider: 'sqlite', - url: process.env.DATABASE_URL || 'file:./keystone-example.db', + url: process.env.DATABASE_URL ?? 'file:./keystone-example.db', // WARNING: this is only needed for our monorepo examples, dont do this prismaClientPath: 'node_modules/myprisma', }, lists, server: { - maxFileSize: bytes('8Mb') + maxFileSize: bytes('8Mb')! }, storage: { my_images: { diff --git a/examples/custom-session-invalidation/keystone.ts b/examples/custom-session-invalidation/keystone.ts index cbcfcf97ff1..c370fc70c71 100644 --- a/examples/custom-session-invalidation/keystone.ts +++ b/examples/custom-session-invalidation/keystone.ts @@ -1,7 +1,10 @@ import { config } from '@keystone-6/core' import { statelessSessions } from '@keystone-6/core/session' import { createAuth } from '@keystone-6/auth' -import { lists, type Session } from './schema' +import { + type Session, + lists, +} from './schema' import type { Config, Context, TypeInfo } from '.keystone/types' // WARNING: this example is for demonstration purposes only @@ -32,13 +35,13 @@ const { withAuth } = createAuth({ sessionData: 'passwordChangedAt', }) -function withSessionInvalidation (config: Config) { +function withSessionInvalidation (config: Config): Config { const existingSessionStrategy = config.session! return { ...config, session: { - ...config.session, + ...existingSessionStrategy, async get ({ context }: { context: Context }): Promise { const session = await existingSessionStrategy.get({ context }) if (!session) return diff --git a/examples/custom-session-passport/schema.ts b/examples/custom-session-passport/schema.ts index ae03efaf203..1872484f9f7 100644 --- a/examples/custom-session-passport/schema.ts +++ b/examples/custom-session-passport/schema.ts @@ -1,9 +1,9 @@ import { denyAll, allOperations } from '@keystone-6/core/access' import { list } from '@keystone-6/core' import { text, relationship } from '@keystone-6/core/fields' -import { type Lists } from '.keystone/types' +import type { Lists } from '.keystone/types' -import { type Session } from './auth' +import type { Session } from './auth' // WARNING: this example is for demonstration purposes only // as with each of our examples, it has not been vetted diff --git a/examples/document-field-customisation/keystone-server/keystone.ts b/examples/document-field-customisation/keystone-server/keystone.ts index f8cd02ade5c..d44b6d6094f 100644 --- a/examples/document-field-customisation/keystone-server/keystone.ts +++ b/examples/document-field-customisation/keystone-server/keystone.ts @@ -1,10 +1,10 @@ import { config } from '@keystone-6/core' -import type { KeystoneConfig } from '@keystone-6/core/types' +import type { KeystoneConfigPre } from '@keystone-6/core/types' import { seedDatabase } from './src/seed' import { lists } from './src/schema' -import { type Context, type TypeInfo } from '.keystone/types' +import type { Context, TypeInfo } from '.keystone/types' -const db: KeystoneConfig['db'] = { +const db: KeystoneConfigPre['db'] = { provider: 'sqlite', url: process.env.DATABASE_URL || 'file:./database.db', async onConnect (context: Context) { diff --git a/examples/extend-graphql-schema-nexus/schema.ts b/examples/extend-graphql-schema-nexus/schema.ts index bb46bbaf2af..f0f721f4113 100644 --- a/examples/extend-graphql-schema-nexus/schema.ts +++ b/examples/extend-graphql-schema-nexus/schema.ts @@ -94,9 +94,8 @@ export function extendGraphqlSchema (baseSchema: GraphQLSchema) { }, // Typescript output settings, probably something you might commit in dev - // TODO: remove false ??, it is not part of the example, but we are having monorepo issues - // eslint-disable-next-line no-constant-binary-expression - shouldGenerateArtifacts: false ?? process.env.NODE_ENV !== 'production', + // TODO: remove false ?? + shouldGenerateArtifacts: false, // ?? process.env.NODE_ENV !== 'production', outputs: { typegen: path.join(process.cwd(), 'nexus-types.ts'), }, diff --git a/examples/framework-nextjs-two-servers/keystone-server/keystone.ts b/examples/framework-nextjs-two-servers/keystone-server/keystone.ts index f8cd02ade5c..d44b6d6094f 100644 --- a/examples/framework-nextjs-two-servers/keystone-server/keystone.ts +++ b/examples/framework-nextjs-two-servers/keystone-server/keystone.ts @@ -1,10 +1,10 @@ import { config } from '@keystone-6/core' -import type { KeystoneConfig } from '@keystone-6/core/types' +import type { KeystoneConfigPre } from '@keystone-6/core/types' import { seedDatabase } from './src/seed' import { lists } from './src/schema' -import { type Context, type TypeInfo } from '.keystone/types' +import type { Context, TypeInfo } from '.keystone/types' -const db: KeystoneConfig['db'] = { +const db: KeystoneConfigPre['db'] = { provider: 'sqlite', url: process.env.DATABASE_URL || 'file:./database.db', async onConnect (context: Context) { diff --git a/packages/auth/src/index.ts b/packages/auth/src/index.ts index 68448486a4c..9b5d3eaba33 100644 --- a/packages/auth/src/index.ts +++ b/packages/auth/src/index.ts @@ -1,10 +1,10 @@ import type { AdminFileToWrite, BaseListTypeInfo, - KeystoneConfig, KeystoneContext, SessionStrategy, BaseKeystoneTypeInfo, + KeystoneConfig, } from '@keystone-6/core/types' import { password, timestamp } from '@keystone-6/core/fields' diff --git a/packages/core/src/admin-ui/system/generateAdminUI.ts b/packages/core/src/admin-ui/system/generateAdminUI.ts index 35aabf60571..6b8065ebe57 100644 --- a/packages/core/src/admin-ui/system/generateAdminUI.ts +++ b/packages/core/src/admin-ui/system/generateAdminUI.ts @@ -3,14 +3,14 @@ import { promisify } from 'node:util' import fs from 'node:fs/promises' import fse from 'fs-extra' import resolve from 'resolve' -import { type GraphQLSchema } from 'graphql' +import type { GraphQLSchema } from 'graphql' import { type Entry, walk as _walk } from '@nodelib/fs.walk' -import { - type AdminFileToWrite, - type __ResolvedKeystoneConfig +import type { + AdminFileToWrite, + KeystoneConfig } from '../../types' import { writeAdminFiles } from '../templates' -import { type AdminMetaRootVal } from '../../lib/create-admin-meta' +import type { AdminMetaRootVal } from '../../lib/create-admin-meta' const walk = promisify(_walk) @@ -66,7 +66,7 @@ export async function writeAdminFile (file: AdminFileToWrite, projectAdminPath: const pageExtensions = new Set(['.js', '.jsx', '.ts', '.tsx']) export async function generateAdminUI ( - config: __ResolvedKeystoneConfig, + config: KeystoneConfig, graphQLSchema: GraphQLSchema, adminMeta: AdminMetaRootVal, projectAdminPath: string, diff --git a/packages/core/src/admin-ui/templates/index.ts b/packages/core/src/admin-ui/templates/index.ts index eaf284d4f7e..c85798bff4d 100644 --- a/packages/core/src/admin-ui/templates/index.ts +++ b/packages/core/src/admin-ui/templates/index.ts @@ -1,9 +1,7 @@ import * as Path from 'path' -import { type GraphQLSchema } from 'graphql' -import { - type __ResolvedKeystoneConfig -} from '../../types' -import { type AdminMetaRootVal } from '../../lib/create-admin-meta' +import type { GraphQLSchema } from 'graphql' +import type { KeystoneConfig } from '../../types' +import type { AdminMetaRootVal } from '../../lib/create-admin-meta' import { appTemplate } from './app' import { homeTemplate } from './home' import { listTemplate } from './list' @@ -14,7 +12,8 @@ import { nextConfigTemplate } from './next-config' const pkgDir = Path.dirname(require.resolve('@keystone-6/core/package.json')) -export function writeAdminFiles (config: __ResolvedKeystoneConfig, +export function writeAdminFiles ( + config: KeystoneConfig, graphQLSchema: GraphQLSchema, adminMeta: AdminMetaRootVal, configFileExists: boolean diff --git a/packages/core/src/artifacts.ts b/packages/core/src/artifacts.ts index fa7243d7c04..2efd4e1cac0 100644 --- a/packages/core/src/artifacts.ts +++ b/packages/core/src/artifacts.ts @@ -1,11 +1,10 @@ import fs from 'node:fs/promises' import path from 'node:path' -import { type ChildProcess } from 'node:child_process' +import type { ChildProcess } from 'node:child_process' import { printSchema } from 'graphql' import { getGenerators, formatSchema } from '@prisma/internals' import { ExitError } from './scripts/utils' -import { type __ResolvedKeystoneConfig } from './types' import { initialiseLists } from './lib/core/initialise-lists' import { type System, diff --git a/packages/core/src/context.ts b/packages/core/src/context.ts index 180ef011d2e..0c034063f97 100644 --- a/packages/core/src/context.ts +++ b/packages/core/src/context.ts @@ -1,7 +1,7 @@ -import { - type BaseKeystoneTypeInfo, - type KeystoneConfig, - type KeystoneContext +import type { + BaseKeystoneTypeInfo, + KeystoneConfig, + KeystoneContext } from './types' import { createSystem } from './lib/createSystem' @@ -12,4 +12,4 @@ export function getContext ( const system = createSystem(config) const { context } = system.getKeystone(PrismaModule) return context -} \ No newline at end of file +} diff --git a/packages/core/src/fields/types/relationship/index.ts b/packages/core/src/fields/types/relationship/index.ts index 1bd1de69f9e..5065d121de5 100644 --- a/packages/core/src/fields/types/relationship/index.ts +++ b/packages/core/src/fields/types/relationship/index.ts @@ -107,13 +107,14 @@ export type RelationshipFieldConfig = } & (OneDbConfig | ManyDbConfig) & (SelectDisplayConfig | CardsDisplayConfig | CountDisplayConfig) -export function relationship ({ +export function relationship ({ ref, ...config }: RelationshipFieldConfig): FieldTypeFunc { + const { many = false } = config + const [foreignListKey, foreignFieldKey] = ref.split('.') + return ({ fieldKey, listKey, lists }) => { - const { many = false } = config - const [foreignListKey, foreignFieldKey] = ref.split('.') const foreignList = lists[foreignListKey] if (!foreignList) throw new Error(`${listKey}.${fieldKey} points to ${ref}, but ${ref} doesn't exist`) diff --git a/packages/core/src/lib/assets/createFilesContext.ts b/packages/core/src/lib/assets/createFilesContext.ts index 48e7a3cb36f..c7ba84f4687 100644 --- a/packages/core/src/lib/assets/createFilesContext.ts +++ b/packages/core/src/lib/assets/createFilesContext.ts @@ -1,8 +1,8 @@ import { randomBytes } from 'node:crypto' -import { - type FilesContext, - type __ResolvedKeystoneConfig, +import type { + FilesContext, + KeystoneConfig, } from '../../types' import { localFileAssetsAPI } from './local' import { s3FileAssetsAPI } from './s3' @@ -21,7 +21,7 @@ function defaultTransformName (path: string) { return `${urlSafeName}-${id}` } -export function createFilesContext (config: __ResolvedKeystoneConfig): FilesContext { +export function createFilesContext (config: KeystoneConfig): FilesContext { const adaptersMap = new Map() for (const [storageKey, storageConfig] of Object.entries(config.storage || {})) { diff --git a/packages/core/src/lib/assets/createImagesContext.ts b/packages/core/src/lib/assets/createImagesContext.ts index 8a2d1a6d7e1..3f3e62f48ff 100644 --- a/packages/core/src/lib/assets/createImagesContext.ts +++ b/packages/core/src/lib/assets/createImagesContext.ts @@ -1,9 +1,9 @@ import { randomBytes } from 'node:crypto' import imageSize from 'image-size' -import { - type ImagesContext, - type __ResolvedKeystoneConfig, +import type { + ImagesContext, + KeystoneConfig, } from '../../types' import type { ImageAdapter } from './types' import { localImageAssetsAPI } from './local' @@ -33,7 +33,7 @@ async function getImageMetadataFromBuffer (buffer: Buffer) { return { width, height, filesize: buffer.length, extension } } -export function createImagesContext (config: __ResolvedKeystoneConfig): ImagesContext { +export function createImagesContext (config: KeystoneConfig): ImagesContext { const imageAssetsAPIs = new Map() for (const [storageKey, storageConfig] of Object.entries(config.storage || {})) { if (storageConfig.type === 'image') { diff --git a/packages/core/src/lib/context/createContext.ts b/packages/core/src/lib/context/createContext.ts index 53a858e5df9..d957d65bf63 100644 --- a/packages/core/src/lib/context/createContext.ts +++ b/packages/core/src/lib/context/createContext.ts @@ -1,6 +1,6 @@ -import { - type IncomingMessage, - type ServerResponse +import type { + IncomingMessage, + ServerResponse } from 'http' import { type ExecutionResult, @@ -8,10 +8,10 @@ import { graphql, print } from 'graphql' -import { - type KeystoneContext, - type KeystoneGraphQLAPI, - type __ResolvedKeystoneConfig, +import type { + KeystoneContext, + KeystoneGraphQLAPI, + KeystoneConfig, } from '../../types' import { type InitialisedList } from '../core/initialise-lists' @@ -27,7 +27,7 @@ export function createContext ({ prismaClient, prismaTypes }: { - config: __ResolvedKeystoneConfig + config: KeystoneConfig lists: Record graphQLSchema: GraphQLSchema graphQLSchemaSudo: GraphQLSchema diff --git a/packages/core/src/lib/core/initialise-lists.ts b/packages/core/src/lib/core/initialise-lists.ts index 5bb774b5edc..eb2eddaca00 100644 --- a/packages/core/src/lib/core/initialise-lists.ts +++ b/packages/core/src/lib/core/initialise-lists.ts @@ -1,38 +1,38 @@ -import { type CacheHint } from '@apollo/cache-control-types' +import type { CacheHint } from '@apollo/cache-control-types' import { GraphQLString, isInputObjectType } from 'graphql' -import { - type BaseItem, - type BaseListTypeInfo, - type CacheHintArgs, - type FindManyArgs, - type GraphQLTypesForList, - type ListGraphQLTypes, - type ListHooks, - type __ResolvedKeystoneConfig, - type MaybePromise, - type NextFieldType, - type FieldTypeFunc, - QueryMode +import type { + BaseItem, + BaseListTypeInfo, + CacheHintArgs, + FindManyArgs, + GraphQLTypesForList, + ListGraphQLTypes, + ListHooks, + KeystoneConfig, + MaybePromise, + NextFieldType, + FieldTypeFunc, } from '../../types' +import { QueryMode } from '../../types' import { type GraphQLNames, __getNames, } from '../../types/utils' import { graphql } from '../..' -import { - type FieldHooks, - type ResolvedListHooks, - type ResolvedFieldHooks +import type { + FieldHooks, + ResolvedListHooks, + ResolvedFieldHooks } from '../../types/config/hooks' import { Empty, } from '../../types/schema/graphql-ts-schema' -import { - type FilterOrderArgs +import type { + FilterOrderArgs } from '../../types/config/fields' -import { - type MaybeItemFunction, - type MaybeSessionFunction +import type { + MaybeItemFunction, + MaybeSessionFunction } from '../../types/config/lists' import { type ResolvedFieldAccessControl, @@ -153,7 +153,7 @@ function throwIfNotAFilter (x: unknown, listKey: string, fieldKey: string) { throw new Error(`Configuration option '${listKey}.${fieldKey}' must be either a boolean value or a function. Received '${x}'.`) } -type ListConfigType = __ResolvedKeystoneConfig['lists'][string] +type ListConfigType = KeystoneConfig['lists'][string] type FieldConfigType = ReturnType> type PartiallyInitialisedList1 = { graphql: { isEnabled: IsListEnabled } } type PartiallyInitialisedList2 = Omit @@ -374,7 +374,7 @@ function parseFieldHooks ( } function getListsWithInitialisedFields ( - config: __ResolvedKeystoneConfig, + config: KeystoneConfig, listsRef: Record, ) { const { storage: configStorage, lists: listsConfig, db: { provider } } = config @@ -874,7 +874,7 @@ function graphqlForOutputField (field: InitialisedField) { }) } -export function initialiseLists (config: __ResolvedKeystoneConfig): Record { +export function initialiseLists (config: KeystoneConfig): Record { const listsRef: Record = {} let intermediateLists diff --git a/packages/core/src/lib/core/prisma-schema-printer.ts b/packages/core/src/lib/core/prisma-schema-printer.ts index 3856cdbe6ea..372561ab9ae 100644 --- a/packages/core/src/lib/core/prisma-schema-printer.ts +++ b/packages/core/src/lib/core/prisma-schema-printer.ts @@ -1,12 +1,10 @@ -import { - type ScalarDBField, - type ScalarDBFieldDefault -} from '../../types' -import { type ResolvedDBField } from './resolve-relationships' -import { type InitialisedList } from './initialise-lists' -import { - type __ResolvedKeystoneConfig +import type { + ScalarDBField, + ScalarDBFieldDefault } from '../../types' +import type { ResolvedDBField } from './resolve-relationships' +import type { InitialisedList } from './initialise-lists' +import type { KeystoneConfig } from '../../types' import { areArraysEqual, getDBFieldKeyForFieldOnMultiField } from './utils' const modifiers = { @@ -183,7 +181,7 @@ function assertDbFieldIsValidForIdField ( } export function printPrismaSchema ( - config: __ResolvedKeystoneConfig, + config: KeystoneConfig, lists: Record, ) { const { diff --git a/packages/core/src/lib/create-admin-meta.ts b/packages/core/src/lib/create-admin-meta.ts index 27636508e92..4ce85269950 100644 --- a/packages/core/src/lib/create-admin-meta.ts +++ b/packages/core/src/lib/create-admin-meta.ts @@ -1,20 +1,20 @@ import path from 'node:path' -import { - type BaseListTypeInfo, - type JSONValue, - type KeystoneContext, - type MaybeItemFunction, - type MaybePromise, - type MaybeSessionFunction, - type __ResolvedKeystoneConfig, +import type { + BaseListTypeInfo, + JSONValue, + KeystoneContext, + MaybeItemFunction, + MaybePromise, + MaybeSessionFunction, + KeystoneConfig, } from '../types' -import { - type GraphQLNames +import type { + GraphQLNames } from '../types/utils' -import { type FilterOrderArgs } from '../types/config/fields' +import type { FilterOrderArgs } from '../types/config/fields' import { humanize } from './utils' -import { type InitialisedList } from './core/initialise-lists' +import type { InitialisedList } from './core/initialise-lists' type ContextFunction = (context: KeystoneContext) => MaybePromise @@ -86,7 +86,7 @@ export type AdminMetaRootVal = { } export function createAdminMeta ( - config: __ResolvedKeystoneConfig, + config: KeystoneConfig, initialisedLists: Record ) { const { lists } = config @@ -272,10 +272,7 @@ export function createAdminMeta ( let currentAdminMeta: undefined | AdminMetaRootVal export function getAdminMetaForRelationshipField () { - if (currentAdminMeta === undefined) { - throw new Error('unexpected call to getAdminMetaInRelationshipField') - } - + if (currentAdminMeta === undefined) throw new Error('Unexpected call to getAdminMetaInRelationshipField') return currentAdminMeta } diff --git a/packages/core/src/lib/createAdminUIMiddleware.ts b/packages/core/src/lib/createAdminUIMiddleware.ts index 151136791ec..5a7b9ea2e48 100644 --- a/packages/core/src/lib/createAdminUIMiddleware.ts +++ b/packages/core/src/lib/createAdminUIMiddleware.ts @@ -2,16 +2,16 @@ import url from 'url' import path from 'path' import type express from 'express' import type next from 'next' -import { - type KeystoneContext, - type __ResolvedKeystoneConfig, +import type { + KeystoneContext, + KeystoneConfig, } from '../types' import { pkgDir } from '../pkg-dir' const adminErrorHTMLFilepath = path.join(pkgDir, 'static', 'admin-error.html') export function createAdminUIMiddlewareWithNextApp ( - config: __ResolvedKeystoneConfig, + config: KeystoneConfig, commonContext: KeystoneContext, nextApp: ReturnType ) { diff --git a/packages/core/src/lib/createExpressServer.ts b/packages/core/src/lib/createExpressServer.ts index a63af48780e..53b7b2a9781 100644 --- a/packages/core/src/lib/createExpressServer.ts +++ b/packages/core/src/lib/createExpressServer.ts @@ -1,19 +1,23 @@ -import { createServer, type Server } from 'http' +import { + type Server, + createServer, +} from 'http' import cors from 'cors' import { json } from 'body-parser' import { expressMiddleware } from '@apollo/server/express4' import express from 'express' +import type { GraphQLFormattedError } from 'graphql' import { - type GraphQLFormattedError, -} from 'graphql' -import { ApolloServer, type ApolloServerOptions } from '@apollo/server' + type ApolloServerOptions, + ApolloServer, +} from '@apollo/server' import { ApolloServerPluginLandingPageDisabled } from '@apollo/server/plugin/disabled' import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default' // @ts-expect-error import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.js' -import { - type KeystoneContext, - type __ResolvedKeystoneConfig, +import type { + KeystoneContext, + KeystoneConfig, } from '../types' /* @@ -24,7 +28,7 @@ The Admin UI takes a while to build for dev, and is created separately so the CLI can bring up the dev server early to handle GraphQL requests. */ -function formatError (graphqlConfig: __ResolvedKeystoneConfig['graphql']) { +function formatError (graphqlConfig: KeystoneConfig['graphql']) { return (formattedError: GraphQLFormattedError, error: unknown) => { let debug = graphqlConfig.debug if (debug === undefined) { @@ -46,7 +50,7 @@ function formatError (graphqlConfig: __ResolvedKeystoneConfig['graphql']) { } export async function createExpressServer ( - config: Pick<__ResolvedKeystoneConfig, 'graphql' | 'server' | 'storage'>, + config: Pick, context: KeystoneContext ): Promise<{ expressServer: express.Express diff --git a/packages/core/src/lib/createGraphQLSchema.ts b/packages/core/src/lib/createGraphQLSchema.ts index 5e4dff60a6e..c38246e3cd2 100644 --- a/packages/core/src/lib/createGraphQLSchema.ts +++ b/packages/core/src/lib/createGraphQLSchema.ts @@ -1,9 +1,7 @@ import { type GraphQLNamedType, GraphQLSchema } from 'graphql' import { graphql } from '../types/schema' -import { - type __ResolvedKeystoneConfig -} from '../types' +import type { KeystoneConfig } from '../types' import { KeystoneMeta } from './resolve-admin-meta' import type { AdminMetaRootVal } from './create-admin-meta' import type { InitialisedList } from './core/initialise-lists' @@ -98,7 +96,7 @@ function collectTypes ( } export function createGraphQLSchema ( - config: __ResolvedKeystoneConfig, + config: KeystoneConfig, lists: Record, adminMeta: AdminMetaRootVal | null, sudo: boolean diff --git a/packages/core/src/lib/createSystem.ts b/packages/core/src/lib/createSystem.ts index 78b039d8627..6996ab5e14b 100644 --- a/packages/core/src/lib/createSystem.ts +++ b/packages/core/src/lib/createSystem.ts @@ -1,14 +1,12 @@ import path from 'node:path' import { randomBytes } from 'node:crypto' -import { - type KeystoneConfig, - type FieldData, - type __ResolvedKeystoneConfig +import type { + FieldData, + KeystoneConfig } from '../types' import { GraphQLError } from 'graphql' import { allowAll } from '../access' -import { resolveDefaults } from './defaults' import { createAdminMeta } from './create-admin-meta' import { createGraphQLSchema } from './createGraphQLSchema' import { createContext } from './context/createContext' @@ -26,7 +24,7 @@ function posixify (s: string) { return s.split(path.sep).join('/') } -export function getSystemPaths (cwd: string, config: KeystoneConfig | __ResolvedKeystoneConfig) { +export function getSystemPaths (cwd: string, config: KeystoneConfig) { const prismaClientPath = config.db.prismaClientPath === '@prisma/client' ? null : config.db.prismaClientPath @@ -64,7 +62,7 @@ export function getSystemPaths (cwd: string, config: KeystoneConfig | __Resolved } } -function getSudoGraphQLSchema (config: __ResolvedKeystoneConfig) { +function getSudoGraphQLSchema (config: KeystoneConfig) { // This function creates a GraphQLSchema based on a modified version of the provided config. // The modifications are: // * All list level access control is disabled @@ -76,7 +74,7 @@ function getSudoGraphQLSchema (config: __ResolvedKeystoneConfig) { // operations that can be run. // // The resulting schema is used as the GraphQL schema when calling `context.sudo()`. - const transformedConfig: __ResolvedKeystoneConfig = { + const transformedConfig: KeystoneConfig = { ...config, ui: { ...config.ui, @@ -183,7 +181,7 @@ function injectNewDefaults (prismaClient: unknown, lists: Record (x: T) { return x } - -export function resolveDefaults (config: KeystoneConfig): __ResolvedKeystoneConfig { - if (!['postgresql', 'sqlite', 'mysql'].includes(config.db.provider)) { - throw new TypeError(`"db.provider" only supports "sqlite", "postgresql" or "mysql"`) - } - - // WARNING: Typescript should prevent this, but any string is useful for Prisma errors - config.db.url ??= 'postgres://' - - const defaultIdField = config.db.idField ?? { kind: 'cuid' } - const cors = - config.server?.cors === true - ? { origin: true, credentials: true } - : config.server?.cors === false - ? null - : config.server?.cors ?? null - - const httpOptions: ListenOptions = { port: 3000 } - if (config?.server && 'port' in config.server) { - httpOptions.port = config.server.port - } - - if (config?.server && 'options' in config.server && config.server.options) { - Object.assign(httpOptions, config.server.options) - } - - return { - types: { - ...config.types, - path: config.types?.path ?? 'node_modules/.keystone/types.ts', - }, - db: { - ...config.db, - shadowDatabaseUrl: config.db?.shadowDatabaseUrl ?? '', - extendPrismaSchema: config.db?.extendPrismaSchema ?? identity, - extendPrismaClient: config.db?.extendPrismaClient ?? identity, - onConnect: config.db.onConnect ?? noop, - prismaClientPath: config.db?.prismaClientPath ?? '@prisma/client', - prismaSchemaPath: config.db?.prismaSchemaPath ?? 'schema.prisma', - idField: config.db?.idField ?? defaultIdField, - enableLogging: config.db.enableLogging === true ? ['query'] - : config.db.enableLogging === false ? [] - : config.db.enableLogging ?? [], - }, - graphql: { - ...config.graphql, - path: config.graphql?.path ?? '/api/graphql', - playground: config.graphql?.playground ?? process.env.NODE_ENV !== 'production', - schemaPath: config.graphql?.schemaPath ?? 'schema.graphql', - extendGraphqlSchema: config.graphql?.extendGraphqlSchema ?? ((s) => s), - }, - lists: injectDefaults(config, defaultIdField), - server: { - ...config.server, - maxFileSize: config.server?.maxFileSize ?? (200 * 1024 * 1024), // 200 MiB - extendExpressApp: config.server?.extendExpressApp ?? noop, - extendHttpServer: config.server?.extendHttpServer ?? noop, - cors, - options: httpOptions, - }, - session: config.session, - storage: { - ...config.storage - }, - telemetry: config.telemetry ?? true, - ui: { - ...config.ui, - basePath: config.ui?.basePath ?? '', - isAccessAllowed: config.ui?.isAccessAllowed ?? defaultIsAccessAllowed, - isDisabled: config.ui?.isDisabled ?? false, - getAdditionalFiles: config.ui?.getAdditionalFiles ?? [], - pageMiddleware: config.ui?.pageMiddleware ?? noop, - publicPages:config.ui?.publicPages ?? [], - }, - } -} diff --git a/packages/core/src/lib/id-field.ts b/packages/core/src/lib/id-field.ts index 0ea90ddcaae..59ab149ad10 100644 --- a/packages/core/src/lib/id-field.ts +++ b/packages/core/src/lib/id-field.ts @@ -6,7 +6,7 @@ import { fieldType, orderDirectionEnum, } from '../types' -import { graphql } from '..' +import { graphql } from '../types/schema' import { userInputError } from './core/graphql-errors' type IDType = string | number | null diff --git a/packages/core/src/schema.ts b/packages/core/src/schema.ts index 4d4fba24148..6263985935d 100644 --- a/packages/core/src/schema.ts +++ b/packages/core/src/schema.ts @@ -1,13 +1,161 @@ -import { - type BaseFields, - type BaseKeystoneTypeInfo, - type BaseListTypeInfo, - type KeystoneConfig, - type ListConfig, +import type { + BaseFields, + BaseKeystoneTypeInfo, + BaseListTypeInfo, + IdFieldConfig, + KeystoneConfigPre, + KeystoneContext, + ListConfig, + KeystoneConfig, } from './types' -export function config (config: KeystoneConfig) { - return config +import type { ListenOptions } from 'node:net' +import { + idFieldType +} from './lib/id-field' + +function injectDefaults (config: KeystoneConfigPre, defaultIdField: IdFieldConfig) { + // some error checking + for (const [listKey, list] of Object.entries(config.lists)) { + if (list.fields.id) { + throw new Error(`"fields.id" is reserved by Keystone, use "db.idField" for the "${listKey}" list`) + } + + if (list.isSingleton && list.db?.idField) { + throw new Error(`"db.idField" on the "${listKey}" list conflicts with singleton defaults`) + } + } + + const updated: KeystoneConfig['lists'] = {} + + for (const [listKey, list] of Object.entries(config.lists)) { + if (list.isSingleton) { + updated[listKey] = { + listKey, + ...list, + fields: { + id: idFieldType({ kind: 'number', type: 'Int' }), + ...list.fields, + }, + } + + continue + } + + updated[listKey] = { + listKey, + ...list, + fields: { + id: idFieldType(list.db?.idField ?? defaultIdField), + ...list.fields, + }, + } + } + + /** @deprecated, TODO: remove in breaking change */ + for (const [listKey, list] of Object.entries(updated)) { + if (list.hooks === undefined) continue + if (list.hooks.validate !== undefined) { + if (list.hooks.validateInput !== undefined) throw new TypeError(`"hooks.validate" conflicts with "hooks.validateInput" for the "${listKey}" list`) + if (list.hooks.validateDelete !== undefined) throw new TypeError(`"hooks.validate" conflicts with "hooks.validateDelete" for the "${listKey}" list`) + continue + } + + list.hooks = { + ...list.hooks, + validate: { + create: list.hooks.validateInput, + update: list.hooks.validateInput, + delete: list.hooks.validateDelete + } + } + } + + return updated +} + +function defaultIsAccessAllowed ({ session, sessionStrategy }: KeystoneContext) { + if (!sessionStrategy) return true + return session !== undefined +} + +async function noop () {} +function identity (x: T) { return x } + +export function config (config: KeystoneConfigPre): KeystoneConfig { + if (!['postgresql', 'sqlite', 'mysql'].includes(config.db.provider)) { + throw new TypeError(`"db.provider" only supports "sqlite", "postgresql" or "mysql"`) + } + + // WARNING: Typescript should prevent this, but any string is useful for Prisma errors + config.db.url ??= 'postgres://' + + const defaultIdField = config.db.idField ?? { kind: 'cuid' } + const cors = + config.server?.cors === true + ? { origin: true, credentials: true } + : config.server?.cors === false + ? null + : config.server?.cors ?? null + + const httpOptions: ListenOptions = { port: 3000 } + if (config?.server && 'port' in config.server) { + httpOptions.port = config.server.port + } + + if (config?.server && 'options' in config.server && config.server.options) { + Object.assign(httpOptions, config.server.options) + } + + return { + types: { + ...config.types, + path: config.types?.path ?? 'node_modules/.keystone/types.ts', + }, + db: { + ...config.db, + shadowDatabaseUrl: config.db?.shadowDatabaseUrl ?? '', + extendPrismaSchema: config.db?.extendPrismaSchema ?? identity, + extendPrismaClient: config.db?.extendPrismaClient ?? identity, + onConnect: config.db.onConnect ?? noop, + prismaClientPath: config.db?.prismaClientPath ?? '@prisma/client', + prismaSchemaPath: config.db?.prismaSchemaPath ?? 'schema.prisma', + idField: config.db?.idField ?? defaultIdField, + enableLogging: config.db.enableLogging === true ? ['query'] + : config.db.enableLogging === false ? [] + : config.db.enableLogging ?? [], + }, + graphql: { + ...config.graphql, + path: config.graphql?.path ?? '/api/graphql', + playground: config.graphql?.playground ?? process.env.NODE_ENV !== 'production', + schemaPath: config.graphql?.schemaPath ?? 'schema.graphql', + extendGraphqlSchema: config.graphql?.extendGraphqlSchema ?? ((s) => s), + }, + lists: injectDefaults(config, defaultIdField), + server: { + ...config.server, + maxFileSize: config.server?.maxFileSize ?? (200 * 1024 * 1024), // 200 MiB + extendExpressApp: config.server?.extendExpressApp ?? noop, + extendHttpServer: config.server?.extendHttpServer ?? noop, + cors, + options: httpOptions, + }, + session: config.session, + storage: { + ...config.storage + }, + telemetry: config.telemetry ?? true, + ui: { + ...config.ui, + basePath: config.ui?.basePath ?? '', + isAccessAllowed: config.ui?.isAccessAllowed ?? defaultIsAccessAllowed, + isDisabled: config.ui?.isDisabled ?? false, + getAdditionalFiles: config.ui?.getAdditionalFiles ?? [], + pageMiddleware: config.ui?.pageMiddleware ?? noop, + publicPages:config.ui?.publicPages ?? [], + }, + } } let i = 0 diff --git a/packages/core/src/scripts/dev.ts b/packages/core/src/scripts/dev.ts index 414499a332b..cf5e22b063d 100644 --- a/packages/core/src/scripts/dev.ts +++ b/packages/core/src/scripts/dev.ts @@ -2,7 +2,7 @@ import fsp from 'node:fs/promises' import path from 'node:path' import url from 'node:url' import { createServer } from 'node:http' -import { type ListenOptions } from 'node:net' +import type { ListenOptions } from 'node:net' import chalk from 'chalk' import esbuild, { type BuildResult } from 'esbuild' @@ -25,24 +25,29 @@ import { generateTypes, getFormattedGraphQLSchema, } from '../artifacts' -import { type KeystoneConfig } from '../types' +import type { KeystoneConfig } from '../types' import { printPrismaSchema } from '../lib/core/prisma-schema-printer' import { pkgDir } from '../pkg-dir' import { ExitError, importBuiltKeystoneConfiguration, } from './utils' -import { type Flags } from './cli' +import type { Flags } from './cli' + +async function noop () {} const devLoadingHTMLFilepath = path.join(pkgDir, 'static', 'dev-loading.html') function stripExtendHttpServer (config: KeystoneConfig): KeystoneConfig { const { server, ...rest } = config - if (server) { - const { extendHttpServer, ...restServer } = server - return { ...rest, server: restServer } + const { extendHttpServer, ...restServer } = server + return { + ...rest, + server: { + ...restServer, + extendHttpServer: noop + } } - return rest } function resolvablePromise () { @@ -375,7 +380,7 @@ export async function dev ( } const { pathname } = url.parse(req.url) - if (expressServer && pathname === (config.graphql?.path || '/api/graphql')) { + if (expressServer && pathname === (config.graphql?.path ?? '/api/graphql')) { return expressServer(req, res, next) } @@ -386,7 +391,7 @@ export async function dev ( port: 3000, } - if (config?.server && 'port' in config.server) { + if (config?.server && 'port' in config.server && typeof config.server?.port === 'number') { httpOptions.port = config.server.port } @@ -396,12 +401,12 @@ export async function dev ( // preference env.PORT if supplied if ('PORT' in process.env) { - httpOptions.port = parseInt(process.env.PORT || '') + httpOptions.port = parseInt(process.env.PORT ?? '') } // preference env.HOST if supplied if ('HOST' in process.env) { - httpOptions.host = process.env.HOST || '' + httpOptions.host = process.env.HOST ?? '' } const server = httpServer.listen(httpOptions, (err?: any) => { @@ -411,11 +416,11 @@ export async function dev ( ? 'localhost' : httpOptions.host console.log( - `⭐️ Server listening on ${httpOptions.host || ''}:${ + `⭐️ Server listening on ${httpOptions.host ?? ''}:${ httpOptions.port } (http://${easyHost}:${httpOptions.port}/)` ) - console.log(`⭐️ GraphQL API available at ${config.graphql?.path || '/api/graphql'}`) + console.log(`⭐️ GraphQL API available at ${config.graphql?.path ?? '/api/graphql'}`) // Don't start initialising Keystone until the dev server is ready, // otherwise it slows down the first response significantly diff --git a/packages/core/src/scripts/utils.ts b/packages/core/src/scripts/utils.ts index afea23045f0..75a64551a69 100644 --- a/packages/core/src/scripts/utils.ts +++ b/packages/core/src/scripts/utils.ts @@ -1,4 +1,5 @@ import { getBuiltKeystoneConfigurationPath } from '../lib/createSystem' +import type { KeystoneConfig } from '../types' import fs from 'node:fs/promises' export class ExitError extends Error { @@ -10,7 +11,7 @@ export class ExitError extends Error { } // TODO: this cannot be changed for now, circular dependency with getSystemPaths, getEsbuildConfig -export async function importBuiltKeystoneConfiguration (cwd: string) { +export async function importBuiltKeystoneConfiguration (cwd: string): Promise { const builtConfigPath = getBuiltKeystoneConfigurationPath(cwd) if (!(await fs.stat(builtConfigPath).catch(() => null))) { console.error('🚨 keystone build has not been run') diff --git a/packages/core/src/types/config/index.ts b/packages/core/src/types/config/index.ts index 0e08f70241d..15213a0e5b1 100644 --- a/packages/core/src/types/config/index.ts +++ b/packages/core/src/types/config/index.ts @@ -9,11 +9,11 @@ import type { Options as BodyParserOptions } from 'body-parser' import type { BaseKeystoneTypeInfo, KeystoneContext, DatabaseProvider } from '..' import type { SessionStrategy } from '../session' import type { MaybePromise } from '../utils' -import { - type IdFieldConfig, - type ListConfig, - type MaybeItemFunction, - type MaybeSessionFunction, +import type { + IdFieldConfig, + ListConfig, + MaybeItemFunction, + MaybeSessionFunction, } from './lists' import type { BaseFields } from './fields' import type { ListAccessControl, FieldAccessControl } from './access-control' @@ -97,7 +97,7 @@ type PrismaLogDefinition = { emit: 'stdout' | 'event' } -export type KeystoneConfig = { +export type KeystoneConfigPre = { types?: { path: string } @@ -251,27 +251,27 @@ export type KeystoneConfig = { - types: KeystoneConfig['types'] - db: Omit['db']>, 'enableLogging'> & { +export type KeystoneConfig = { + types: KeystoneConfigPre['types'] + db: Omit['db']>, 'enableLogging'> & { enableLogging: PrismaLogLevel | Array } - graphql: NonNullable['graphql']> & { - path: Exclude['graphql'], undefined> + graphql: NonNullable['graphql']> & { + path: Exclude['graphql'], undefined> } lists: { [listKey: string]: { listKey: string - } & KeystoneConfig['lists'][string] + } & KeystoneConfigPre['lists'][string] } - server: Omit['server']>>, 'cors' | 'port'> & { + server: Omit['server']>>, 'cors' | 'port'> & { cors: CorsOptions | null options: ListenOptions } - session: KeystoneConfig['session'] - storage: NonNullable['storage']> + session: KeystoneConfigPre['session'] + storage: NonNullable['storage']> telemetry: boolean - ui: NonNullable['ui']>> + ui: NonNullable['ui']>> } export type { ListConfig, BaseFields, MaybeSessionFunction, MaybeItemFunction } diff --git a/packages/core/src/types/next-fields.ts b/packages/core/src/types/next-fields.ts index 05149147e5e..6eb5d4de165 100644 --- a/packages/core/src/types/next-fields.ts +++ b/packages/core/src/types/next-fields.ts @@ -1,13 +1,13 @@ import Decimal from 'decimal.js' -import { graphql } from '..' -import { type BaseListTypeInfo } from './type-info' -import { type CommonFieldConfig } from './config' -import { type DatabaseProvider } from './core' -import { - type JSONValue, - type KeystoneContext, - type MaybePromise, - type StorageConfig +import { graphql } from './schema' +import type { BaseListTypeInfo } from './type-info' +import type { CommonFieldConfig } from './config' +import type { DatabaseProvider } from './core' +import type { + JSONValue, + KeystoneContext, + MaybePromise, + StorageConfig } from '.' export { Decimal } diff --git a/packages/core/src/types/schema/graphql-ts-schema.ts b/packages/core/src/types/schema/graphql-ts-schema.ts index d46571b71bc..fe60ac5b077 100644 --- a/packages/core/src/types/schema/graphql-ts-schema.ts +++ b/packages/core/src/types/schema/graphql-ts-schema.ts @@ -5,8 +5,8 @@ import GraphQLUpload from 'graphql-upload/GraphQLUpload.js' import { GraphQLError, GraphQLScalarType } from 'graphql' import { Decimal as DecimalValue } from 'decimal.js' import type { GraphQLFieldExtensions, GraphQLResolveInfo } from 'graphql' -import { type KeystoneContext } from '../context' -import { type JSONValue } from '../utils' +import type { KeystoneContext } from '../context' +import type { JSONValue } from '../utils' export { Boolean, Float, @@ -40,7 +40,7 @@ export { bindGraphQLSchemaAPIToContext } from '@graphql-ts/schema' export type { BaseSchemaMeta, Extension } from '@graphql-ts/extend' export { extend, wrap } from '@graphql-ts/extend' import { field as fieldd } from './schema-api-with-context' -import { type InputType, type Arg } from '@graphql-ts/schema' +import type { InputType, Arg } from '@graphql-ts/schema' export { fields, interface, interfaceField, object, union } from './schema-api-with-context' // TODO: remove when we use { graphql } from '.keystone' diff --git a/packages/core/src/types/utils.ts b/packages/core/src/types/utils.ts index 9146abdad4f..a0a2460c9ac 100644 --- a/packages/core/src/types/utils.ts +++ b/packages/core/src/types/utils.ts @@ -1,8 +1,6 @@ import pluralize from 'pluralize' import { humanize } from '../lib/utils' -import { - type __ResolvedKeystoneConfig -} from '../types' +import { type KeystoneConfig } from '../types' export type JSONValue = | string @@ -62,7 +60,7 @@ const labelToPath = (str: string) => str.split(' ').join('-').toLowerCase() const labelToClass = (str: string) => str.replace(/\s+/g, '') // WARNING: may break in patch -export function __getNames (listKey: string, list: __ResolvedKeystoneConfig['lists'][string]) { +export function __getNames (listKey: string, list: KeystoneConfig['lists'][string]) { const { graphql, ui, isSingleton } = list if (ui?.path !== undefined && !/^[a-z-_][a-z0-9-_]*$/.test(ui.path)) { throw new Error(`ui.path for ${listKey} is ${ui.path} but it must only contain lowercase letters, numbers, dashes, and underscores and not start with a number`) diff --git a/packages/fields-document/src/DocumentEditor/tests/utils.tsx b/packages/fields-document/src/DocumentEditor/tests/utils.tsx index e3eb4026018..6d55ba1d5a0 100644 --- a/packages/fields-document/src/DocumentEditor/tests/utils.tsx +++ b/packages/fields-document/src/DocumentEditor/tests/utils.tsx @@ -373,7 +373,7 @@ function nodeToReactElement ( if (type !== undefined) { return createElement(type, { ...restNode, ...computedData, children }) } - // @ts-ignore TODO: can `type` actually be undefined? + // @ts-expect-error TODO: can `type` actually be undefined? return createElement('element', { ...node, ...computedData, children }) } diff --git a/tests/api-tests/auth-header.test.ts b/tests/api-tests/auth-header.test.ts index 9b9cbd43a44..22b973ea57b 100644 --- a/tests/api-tests/auth-header.test.ts +++ b/tests/api-tests/auth-header.test.ts @@ -1,5 +1,5 @@ -import { text, timestamp, password } from '@keystone-6/core/fields' import { list } from '@keystone-6/core' +import { text, timestamp, password } from '@keystone-6/core/fields' import { statelessSessions } from '@keystone-6/core/session' import { createAuth } from '@keystone-6/auth' import { setupTestRunner, setupTestEnv } from '@keystone-6/api-tests/test-runner' @@ -23,9 +23,7 @@ function setup (options?: any) { }) return setupTestRunner({ - serve: true, config: withAuth({ - db: {} as any, lists: { Post: list({ access: allowAll, @@ -44,7 +42,8 @@ function setup (options?: any) { }), }, session: statelessSessions(), - }) + } as any) as any, + serve: true, }) } @@ -99,23 +98,20 @@ describe('Auth testing', () => { sessionData: 'id', }) await expect( - setupTestEnv({ - config: auth.withAuth({ - db: {} as any, - lists: { - User: list({ - access: allowAll, - fields: { - name: text(), - email: text(), - password: password(), - }, - }), - }, + setupTestEnv(auth.withAuth({ + lists: { + User: list({ + access: allowAll, + fields: { + name: text(), + email: text(), + password: password(), + }, + }), + }, - session: statelessSessions(), - }), - }) + session: statelessSessions(), + } as any) as any), ).rejects.toMatchInlineSnapshot( `[Error: createAuth was called with an identityField of email on the list User but that field doesn't allow being searched uniquely with a String or ID. You should likely add \`isIndexed: 'unique'\` to the field at User.email]` ) diff --git a/tests/api-tests/auth.test.ts b/tests/api-tests/auth.test.ts index 4c1ab5f3a40..8ef9af061a2 100644 --- a/tests/api-tests/auth.test.ts +++ b/tests/api-tests/auth.test.ts @@ -57,7 +57,7 @@ const runner = setupTestRunner({ }), }, session: statelessSessions(), - }), + } as any) as any, }) async function authenticateWithPassword ( diff --git a/tests/api-tests/authed-user.test.ts b/tests/api-tests/authed-user.test.ts index d58f0602659..d267c2ac72b 100644 --- a/tests/api-tests/authed-user.test.ts +++ b/tests/api-tests/authed-user.test.ts @@ -29,7 +29,7 @@ const runner = setupTestRunner({ }), }, session: statelessSessions(), - })) + }) as any) as any }) test( diff --git a/tests/api-tests/defaults.test.ts b/tests/api-tests/defaults.test.ts index 0b4b0b23b2d..720c262aa67 100644 --- a/tests/api-tests/defaults.test.ts +++ b/tests/api-tests/defaults.test.ts @@ -1,12 +1,12 @@ import { text } from '@keystone-6/core/fields' import { list } from '@keystone-6/core' -import { type BaseFields } from '@keystone-6/core/types' +import type { BaseFields } from '@keystone-6/core/types' import { allowAll } from '@keystone-6/core/access' import { setupTestRunner } from './test-runner' -const setupList = (fields: BaseFields) => - setupTestRunner({ +function setupList (fields: BaseFields) { + return setupTestRunner({ config: ({ lists: { User: list({ @@ -16,6 +16,7 @@ const setupList = (fields: BaseFields) => }, }), }) +} describe('defaultValue field config', () => { test( diff --git a/tests/api-tests/field-groups.test.ts b/tests/api-tests/field-groups.test.ts index 1ee74812cb7..3e183b353dc 100644 --- a/tests/api-tests/field-groups.test.ts +++ b/tests/api-tests/field-groups.test.ts @@ -1,11 +1,11 @@ -import { group, list } from '@keystone-6/core' +import { config, list, group } from '@keystone-6/core' import { allowAll } from '@keystone-6/core/access' import { getContext } from '@keystone-6/core/context' import { integer, text } from '@keystone-6/core/fields' test('errors with nested field groups', () => { expect(() => - getContext({ + getContext(config({ db: { provider: 'sqlite', url: 'file://' @@ -26,16 +26,16 @@ test('errors with nested field groups', () => { }), }, }), - }, + } as any, }), }, - }, {}) + }), {}) ).toThrowErrorMatchingInlineSnapshot(`"groups cannot be nested"`) }) test('errors if you write a group manually differently to the group function', () => { expect(() => - getContext({ + getContext(config({ db: { provider: 'sqlite', url: 'file://' @@ -50,9 +50,9 @@ test('errors if you write a group manually differently to the group function', ( label: 'Group 1', description: null, } as any, - }, + } as any, }), } - }, {}) + }), {}) ).toThrowErrorMatchingInlineSnapshot(`"unexpected value for a group at User.__group0"`) }) diff --git a/tests/api-tests/fields/files.test.ts b/tests/api-tests/fields/files.test.ts index ec0691fd1d4..3018fb6c5ab 100644 --- a/tests/api-tests/fields/files.test.ts +++ b/tests/api-tests/fields/files.test.ts @@ -9,7 +9,7 @@ import Upload from 'graphql-upload/Upload.js' import mime from 'mime' import { file, text } from '@keystone-6/core/fields' import { list } from '@keystone-6/core' -import { type KeystoneConfig, type StorageConfig } from '@keystone-6/core/types' +import type { KeystoneConfigPre, StorageConfig } from '@keystone-6/core/types' import { setupTestRunner } from '@keystone-6/api-tests/test-runner' import { allowAll } from '@keystone-6/core/access' @@ -49,7 +49,7 @@ function getRunner ({ fields, }: { storage: Record - fields: KeystoneConfig['lists'][string]['fields'] + fields: KeystoneConfigPre['lists'][string]['fields'] }) { return setupTestRunner({ config: { diff --git a/tests/api-tests/fields/images.crud.test.disabled.ts b/tests/api-tests/fields/images.crud.test.disabled.ts index f02d684abde..e05e7393df1 100644 --- a/tests/api-tests/fields/images.crud.test.disabled.ts +++ b/tests/api-tests/fields/images.crud.test.disabled.ts @@ -10,7 +10,7 @@ import Upload from 'graphql-upload/Upload.js' import mime from 'mime' import { text, image } from '@keystone-6/core/fields' import { list } from '@keystone-6/core' -import { type KeystoneConfig, type StorageConfig } from '@keystone-6/core/types' +import type { KeystoneConfig, StorageConfig } from '@keystone-6/core/types' import { setupTestRunner } from '@keystone-6/api-tests/test-runner' import { allowAll } from '@keystone-6/core/access' import { expectSingleResolverError } from '../utils' diff --git a/tests/api-tests/fields/non-null.test.ts b/tests/api-tests/fields/non-null.test.ts index 1969ea63a75..8faa8cb1fea 100644 --- a/tests/api-tests/fields/non-null.test.ts +++ b/tests/api-tests/fields/non-null.test.ts @@ -49,37 +49,35 @@ testModules const getSchema = async (fieldConfig: TextFieldConfig) => { const { context } = await setupTestEnv({ - config: { - lists: { - Test: list({ - access: allowAll, - fields: { - name: text(), - testField: mod.typeFunction({ - ...(mod.fieldConfig ? mod.fieldConfig(matrixValue) : {}), - ...fieldConfig, - }), - }, - }), - }, - storage: { - test_image: { - kind: 'local', - type: 'image', - storagePath: fs.mkdtempSync(path.join(os.tmpdir(), 'tmp_test_images')), - generateUrl: path => `http://localhost:3000/images${path}`, - serverRoute: { - path: '/images', - }, + lists: { + Test: list({ + access: allowAll, + fields: { + name: text(), + testField: mod.typeFunction({ + ...(mod.fieldConfig ? mod.fieldConfig(matrixValue) : {}), + ...fieldConfig, + }), + }, + }), + }, + storage: { + test_image: { + kind: 'local', + type: 'image', + storagePath: fs.mkdtempSync(path.join(os.tmpdir(), 'tmp_test_images')), + generateUrl: path => `http://localhost:3000/images${path}`, + serverRoute: { + path: '/images', }, - test_file: { - kind: 'local', - type: 'file', - storagePath: fs.mkdtempSync(path.join(os.tmpdir(), 'tmp_test_files')), - generateUrl: path => `http://localhost:3000/files${path}`, - serverRoute: { - path: '/files', - }, + }, + test_file: { + kind: 'local', + type: 'file', + storagePath: fs.mkdtempSync(path.join(os.tmpdir(), 'tmp_test_files')), + generateUrl: path => `http://localhost:3000/files${path}`, + serverRoute: { + path: '/files', }, }, }, diff --git a/tests/api-tests/fields/types/Virtual.test.ts b/tests/api-tests/fields/types/Virtual.test.ts index 2a5eea2f533..95c780a07d6 100644 --- a/tests/api-tests/fields/types/Virtual.test.ts +++ b/tests/api-tests/fields/types/Virtual.test.ts @@ -161,25 +161,23 @@ describe('Virtual field type', () => { test("errors when a non leaf type is used but the field isn't hidden in the Admin UI and ui.query isn't provided", async () => { await expect( setupTestEnv({ - config: ({ - lists: { - Post: list({ - access: allowAll, - fields: { - virtual: virtual({ - field: graphql.field({ - type: graphql.object()({ - name: 'Something', - fields: { - something: graphql.field({ type: graphql.String }), - }, - }), + lists: { + Post: list({ + access: allowAll, + fields: { + virtual: virtual({ + field: graphql.field({ + type: graphql.object()({ + name: 'Something', + fields: { + something: graphql.field({ type: graphql.String }), + }, }), }), - }, - }), - }, - }), + }), + }, + }), + }, }) ).rejects.toMatchInlineSnapshot(` [Error: The virtual field at Post.virtual requires a selection for the Admin UI but ui.query is unspecified and ui.listView.fieldMode and ui.itemView.fieldMode are not both set to 'hidden'. diff --git a/tests/api-tests/fields/types/document.test.ts b/tests/api-tests/fields/types/document.test.ts index bcf3cf59116..37899ab3236 100644 --- a/tests/api-tests/fields/types/document.test.ts +++ b/tests/api-tests/fields/types/document.test.ts @@ -299,24 +299,22 @@ describe('Document field type', () => { test("an inline relationship to a list that doesn't exist throws an error", async () => { await expect( setupTestEnv({ - config: ({ - lists: { - Post: list({ - access: allowAll, - fields: { - content: document({ - relationships: { - mention: { - listKey: 'Author', - label: 'Mention', - selection: 'id name', - }, + lists: { + Post: list({ + access: allowAll, + fields: { + content: document({ + relationships: { + mention: { + listKey: 'Author', + label: 'Mention', + selection: 'id name', }, - }), - }, - }), - }, - }), + }, + }), + }, + }), + }, }) ).rejects.toMatchInlineSnapshot( `[Error: An inline relationship Mention (mention) in the field at Post.content has listKey set to "Author" but no list named "Author" exists.]` @@ -325,34 +323,32 @@ describe('Document field type', () => { test("an relationship on a component block prop to a list that doesn't exist throws an error", async () => { await expect( setupTestEnv({ - config: ({ - lists: { - Post: list({ - access: allowAll, - fields: { - content: document({ - componentBlocks: { - someBlock: component({ - preview: () => null, - label: 'Some Block', - schema: { - something: fields.object({ - blah: fields.conditional(fields.checkbox({ label: 'Some conditional' }), { - false: fields.empty(), - true: fields.relationship({ - label: 'Some Relationship', - listKey: 'Author', - }), + lists: { + Post: list({ + access: allowAll, + fields: { + content: document({ + componentBlocks: { + someBlock: component({ + preview: () => null, + label: 'Some Block', + schema: { + something: fields.object({ + blah: fields.conditional(fields.checkbox({ label: 'Some conditional' }), { + false: fields.empty(), + true: fields.relationship({ + label: 'Some Relationship', + listKey: 'Author', }), }), - }, - }), - }, - }), - }, - }), - }, - }), + }), + }, + }), + }, + }), + }, + }), + }, }) ).rejects.toMatchInlineSnapshot( `[Error: Component block someBlock in Post.content: The relationship field at "object.something.object.blah.conditional.true" has the listKey "Author" but no list named "Author" exists.]` diff --git a/tests/api-tests/fields/types/fixtures/file/test-fixtures.ts b/tests/api-tests/fields/types/fixtures/file/test-fixtures.ts index 96462ea3472..709feaf4164 100644 --- a/tests/api-tests/fields/types/fixtures/file/test-fixtures.ts +++ b/tests/api-tests/fields/types/fixtures/file/test-fixtures.ts @@ -5,10 +5,10 @@ import fs from 'fs-extra' import Upload from 'graphql-upload/Upload.js' import mime from 'mime' import { file } from '@keystone-6/core/fields' -import { type KeystoneConfig } from '@keystone-6/core/types' +import type { KeystoneConfig } from '@keystone-6/core/types' -export const prepareFile = (_filePath: string) => { - const filePath = path.resolve(`${__dirname}/test-files/${_filePath}`) +export function prepareFile (filePath_: string) { + const filePath = path.resolve(`${__dirname}/test-files/${filePath_}`) const upload = new Upload() upload.resolve({ createReadStream: () => fs.createReadStream(filePath), @@ -27,7 +27,7 @@ if (process.env.S3_BUCKET_NAME) { export const TEMP_STORAGE = fs.mkdtempSync(path.join(os.tmpdir(), 'tmp_test_images')) -export const getRootConfig = (matrixValue: MatrixValue): Partial => { +export function getRootConfig (matrixValue: MatrixValue): Partial { if (matrixValue === 'local') { return { storage: { diff --git a/tests/api-tests/fields/types/fixtures/image/test-fixtures-skip.ts b/tests/api-tests/fields/types/fixtures/image/test-fixtures-skip.ts index 02d551c2619..5a2b1a12653 100644 --- a/tests/api-tests/fields/types/fixtures/image/test-fixtures-skip.ts +++ b/tests/api-tests/fields/types/fixtures/image/test-fixtures-skip.ts @@ -4,11 +4,11 @@ import fs from 'fs-extra' // @ts-expect-error import Upload from 'graphql-upload/Upload.js' import mime from 'mime' -import { type KeystoneConfig } from '@keystone-6/core/types' +import type { KeystoneConfig } from '@keystone-6/core/types' import { image } from '@keystone-6/core/fields' -export const prepareFile = (_filePath: string) => { - const filePath = path.resolve(`${__dirname}/../test-files/${_filePath}`) +export function prepareFile (filePath_: string) { + const filePath = path.resolve(`${__dirname}/../test-files/${filePath_}`) const upload = new Upload() upload.resolve({ createReadStream: () => fs.createReadStream(filePath), @@ -31,7 +31,7 @@ export const fieldConfig = () => ({ storage: 'test_image' }) export const TEMP_STORAGE = fs.mkdtempSync(path.join(os.tmpdir(), 'tmp_test_images')) -export const getRootConfig = (matrixValue: MatrixValue): Partial => { +export function getRootConfig (matrixValue: MatrixValue): Partial { if (matrixValue === 'local') { return { storage: { diff --git a/tests/api-tests/fields/types/relationship.test.ts b/tests/api-tests/fields/types/relationship.test.ts index f42a137b089..af64c249518 100644 --- a/tests/api-tests/fields/types/relationship.test.ts +++ b/tests/api-tests/fields/types/relationship.test.ts @@ -1,5 +1,5 @@ import { assertInputObjectType, printType, assertObjectType, parse } from 'graphql' -import { type KeystoneConfig } from '@keystone-6/core/types' +import type { KeystoneConfigPre } from '@keystone-6/core/types' import { config, list } from '@keystone-6/core' import { text, relationship } from '@keystone-6/core/fields' @@ -135,7 +135,7 @@ describe('Type Generation', () => { }) describe('Reference errors', () => { - function tryf (lists: KeystoneConfig['lists']) { + function tryf (lists: KeystoneConfigPre['lists']) { return createSystem( config({ db: { url: 'file:./thing.db', provider: 'sqlite' }, diff --git a/tests/api-tests/fields/unique.test.ts b/tests/api-tests/fields/unique.test.ts index 240b6942583..95054359759 100644 --- a/tests/api-tests/fields/unique.test.ts +++ b/tests/api-tests/fields/unique.test.ts @@ -150,40 +150,38 @@ for (const modulePath of testModules) { let erroredOut = false try { await setupTestEnv({ - config: ({ - lists: { - Test: list({ - access: allowAll, - fields: { - name: text(), - testField: mod.typeFunction({ - isIndexed: 'unique', - ...(mod.fieldConfig ? mod.fieldConfig(matrixValue) : {}), - }), - }, - }), - }, - storage: { - test_image: { - kind: 'local', - type: 'image', - storagePath: fs.mkdtempSync(path.join(os.tmpdir(), 'tmp_test_images')), - generateUrl: path => `http://localhost:3000/images${path}`, - serverRoute: { - path: '/images', - }, + lists: { + Test: list({ + access: allowAll, + fields: { + name: text(), + testField: mod.typeFunction({ + isIndexed: 'unique', + ...(mod.fieldConfig ? mod.fieldConfig(matrixValue) : {}), + }), }, - test_file: { - kind: 'local', - type: 'file', - storagePath: fs.mkdtempSync(path.join(os.tmpdir(), 'tmp_test_files')), - generateUrl: path => `http://localhost:3000/images${path}`, - serverRoute: { - path: '/images', - }, + }), + }, + storage: { + test_image: { + kind: 'local', + type: 'image', + storagePath: fs.mkdtempSync(path.join(os.tmpdir(), 'tmp_test_images')), + generateUrl: path => `http://localhost:3000/images${path}`, + serverRoute: { + path: '/images', }, }, - }), + test_file: { + kind: 'local', + type: 'file', + storagePath: fs.mkdtempSync(path.join(os.tmpdir(), 'tmp_test_files')), + generateUrl: path => `http://localhost:3000/images${path}`, + serverRoute: { + path: '/images', + }, + }, + }, }) } catch (error: any) { expect(error.message).toMatch( diff --git a/tests/api-tests/fields/unsupported.test.ts b/tests/api-tests/fields/unsupported.test.ts index c15e76e65e7..c5512077023 100644 --- a/tests/api-tests/fields/unsupported.test.ts +++ b/tests/api-tests/fields/unsupported.test.ts @@ -48,31 +48,29 @@ if (unsupportedModules.length > 0) { await expect( async () => await setupTestEnv({ - config: { - lists: { - [listKey]: list({ - access: allowAll, - fields: { name: text(), ...mod.getTestFields(matrixValue) }, - }), - }, - storage: { - test_image: { - kind: 'local', - type: 'image', - storagePath: fs.mkdtempSync(path.join(os.tmpdir(), 'tmp_test_images')), - generateUrl: path => `http://localhost:3000/images${path}`, - serverRoute: { - path: '/images', - }, + lists: { + [listKey]: list({ + access: allowAll, + fields: { name: text(), ...mod.getTestFields(matrixValue) }, + }), + }, + storage: { + test_image: { + kind: 'local', + type: 'image', + storagePath: fs.mkdtempSync(path.join(os.tmpdir(), 'tmp_test_images')), + generateUrl: path => `http://localhost:3000/images${path}`, + serverRoute: { + path: '/images', }, - test_file: { - kind: 'local', - type: 'file', - storagePath: fs.mkdtempSync(path.join(os.tmpdir(), 'tmp_test_files')), - generateUrl: path => `http://localhost:3000/files${path}`, - serverRoute: { - path: '/files', - }, + }, + test_file: { + kind: 'local', + type: 'file', + storagePath: fs.mkdtempSync(path.join(os.tmpdir(), 'tmp_test_files')), + generateUrl: path => `http://localhost:3000/files${path}`, + serverRoute: { + path: '/files', }, }, }, diff --git a/tests/api-tests/indexes.test.ts b/tests/api-tests/indexes.test.ts index ee2a763d878..40051ec051b 100644 --- a/tests/api-tests/indexes.test.ts +++ b/tests/api-tests/indexes.test.ts @@ -6,16 +6,14 @@ import { dbProvider } from './utils' test('isIndexed: true and db.map on a text field generates a valid Prisma schema', async () => { const { artifacts, system } = await setupTestEnv({ - config: { - lists: { - Test: list({ - access: allowAll, - fields: { - somethingIndexed: text({ isIndexed: true, db: { map: 'something' } }), - other: text(), - }, - }), - }, + lists: { + Test: list({ + access: allowAll, + fields: { + somethingIndexed: text({ isIndexed: true, db: { map: 'something' } }), + other: text(), + }, + }), } }) @@ -48,23 +46,21 @@ if (dbProvider === 'postgresql') { // scalar and enum fields are printed slightly differently so that's why we're also testing an enum select field test('isIndexed: true and db.map on an enum select field generates a valid Prisma schema', async () => { const { artifacts, system } = await setupTestEnv({ - config: { - lists: { - Test: list({ - access: allowAll, - fields: { - somethingIndexed: text({ isIndexed: true, db: { map: 'something' } }), - enumSelectIndexed: select({ - type: 'enum', - options: ['a', 'b'], - isIndexed: true, - db: { map: 'enum_select' }, - }), - other: text(), - }, - }), - }, - } + lists: { + Test: list({ + access: allowAll, + fields: { + somethingIndexed: text({ isIndexed: true, db: { map: 'something' } }), + enumSelectIndexed: select({ + type: 'enum', + options: ['a', 'b'], + isIndexed: true, + db: { map: 'enum_select' }, + }), + other: text(), + }, + }), + }, }) expect(artifacts.prisma).toEqual( `// This file is automatically generated by Keystone, do not modify it manually. diff --git a/tests/api-tests/relationships/label-search-field-validation.test.ts b/tests/api-tests/relationships/label-search-field-validation.test.ts index 5ec6f5e6dba..b62327c5296 100644 --- a/tests/api-tests/relationships/label-search-field-validation.test.ts +++ b/tests/api-tests/relationships/label-search-field-validation.test.ts @@ -1,4 +1,4 @@ -import { list } from '@keystone-6/core' +import { config, list } from '@keystone-6/core' import { allowAll } from '@keystone-6/core/access' import { getContext } from '@keystone-6/core/context' import { integer, relationship, text } from '@keystone-6/core/fields' @@ -15,7 +15,7 @@ const Thing = list({ test("labelField that doesn't exist is rejected with displayMode: select", () => { expect(() => getContext( - ({ + config({ db: { provider: 'sqlite', url: 'file://' @@ -35,7 +35,7 @@ test("labelField that doesn't exist is rejected with displayMode: select", () => Thing, }, }), - {} as any + {} ) ).toThrowErrorMatchingInlineSnapshot(`""doesNotExist" is not a field of list "Thing""`) }) @@ -43,7 +43,7 @@ test("labelField that doesn't exist is rejected with displayMode: select", () => test("labelField that doesn't exist is rejected with displayMode: cards", () => { expect(() => getContext( - ({ + config({ db: { provider: 'sqlite', url: 'file://' @@ -65,7 +65,7 @@ test("labelField that doesn't exist is rejected with displayMode: cards", () => Thing, }, }), - {} as any + {} ) ).toThrowErrorMatchingInlineSnapshot(`""doesNotExist" is not a field of list "Thing""`) }) @@ -73,7 +73,7 @@ test("labelField that doesn't exist is rejected with displayMode: cards", () => test("searchFields that don't exist are rejected with displayMode: select", () => { expect(() => getContext( - ({ + config({ db: { provider: 'sqlite', url: 'file://' @@ -93,7 +93,7 @@ test("searchFields that don't exist are rejected with displayMode: select", () = Thing, }, }), - {} as any + {} ) ).toThrowErrorMatchingInlineSnapshot(`""doesNotExist" is not a field of list "Thing""`) }) @@ -101,7 +101,7 @@ test("searchFields that don't exist are rejected with displayMode: select", () = test("searchFields that don't exist are rejected with displayMode: cards", () => { expect(() => getContext( - ({ + config({ db: { provider: 'sqlite', url: 'file://' @@ -123,7 +123,7 @@ test("searchFields that don't exist are rejected with displayMode: cards", () => Thing, }, }), - {} as any + {} ) ).toThrowErrorMatchingInlineSnapshot(`""doesNotExist" is not a field of list "Thing""`) }) diff --git a/tests/api-tests/test-runner.ts b/tests/api-tests/test-runner.ts index 551ac04880f..dcb3815b4c6 100644 --- a/tests/api-tests/test-runner.ts +++ b/tests/api-tests/test-runner.ts @@ -17,6 +17,9 @@ import { objectEnumValues, } from '@prisma/client/runtime/library' +import { + config, +} from '@keystone-6/core' import { createExpressServer, createSystem, @@ -24,10 +27,11 @@ import { withMigrate } from '@keystone-6/core/___internal-do-not-use-will-break-in-patch/artifacts' -import { - type BaseKeystoneTypeInfo, +import type { + BaseKeystoneTypeInfo, + KeystoneConfigPre, } from '@keystone-6/core/types' -import { dbProvider, type FloatingConfig } from './utils' +import { dbProvider } from './utils' // prisma checks { @@ -81,15 +85,15 @@ afterAll(async () => { } }) -export async function setupTestEnv ({ - config: config_, - serve = false, - identifier, -}: { - config: FloatingConfig - serve?: boolean - identifier?: string -}) { +type FloatingConfig = Omit, 'db'> & { + db?: Omit['db'], 'provider' | 'url'> +} + +export async function setupTestEnv ( + config_: FloatingConfig, + serve: boolean = false, + identifier?: string, +) { const random = identifier ?? randomBytes(8).toString('base64url').toLowerCase() const cwd = join(tmpdir(), `ks6-tests-${random}`) await fs.mkdir(cwd) @@ -113,7 +117,7 @@ export async function setupTestEnv ({ dbUrl = parsed.toString() } - const system = createSystem({ + const system = createSystem(config({ ...config_, db: { provider: dbProvider, @@ -134,7 +138,7 @@ export async function setupTestEnv ({ isDisabled: true, ...config_.ui, }, - }) + })) const artifacts = await generateArtifacts(cwd, system) const paths = system.getPaths(cwd) @@ -209,7 +213,7 @@ export function setupTestRunner ({ identifier?: string }) { return (testFn: (args: Awaited>) => Promise) => async () => { - const result = await setupTestEnv({ config: config_, serve, identifier }) + const result = await setupTestEnv(config_, serve, identifier) await result.connect() try { @@ -230,7 +234,7 @@ export function setupTestSuite ({ serve?: boolean identifier?: string }) { - const result = setupTestEnv({ config: config_, serve, identifier }) + const result = setupTestEnv(config_, serve, identifier) const connectPromise = result.then((x) => { x.connect() return x diff --git a/tests/api-tests/utils.ts b/tests/api-tests/utils.ts index 3fff79b654e..53c6905ff2b 100644 --- a/tests/api-tests/utils.ts +++ b/tests/api-tests/utils.ts @@ -1,7 +1,10 @@ import { - type BaseKeystoneTypeInfo, - type KeystoneConfig, - type KeystoneContext + config, +} from '@keystone-6/core' +import type { + BaseKeystoneTypeInfo, + KeystoneContext, + KeystoneConfigPre, } from '@keystone-6/core/types' import { createSystem, @@ -24,20 +27,6 @@ if (workerId === undefined) { throw new Error('expected JEST_WORKER_ID to be set') } -export type FloatingConfig = Omit, 'db'> & { - db?: Omit['db'], 'provider' | 'url'> -} - -export type TypeInfoFromConfig> = Config extends KeystoneConfig< - infer TypeInfo -> - ? TypeInfo - : never - -export type ContextFromConfig> = KeystoneContext< - TypeInfoFromConfig -> - export type ContextFromRunner> = Parameters< Parameters[0] >[0]['context'] @@ -149,7 +138,7 @@ export function expectFilterDenied ( ) } -export function expectResolverError ( +function expectResolverError ( errors: readonly any[] | undefined, args: { path: (string | number)[], messages: string[], debug: any[] }[] ) { @@ -176,10 +165,10 @@ export const expectSingleResolverError = ( }, ]) -export const expectRelationshipError = ( +function expectRelationshipError ( errors: readonly any[] | undefined, args: { path: (string | number)[], messages: string[], debug: any[] }[] -) => { +) { const unpackedErrors = unpackErrors(errors) expect(unpackedErrors).toEqual( args.map(({ path, messages, debug }) => { @@ -189,12 +178,12 @@ export const expectRelationshipError = ( ) } -export const expectSingleRelationshipError = ( +export function expectSingleRelationshipError ( errors: readonly any[] | undefined, path: string, fieldPath: string, message: string -) => +) { expectRelationshipError(errors, [ { path: [path], @@ -202,6 +191,7 @@ export const expectSingleRelationshipError = ( debug: [{ message, stacktrace: expect.stringMatching(new RegExp(`Error: ${message}\n`)) }], }, ]) +} export async function seed[]>> ( context: KeystoneContext, @@ -217,23 +207,17 @@ export async function seed[]>> return results as Record[]> } -export function testConfig (config: FloatingConfig): KeystoneConfig { - return { - ...config, +export async function getPrismaSchema ({ lists }: { lists: KeystoneConfigPre['lists'] }) { + const system = createSystem(config({ + lists, db: { provider: dbProvider, url: '', - ...config.db, }, // default to a disabled UI ui: { isDisabled: true, - ...config.ui }, - } -} - -export async function getPrismaSchema (config: FloatingConfig) { - const system = createSystem(testConfig(config)) + })) return (await getArtifacts(system)).prisma } diff --git a/tests/cli-tests/artifacts.test.ts b/tests/cli-tests/artifacts.test.ts index 76d45faad66..87aa5b29073 100644 --- a/tests/cli-tests/artifacts.test.ts +++ b/tests/cli-tests/artifacts.test.ts @@ -1,5 +1,4 @@ import { ExitError } from '@keystone-6/core/___internal-do-not-use-will-break-in-patch/artifacts' - import { basicKeystoneConfig, getFiles,