Files
payloadcms/packages/payload/src/index.ts
Dan Ribbens 1bf580fac3 feat: join field works with hasMany relationships (#8493)
Join field works on relationships and uploads having `hasMany: true`

---------

Co-authored-by: Sasha <64744993+r1tsuu@users.noreply.github.com>
2024-10-08 11:40:34 -04:00

1083 lines
35 KiB
TypeScript

import type { ExecutionResult, GraphQLSchema, ValidationRule } from 'graphql'
import type { Request as graphQLRequest, OperationArgs } from 'graphql-http'
import type { Logger } from 'pino'
import { spawn } from 'child_process'
import crypto from 'crypto'
import { fileURLToPath } from 'node:url'
import path from 'path'
import type { AuthArgs } from './auth/operations/auth.js'
import type { Result as ForgotPasswordResult } from './auth/operations/forgotPassword.js'
import type { Options as ForgotPasswordOptions } from './auth/operations/local/forgotPassword.js'
import type { Options as LoginOptions } from './auth/operations/local/login.js'
import type { Options as ResetPasswordOptions } from './auth/operations/local/resetPassword.js'
import type { Options as UnlockOptions } from './auth/operations/local/unlock.js'
import type { Options as VerifyEmailOptions } from './auth/operations/local/verifyEmail.js'
import type { Result as LoginResult } from './auth/operations/login.js'
import type { Result as ResetPasswordResult } from './auth/operations/resetPassword.js'
import type { AuthStrategy, User } from './auth/types.js'
import type { ImportMap } from './bin/generateImportMap/index.js'
import type {
BulkOperationResult,
Collection,
DataFromCollectionSlug,
TypeWithID,
} from './collections/config/types.js'
export type * from './admin/types.js'
import type { Options as CountOptions } from './collections/operations/local/count.js'
import type { Options as CreateOptions } from './collections/operations/local/create.js'
import type {
ByIDOptions as DeleteByIDOptions,
ManyOptions as DeleteManyOptions,
Options as DeleteOptions,
} from './collections/operations/local/delete.js'
export type { MappedView } from './admin/views/types.js'
import type { Options as DuplicateOptions } from './collections/operations/local/duplicate.js'
import type { Options as FindOptions } from './collections/operations/local/find.js'
import type { Options as FindByIDOptions } from './collections/operations/local/findByID.js'
import type { Options as FindVersionByIDOptions } from './collections/operations/local/findVersionByID.js'
import type { Options as FindVersionsOptions } from './collections/operations/local/findVersions.js'
import type { Options as RestoreVersionOptions } from './collections/operations/local/restoreVersion.js'
import type {
ByIDOptions as UpdateByIDOptions,
ManyOptions as UpdateManyOptions,
Options as UpdateOptions,
} from './collections/operations/local/update.js'
import type { InitOptions, SanitizedConfig } from './config/types.js'
import type { BaseDatabaseAdapter, PaginatedDocs } from './database/types.js'
import type { InitializedEmailAdapter } from './email/types.js'
import type { DataFromGlobalSlug, Globals } from './globals/config/types.js'
import type { Options as FindGlobalOptions } from './globals/operations/local/findOne.js'
import type { Options as FindGlobalVersionByIDOptions } from './globals/operations/local/findVersionByID.js'
import type { Options as FindGlobalVersionsOptions } from './globals/operations/local/findVersions.js'
import type { Options as RestoreGlobalVersionOptions } from './globals/operations/local/restoreVersion.js'
import type { Options as UpdateGlobalOptions } from './globals/operations/local/update.js'
import type { JsonObject } from './types/index.js'
import type { TraverseFieldsCallback } from './utilities/traverseFields.js'
import type { TypeWithVersion } from './versions/types.js'
import { decrypt, encrypt } from './auth/crypto.js'
import { APIKeyAuthentication } from './auth/strategies/apiKey.js'
import { JWTAuthentication } from './auth/strategies/jwt.js'
import { checkPayloadDependencies } from './checkPayloadDependencies.js'
import localOperations from './collections/operations/local/index.js'
import { consoleEmailAdapter } from './email/consoleEmailAdapter.js'
import { fieldAffectsData } from './fields/config/types.js'
import localGlobalOperations from './globals/operations/local/index.js'
import { getLogger } from './utilities/logger.js'
import { serverInit as serverInitTelemetry } from './utilities/telemetry/events/serverInit.js'
import { traverseFields } from './utilities/traverseFields.js'
export interface GeneratedTypes {
authUntyped: {
[slug: string]: {
forgotPassword: {
email: string
}
login: {
email: string
password: string
}
registerFirstUser: {
email: string
password: string
}
unlock: {
email: string
}
}
}
collectionsUntyped: {
[slug: string]: JsonObject & TypeWithID
}
dbUntyped: {
defaultIDType: number | string
}
globalsUntyped: {
[slug: string]: JsonObject
}
localeUntyped: null | string
userUntyped: User
}
// Helper type to resolve the correct type using conditional types
type ResolveCollectionType<T> = 'collections' extends keyof T
? T['collections']
: // @ts-expect-error
T['collectionsUntyped']
// @ts-expect-error
type ResolveGlobalType<T> = 'globals' extends keyof T ? T['globals'] : T['globalsUntyped']
// Applying helper types to GeneratedTypes
export type TypedCollection = ResolveCollectionType<GeneratedTypes>
export type TypedGlobal = ResolveGlobalType<GeneratedTypes>
// Extract string keys from the type
type StringKeyOf<T> = Extract<keyof T, string>
// Define the types for slugs using the appropriate collections and globals
export type CollectionSlug = StringKeyOf<TypedCollection>
type ResolveDbType<T> = 'db' extends keyof T
? T['db']
: // @ts-expect-error
T['dbUntyped']
export type DefaultDocumentIDType = ResolveDbType<GeneratedTypes>['defaultIDType']
export type GlobalSlug = StringKeyOf<TypedGlobal>
// now for locale and user
// @ts-expect-error
type ResolveLocaleType<T> = 'locale' extends keyof T ? T['locale'] : T['localeUntyped']
// @ts-expect-error
type ResolveUserType<T> = 'user' extends keyof T ? T['user'] : T['userUntyped']
export type TypedLocale = ResolveLocaleType<GeneratedTypes>
export type TypedUser = ResolveUserType<GeneratedTypes>
// @ts-expect-error
type ResolveAuthOperationsType<T> = 'auth' extends keyof T ? T['auth'] : T['authUntyped']
export type TypedAuthOperations = ResolveAuthOperationsType<GeneratedTypes>
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
let checkedDependencies = false
/**
* @description Payload
*/
export class BasePayload {
/**
* @description Authorization and Authentication using headers and cookies to run auth user strategies
* @returns permissions: Permissions
* @returns user: User
*/
auth = async (options: AuthArgs) => {
const { auth } = localOperations.auth
return auth(this, options)
}
authStrategies: AuthStrategy[]
collections: {
[slug: string]: Collection
} = {}
config: SanitizedConfig
/**
* @description Performs count operation
* @param options
* @returns count of documents satisfying query
*/
count = async <T extends CollectionSlug>(
options: CountOptions<T>,
): Promise<{ totalDocs: number }> => {
const { count } = localOperations
return count(this, options)
}
/**
* @description Performs create operation
* @param options
* @returns created document
*/
create = async <TSlug extends CollectionSlug>(
options: CreateOptions<TSlug>,
): Promise<DataFromCollectionSlug<TSlug>> => {
const { create } = localOperations
return create<TSlug>(this, options)
}
db: DatabaseAdapter
decrypt = decrypt
duplicate = async <TSlug extends CollectionSlug>(
options: DuplicateOptions<TSlug>,
): Promise<DataFromCollectionSlug<TSlug>> => {
const { duplicate } = localOperations
return duplicate<TSlug>(this, options)
}
email: InitializedEmailAdapter
encrypt = encrypt
// TODO: re-implement or remove?
// errorHandler: ErrorHandler
extensions: (args: {
args: OperationArgs<any>
req: graphQLRequest<unknown, unknown>
result: ExecutionResult
}) => Promise<any>
/**
* @description Find documents with criteria
* @param options
* @returns documents satisfying query
*/
find = async <TSlug extends CollectionSlug>(
options: FindOptions<TSlug>,
): Promise<PaginatedDocs<DataFromCollectionSlug<TSlug>>> => {
const { find } = localOperations
return find<TSlug>(this, options)
}
/**
* @description Find document by ID
* @param options
* @returns document with specified ID
*/
findByID = async <TOptions extends FindByIDOptions>(
options: TOptions,
): Promise<
TOptions['disableErrors'] extends true
? DataFromCollectionSlug<TOptions['collection']> | null
: DataFromCollectionSlug<TOptions['collection']>
> => {
const { findByID } = localOperations
return findByID<TOptions>(this, options)
}
findGlobal = async <TSlug extends GlobalSlug>(
options: FindGlobalOptions<TSlug>,
): Promise<DataFromGlobalSlug<TSlug>> => {
const { findOne } = localGlobalOperations
return findOne<TSlug>(this, options)
}
/**
* @description Find global version by ID
* @param options
* @returns global version with specified ID
*/
findGlobalVersionByID = async <TSlug extends GlobalSlug>(
options: FindGlobalVersionByIDOptions<TSlug>,
): Promise<TypeWithVersion<DataFromGlobalSlug<TSlug>>> => {
const { findVersionByID } = localGlobalOperations
return findVersionByID<TSlug>(this, options)
}
/**
* @description Find global versions with criteria
* @param options
* @returns versions satisfying query
*/
findGlobalVersions = async <TSlug extends GlobalSlug>(
options: FindGlobalVersionsOptions<TSlug>,
): Promise<PaginatedDocs<TypeWithVersion<DataFromGlobalSlug<TSlug>>>> => {
const { findVersions } = localGlobalOperations
return findVersions<TSlug>(this, options)
}
/**
* @description Find version by ID
* @param options
* @returns version with specified ID
*/
findVersionByID = async <TSlug extends CollectionSlug>(
options: FindVersionByIDOptions<TSlug>,
): Promise<TypeWithVersion<DataFromCollectionSlug<TSlug>>> => {
const { findVersionByID } = localOperations
return findVersionByID<TSlug>(this, options)
}
/**
* @description Find versions with criteria
* @param options
* @returns versions satisfying query
*/
findVersions = async <TSlug extends CollectionSlug>(
options: FindVersionsOptions<TSlug>,
): Promise<PaginatedDocs<TypeWithVersion<DataFromCollectionSlug<TSlug>>>> => {
const { findVersions } = localOperations
return findVersions<TSlug>(this, options)
}
forgotPassword = async <TSlug extends CollectionSlug>(
options: ForgotPasswordOptions<TSlug>,
): Promise<ForgotPasswordResult> => {
const { forgotPassword } = localOperations.auth
return forgotPassword<TSlug>(this, options)
}
getAdminURL = (): string => `${this.config.serverURL}${this.config.routes.admin}`
getAPIURL = (): string => `${this.config.serverURL}${this.config.routes.api}`
globals: Globals
importMap: ImportMap
logger: Logger
login = async <TSlug extends CollectionSlug>(
options: LoginOptions<TSlug>,
): Promise<{ user: DataFromCollectionSlug<TSlug> } & LoginResult> => {
const { login } = localOperations.auth
return login<TSlug>(this, options)
}
resetPassword = async <TSlug extends CollectionSlug>(
options: ResetPasswordOptions<TSlug>,
): Promise<ResetPasswordResult> => {
const { resetPassword } = localOperations.auth
return resetPassword<TSlug>(this, options)
}
/**
* @description Restore global version by ID
* @param options
* @returns version with specified ID
*/
restoreGlobalVersion = async <TSlug extends GlobalSlug>(
options: RestoreGlobalVersionOptions<TSlug>,
): Promise<DataFromGlobalSlug<TSlug>> => {
const { restoreVersion } = localGlobalOperations
return restoreVersion<TSlug>(this, options)
}
/**
* @description Restore version by ID
* @param options
* @returns version with specified ID
*/
restoreVersion = async <TSlug extends CollectionSlug>(
options: RestoreVersionOptions<TSlug>,
): Promise<DataFromCollectionSlug<TSlug>> => {
const { restoreVersion } = localOperations
return restoreVersion<TSlug>(this, options)
}
schema: GraphQLSchema
secret: string
sendEmail: InitializedEmailAdapter['sendEmail']
types: {
arrayTypes: any
blockInputTypes: any
blockTypes: any
fallbackLocaleInputType?: any
groupTypes: any
localeInputType?: any
tabTypes: any
}
unlock = async <TSlug extends CollectionSlug>(
options: UnlockOptions<TSlug>,
): Promise<boolean> => {
const { unlock } = localOperations.auth
return unlock<TSlug>(this, options)
}
updateGlobal = async <TSlug extends GlobalSlug>(
options: UpdateGlobalOptions<TSlug>,
): Promise<DataFromGlobalSlug<TSlug>> => {
const { update } = localGlobalOperations
return update<TSlug>(this, options)
}
validationRules: (args: OperationArgs<any>) => ValidationRule[]
verifyEmail = async <TSlug extends CollectionSlug>(
options: VerifyEmailOptions<TSlug>,
): Promise<boolean> => {
const { verifyEmail } = localOperations.auth
return verifyEmail(this, options)
}
versions: {
[slug: string]: any // TODO: Type this
} = {}
async bin({
args,
cwd,
log,
}: {
args: string[]
cwd?: string
log?: boolean
}): Promise<{ code: number }> {
return new Promise((resolve, reject) => {
const spawned = spawn('node', [path.resolve(dirname, '../bin.js'), ...args], {
cwd,
stdio: log || log === undefined ? 'inherit' : 'ignore',
})
spawned.on('exit', (code) => {
resolve({ code })
})
spawned.on('error', (error) => {
reject(error)
})
})
}
/**
* @description delete one or more documents
* @param options
* @returns Updated document(s)
*/
delete<TSlug extends CollectionSlug>(
options: DeleteByIDOptions<TSlug>,
): Promise<DataFromCollectionSlug<TSlug>>
delete<TSlug extends CollectionSlug>(
options: DeleteManyOptions<TSlug>,
): Promise<BulkOperationResult<TSlug>>
delete<TSlug extends CollectionSlug>(
options: DeleteOptions<TSlug>,
): Promise<BulkOperationResult<TSlug> | DataFromCollectionSlug<TSlug>> {
const { deleteLocal } = localOperations
return deleteLocal<TSlug>(this, options)
}
/**
* @description Initializes Payload
* @param options
*/
async init(options: InitOptions): Promise<Payload> {
if (
process.env.NODE_ENV !== 'production' &&
process.env.PAYLOAD_DISABLE_DEPENDENCY_CHECKER !== 'true' &&
!checkedDependencies
) {
checkedDependencies = true
await checkPayloadDependencies()
}
this.importMap = options.importMap
if (!options?.config) {
throw new Error('Error: the payload config is required to initialize payload.')
}
this.config = await options.config
this.logger = getLogger('payload', this.config.logger)
if (!this.config.secret) {
throw new Error('Error: missing secret key. A secret key is needed to secure Payload.')
}
this.secret = crypto.createHash('sha256').update(this.config.secret).digest('hex').slice(0, 32)
this.globals = {
config: this.config.globals,
}
this.config.collections.forEach((collection) => {
let customIDType = undefined
const findCustomID: TraverseFieldsCallback = ({ field, next }) => {
if (['array', 'blocks'].includes(field.type)) {
next()
return
}
if (!fieldAffectsData(field)) {
return
}
if (field.name === 'id') {
customIDType = field.type
return true
}
}
traverseFields({ callback: findCustomID, fields: collection.fields })
this.collections[collection.slug] = {
config: collection,
customIDType,
}
})
// Generate types on startup
if (process.env.NODE_ENV !== 'production' && this.config.typescript.autoGenerate !== false) {
// We cannot run it directly here, as generate-types imports json-schema-to-typescript, which breaks on turbopack.
// see: https://github.com/vercel/next.js/issues/66723
void this.bin({
args: ['generate:types'],
log: false,
})
}
this.db = this.config.db.init({ payload: this })
this.db.payload = this
if (this.db?.init) {
await this.db.init()
}
if (!options.disableDBConnect && this.db.connect) {
await this.db.connect()
}
// Load email adapter
if (this.config.email instanceof Promise) {
const awaitedAdapter = await this.config.email
this.email = awaitedAdapter({ payload: this })
} else if (this.config.email) {
this.email = this.config.email({ payload: this })
} else {
if (process.env.NEXT_PHASE !== 'phase-production-build') {
this.logger.warn(
`No email adapter provided. Email will be written to console. More info at https://payloadcms.com/docs/email/overview.`,
)
}
this.email = consoleEmailAdapter({ payload: this })
}
// Warn if image resizing is enabled but sharp is not installed
if (
!this.config.sharp &&
this.config.collections.some((c) => c.upload.imageSizes || c.upload.formatOptions)
) {
this.logger.warn(
`Image resizing is enabled for one or more collections, but sharp not installed. Please install 'sharp' and pass into the config.`,
)
}
this.sendEmail = this.email['sendEmail']
serverInitTelemetry(this)
// 1. loop over collections, if collection has auth strategy, initialize and push to array
let jwtStrategyEnabled = false
this.authStrategies = this.config.collections.reduce((authStrategies, collection) => {
if (collection?.auth) {
if (collection.auth.strategies.length > 0) {
authStrategies.push(...collection.auth.strategies)
}
// 2. if api key enabled, push api key strategy into the array
if (collection.auth?.useAPIKey) {
authStrategies.push({
name: `${collection.slug}-api-key`,
authenticate: APIKeyAuthentication(collection),
})
}
// 3. if localStrategy flag is true
if (!collection.auth.disableLocalStrategy && !jwtStrategyEnabled) {
jwtStrategyEnabled = true
}
}
return authStrategies
}, [] as AuthStrategy[])
// 4. if enabled, push jwt strategy into authStrategies last
if (jwtStrategyEnabled) {
this.authStrategies.push({
name: 'local-jwt',
authenticate: JWTAuthentication,
})
}
if (!options.disableOnInit) {
if (typeof options.onInit === 'function') {
await options.onInit(this)
}
if (typeof this.config.onInit === 'function') {
await this.config.onInit(this)
}
}
return this
}
update<TSlug extends CollectionSlug>(
options: UpdateManyOptions<TSlug>,
): Promise<BulkOperationResult<TSlug>>
/**
* @description Update one or more documents
* @param options
* @returns Updated document(s)
*/
update<TSlug extends CollectionSlug>(
options: UpdateByIDOptions<TSlug>,
): Promise<DataFromCollectionSlug<TSlug>>
update<TSlug extends CollectionSlug>(
options: UpdateOptions<TSlug>,
): Promise<BulkOperationResult<TSlug> | DataFromCollectionSlug<TSlug>> {
const { update } = localOperations
return update<TSlug>(this, options)
}
}
const initialized = new BasePayload()
export default initialized
let cached = global._payload
if (!cached) {
cached = global._payload = { payload: null, promise: null }
}
export const getPayload = async (options: InitOptions): Promise<BasePayload> => {
if (!options?.config) {
throw new Error('Error: the payload config is required for getPayload to work.')
}
if (cached.payload) {
return cached.payload
}
if (!cached.promise) {
cached.promise = new BasePayload().init(options)
}
try {
cached.payload = await cached.promise
} catch (e) {
cached.promise = null
throw e
}
return cached.payload
}
type Payload = BasePayload
interface RequestContext {
[key: string]: unknown
}
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface DatabaseAdapter extends BaseDatabaseAdapter {}
export type { Payload, RequestContext }
export { default as executeAccess } from './auth/executeAccess.js'
export { executeAuthStrategies } from './auth/executeAuthStrategies.js'
export { getAccessResults } from './auth/getAccessResults.js'
export { getFieldsToSign } from './auth/getFieldsToSign.js'
export * from './auth/index.js'
export { accessOperation } from './auth/operations/access.js'
export { forgotPasswordOperation } from './auth/operations/forgotPassword.js'
export { initOperation } from './auth/operations/init.js'
export { loginOperation } from './auth/operations/login.js'
export { logoutOperation } from './auth/operations/logout.js'
export type { MeOperationResult } from './auth/operations/me.js'
export { meOperation } from './auth/operations/me.js'
export { refreshOperation } from './auth/operations/refresh.js'
export { registerFirstUserOperation } from './auth/operations/registerFirstUser.js'
export { resetPasswordOperation } from './auth/operations/resetPassword.js'
export { unlockOperation } from './auth/operations/unlock.js'
export { verifyEmailOperation } from './auth/operations/verifyEmail.js'
export type {
AuthStrategyFunction,
AuthStrategyFunctionArgs,
CollectionPermission,
DocumentPermissions,
FieldPermissions,
GlobalPermission,
IncomingAuthType,
Permission,
Permissions,
User,
VerifyConfig,
} from './auth/types.js'
export { generateImportMap } from './bin/generateImportMap/index.js'
export type { ImportMap } from './bin/generateImportMap/index.js'
export { genImportMapIterateFields } from './bin/generateImportMap/iterateFields.js'
export type { ClientCollectionConfig } from './collections/config/client.js'
export type {
ServerOnlyCollectionAdminProperties,
ServerOnlyCollectionProperties,
ServerOnlyUploadProperties,
} from './collections/config/client.js'
export type {
AfterChangeHook as CollectionAfterChangeHook,
AfterDeleteHook as CollectionAfterDeleteHook,
AfterErrorHook as CollectionAfterErrorHook,
AfterForgotPasswordHook as CollectionAfterForgotPasswordHook,
AfterLoginHook as CollectionAfterLoginHook,
AfterLogoutHook as CollectionAfterLogoutHook,
AfterMeHook as CollectionAfterMeHook,
AfterOperationHook as CollectionAfterOperationHook,
AfterReadHook as CollectionAfterReadHook,
AfterRefreshHook as CollectionAfterRefreshHook,
AuthCollection,
AuthOperationsFromCollectionSlug,
BeforeChangeHook as CollectionBeforeChangeHook,
BeforeDeleteHook as CollectionBeforeDeleteHook,
BeforeLoginHook as CollectionBeforeLoginHook,
BeforeOperationHook as CollectionBeforeOperationHook,
BeforeReadHook as CollectionBeforeReadHook,
BeforeValidateHook as CollectionBeforeValidateHook,
BulkOperationResult,
Collection,
CollectionAdminOptions,
CollectionConfig,
DataFromCollectionSlug,
HookOperationType,
MeHook as CollectionMeHook,
RefreshHook as CollectionRefreshHook,
RequiredDataFromCollection,
RequiredDataFromCollectionSlug,
SanitizedCollectionConfig,
SanitizedJoins,
TypeWithID,
TypeWithTimestamps,
} from './collections/config/types.js'
export { createDataloaderCacheKey, getDataLoader } from './collections/dataloader.js'
export { countOperation } from './collections/operations/count.js'
export { createOperation } from './collections/operations/create.js'
export { deleteOperation } from './collections/operations/delete.js'
export { deleteByIDOperation } from './collections/operations/deleteByID.js'
export { docAccessOperation } from './collections/operations/docAccess.js'
export { duplicateOperation } from './collections/operations/duplicate.js'
export { findOperation } from './collections/operations/find.js'
export { findByIDOperation } from './collections/operations/findByID.js'
export { findVersionByIDOperation } from './collections/operations/findVersionByID.js'
export { findVersionsOperation } from './collections/operations/findVersions.js'
export { restoreVersionOperation } from './collections/operations/restoreVersion.js'
export { updateOperation } from './collections/operations/update.js'
export { updateByIDOperation } from './collections/operations/updateByID.js'
export { buildConfig } from './config/build.js'
export type { ClientConfig } from './config/client.js'
export { serverOnlyConfigProperties } from './config/client.js'
export { defaults } from './config/defaults.js'
export { sanitizeConfig } from './config/sanitize.js'
export type * from './config/types.js'
export { combineQueries } from './database/combineQueries.js'
export { createDatabaseAdapter } from './database/createDatabaseAdapter.js'
export { defaultBeginTransaction } from './database/defaultBeginTransaction.js'
export { default as flattenWhereToOperators } from './database/flattenWhereToOperators.js'
export { getLocalizedPaths } from './database/getLocalizedPaths.js'
export { createMigration } from './database/migrations/createMigration.js'
export { getMigrations } from './database/migrations/getMigrations.js'
export { getPredefinedMigration } from './database/migrations/getPredefinedMigration.js'
export { migrate } from './database/migrations/migrate.js'
export { migrateDown } from './database/migrations/migrateDown.js'
export { migrateRefresh } from './database/migrations/migrateRefresh.js'
export { migrateReset } from './database/migrations/migrateReset.js'
export { migrateStatus } from './database/migrations/migrateStatus.js'
export { migrationsCollection } from './database/migrations/migrationsCollection.js'
export { migrationTemplate } from './database/migrations/migrationTemplate.js'
export { readMigrationFiles } from './database/migrations/readMigrationFiles.js'
export { writeMigrationIndex } from './database/migrations/writeMigrationIndex.js'
export type * from './database/queryValidation/types.js'
export type { EntityPolicies, PathToQuery } from './database/queryValidation/types.js'
export { validateQueryPaths } from './database/queryValidation/validateQueryPaths.js'
export { validateSearchParam } from './database/queryValidation/validateSearchParams.js'
export type {
BaseDatabaseAdapter,
BeginTransaction,
CommitTransaction,
Connect,
Count,
CountArgs,
Create,
CreateArgs,
CreateGlobal,
CreateGlobalArgs,
CreateGlobalVersion,
CreateGlobalVersionArgs,
CreateMigration,
CreateVersion,
CreateVersionArgs,
DatabaseAdapterResult as DatabaseAdapterObj,
DBIdentifierName,
DeleteMany,
DeleteManyArgs,
DeleteOne,
DeleteOneArgs,
DeleteVersions,
DeleteVersionsArgs,
Destroy,
Find,
FindArgs,
FindGlobal,
FindGlobalArgs,
FindGlobalVersions,
FindGlobalVersionsArgs,
FindOne,
FindOneArgs,
FindVersions,
FindVersionsArgs,
Init,
Migration,
MigrationData,
MigrationTemplateArgs,
PaginatedDocs,
QueryDrafts,
QueryDraftsArgs,
RollbackTransaction,
Transaction,
UpdateGlobal,
UpdateGlobalArgs,
UpdateGlobalVersion,
UpdateGlobalVersionArgs,
UpdateOne,
UpdateOneArgs,
UpdateVersion,
UpdateVersionArgs,
Upsert,
} from './database/types.js'
export type { EmailAdapter as PayloadEmailAdapter, SendEmailOptions } from './email/types.js'
export {
APIError,
APIErrorName,
AuthenticationError,
DuplicateCollection,
DuplicateFieldName,
DuplicateGlobal,
ErrorDeletingFile,
FileRetrievalError,
FileUploadError,
Forbidden,
InvalidConfiguration,
InvalidFieldName,
InvalidFieldRelationship,
Locked,
LockedAuth,
MissingCollectionLabel,
MissingEditorProp,
MissingFieldInputOptions,
MissingFieldType,
MissingFile,
NotFound,
QueryError,
ValidationError,
ValidationErrorName,
} from './errors/index.js'
export { baseBlockFields } from './fields/baseFields/baseBlockFields.js'
export { baseIDField } from './fields/baseFields/baseIDField.js'
export type { ServerOnlyFieldProperties } from './fields/config/client.js'
export type { ServerOnlyFieldAdminProperties } from './fields/config/client.js'
export { sanitizeFields } from './fields/config/sanitize.js'
export type {
AdminClient,
ArrayField,
ArrayFieldClient,
BaseValidateOptions,
Block,
BlocksField,
BlocksFieldClient,
CheckboxField,
CheckboxFieldClient,
ClientBlock,
ClientField,
CodeField,
CodeFieldClient,
CollapsibleField,
CollapsibleFieldClient,
Condition,
DateField,
DateFieldClient,
EmailField,
EmailFieldClient,
Field,
FieldAccess,
FieldAffectingData,
FieldAffectingDataClient,
FieldBase,
FieldBaseClient,
FieldHook,
FieldHookArgs,
FieldPresentationalOnly,
FieldPresentationalOnlyClient,
FieldTypes,
FieldWithMany,
FieldWithManyClient,
FieldWithMaxDepth,
FieldWithMaxDepthClient,
FieldWithPath,
FieldWithPathClient,
FieldWithSubFields,
FieldWithSubFieldsClient,
FilterOptions,
FilterOptionsProps,
GroupField,
GroupFieldClient,
HookName,
JoinField,
JoinFieldClient,
JSONField,
JSONFieldClient,
Labels,
LabelsClient,
NamedTab,
NonPresentationalField,
NonPresentationalFieldClient,
NumberField,
NumberFieldClient,
Option,
OptionObject,
PointField,
PointFieldClient,
PolymorphicRelationshipField,
PolymorphicRelationshipFieldClient,
RadioField,
RadioFieldClient,
RelationshipField,
RelationshipFieldClient,
RelationshipValue,
RichTextField,
RichTextFieldClient,
RowField,
RowFieldClient,
SelectField,
SelectFieldClient,
SingleRelationshipField,
SingleRelationshipFieldClient,
Tab,
TabAsField,
TabAsFieldClient,
TabsField,
TabsFieldClient,
TextareaField,
TextareaFieldClient,
TextField,
TextFieldClient,
UIField,
UIFieldClient,
UnnamedTab,
UploadField,
UploadFieldClient,
Validate,
ValidateOptions,
ValueWithRelation,
} from './fields/config/types.js'
export { getDefaultValue } from './fields/getDefaultValue.js'
export { traverseFields as afterChangeTraverseFields } from './fields/hooks/afterChange/traverseFields.js'
export { promise as afterReadPromise } from './fields/hooks/afterRead/promise.js'
export { traverseFields as afterReadTraverseFields } from './fields/hooks/afterRead/traverseFields.js'
export { traverseFields as beforeChangeTraverseFields } from './fields/hooks/beforeChange/traverseFields.js'
export { traverseFields as beforeValidateTraverseFields } from './fields/hooks/beforeValidate/traverseFields.js'
export { default as sortableFieldTypes } from './fields/sortableFieldTypes.js'
export type {
ArrayFieldValidation,
BlocksFieldValidation,
CheckboxFieldValidation,
CodeFieldValidation,
ConfirmPasswordFieldValidation,
DateFieldValidation,
EmailFieldValidation,
JSONFieldValidation,
NumberFieldManyValidation,
NumberFieldSingleValidation,
NumberFieldValidation,
PasswordFieldValidation,
PointFieldValidation,
RadioFieldValidation,
RelationshipFieldManyValidation,
RelationshipFieldSingleValidation,
RelationshipFieldValidation,
RichTextFieldValidation,
SelectFieldManyValidation,
SelectFieldSingleValidation,
SelectFieldValidation,
TextareaFieldValidation,
TextFieldManyValidation,
TextFieldSingleValidation,
TextFieldValidation,
UploadFieldManyValidation,
UploadFieldSingleValidation,
UploadFieldValidation,
UsernameFieldValidation,
} from './fields/validations.js'
export type { ClientGlobalConfig } from './globals/config/client.js'
export type {
ServerOnlyGlobalAdminProperties,
ServerOnlyGlobalProperties,
} from './globals/config/client.js'
export type {
AfterChangeHook as GlobalAfterChangeHook,
AfterReadHook as GlobalAfterReadHook,
BeforeChangeHook as GlobalBeforeChangeHook,
BeforeReadHook as GlobalBeforeReadHook,
BeforeValidateHook as GlobalBeforeValidateHook,
DataFromGlobalSlug,
GlobalAdminOptions,
GlobalConfig,
SanitizedGlobalConfig,
} from './globals/config/types.js'
export { docAccessOperation as docAccessOperationGlobal } from './globals/operations/docAccess.js'
export { findOneOperation } from './globals/operations/findOne.js'
export { findVersionByIDOperation as findVersionByIDOperationGlobal } from './globals/operations/findVersionByID.js'
export { findVersionsOperation as findVersionsOperationGlobal } from './globals/operations/findVersions.js'
export { restoreVersionOperation as restoreVersionOperationGlobal } from './globals/operations/restoreVersion.js'
export { updateOperation as updateOperationGlobal } from './globals/operations/update.js'
export type {
CollapsedPreferences,
DocumentPreferences,
FieldsPreferences,
InsideFieldsPreferences,
PreferenceRequest,
PreferenceUpdateRequest,
TabsPreferences,
} from './preferences/types.js'
export { getLocalI18n } from './translations/getLocalI18n.js'
export * from './types/index.js'
export { getFileByPath } from './uploads/getFileByPath.js'
export type * from './uploads/types.js'
export { commitTransaction } from './utilities/commitTransaction.js'
export {
configToJSONSchema,
entityToJSONSchema,
fieldsToJSONSchema,
withNullableJSONSchemaType,
} from './utilities/configToJSONSchema.js'
export { createArrayFromCommaDelineated } from './utilities/createArrayFromCommaDelineated.js'
export { createLocalReq } from './utilities/createLocalReq.js'
export {
deepCopyObject,
deepCopyObjectComplex,
deepCopyObjectSimple,
} from './utilities/deepCopyObject.js'
export {
deepMerge,
deepMergeWithCombinedArrays,
deepMergeWithReactComponents,
deepMergeWithSourceArrays,
} from './utilities/deepMerge.js'
export {
checkDependencies,
type CustomVersionParser,
} from './utilities/dependencies/dependencyChecker.js'
export { getDependencies } from './utilities/dependencies/getDependencies.js'
export {
findUp,
findUpSync,
pathExistsAndIsAccessible,
pathExistsAndIsAccessibleSync,
} from './utilities/findUp.js'
export { default as flattenTopLevelFields } from './utilities/flattenTopLevelFields.js'
export { formatLabels, formatNames, toWords } from './utilities/formatLabels.js'
export { getCollectionIDFieldTypes } from './utilities/getCollectionIDFieldTypes.js'
export { getObjectDotNotation } from './utilities/getObjectDotNotation.js'
export { initTransaction } from './utilities/initTransaction.js'
export { isEntityHidden } from './utilities/isEntityHidden.js'
export { default as isolateObjectProperty } from './utilities/isolateObjectProperty.js'
export { isPlainObject } from './utilities/isPlainObject.js'
export { isValidID } from './utilities/isValidID.js'
export { killTransaction } from './utilities/killTransaction.js'
export { mapAsync } from './utilities/mapAsync.js'
export { mergeListSearchAndWhere } from './utilities/mergeListSearchAndWhere.js'
export { traverseFields } from './utilities/traverseFields.js'
export type { TraverseFieldsCallback } from './utilities/traverseFields.js'
export { buildVersionCollectionFields } from './versions/buildCollectionFields.js'
export { buildVersionGlobalFields } from './versions/buildGlobalFields.js'
export { versionDefaults } from './versions/defaults.js'
export { deleteCollectionVersions } from './versions/deleteCollectionVersions.js'
export { enforceMaxVersions } from './versions/enforceMaxVersions.js'
export { getLatestCollectionVersion } from './versions/getLatestCollectionVersion.js'
export { getLatestGlobalVersion } from './versions/getLatestGlobalVersion.js'
export { saveVersion } from './versions/saveVersion.js'
export type { TypeWithVersion } from './versions/types.js'
export { deepMergeSimple } from '@payloadcms/translations/utilities'