Skip to content

Commit

Permalink
fix!: improve collection / global slugs type-safety in various places (
Browse files Browse the repository at this point in the history
…#8311)

**BREAKING:**
Improves type-safety of collection / global slugs by using `CollectionSlug` / `UploadCollectionSlug` and `GlobalSlug` types instead of `string` in these places:
Adds `UploadCollectionSlug` and `TypedUploadCollection` utility types

This also changes how we suggest to add an upload collection to a cloud-storage adapter:
Before:
```ts
azureStorage({
  collections: {
    [Media.slug]: true,
  },
}) 
``` 

After:
```ts
azureStorage({
  collections: {
    media: true,
  },
}) 
```
  • Loading branch information
r1tsuu authored Nov 15, 2024
1 parent a5cae07 commit 810c29b
Show file tree
Hide file tree
Showing 26 changed files with 92 additions and 65 deletions.
4 changes: 2 additions & 2 deletions docs/migration-guide/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,7 @@ import { s3Adapter } from '@payloadcms/plugin-cloud-storage/s3'
plugins: [
cloudStorage({
collections: {
[mediaSlug]: {
media: {
adapter: s3Adapter({
bucket: process.env.S3_BUCKET,
config: {
Expand All @@ -707,7 +707,7 @@ plugins: [
plugins: [
s3Storage({
collections: {
[mediaSlug]: true,
media: true,
},
bucket: process.env.S3_BUCKET,
config: {
Expand Down
18 changes: 9 additions & 9 deletions docs/upload/storage-adapters.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ export default buildConfig({
enabled: true, // Optional, defaults to true
// Specify which collections should use Vercel Blob
collections: {
[Media.slug]: true,
[MediaWithPrefix.slug]: {
media: true,
'media-with-prefix': {
prefix: 'my-prefix',
},
},
Expand Down Expand Up @@ -90,8 +90,8 @@ export default buildConfig({
plugins: [
s3Storage({
collections: {
[mediaSlug]: true,
[mediaWithPrefixSlug]: {
media: true,
'media-with-prefix': {
prefix,
},
},
Expand Down Expand Up @@ -137,8 +137,8 @@ export default buildConfig({
plugins: [
azureStorage({
collections: {
[mediaSlug]: true,
[mediaWithPrefixSlug]: {
media: true,
'media-with-prefix': {
prefix,
},
},
Expand Down Expand Up @@ -186,8 +186,8 @@ export default buildConfig({
plugins: [
gcsStorage({
collections: {
[mediaSlug]: true,
[mediaWithPrefixSlug]: {
media: true,
'media-with-prefix': {
prefix,
},
},
Expand Down Expand Up @@ -233,7 +233,7 @@ export default buildConfig({
plugins: [
uploadthingStorage({
collections: {
[mediaSlug]: true,
media: true,
},
options: {
token: process.env.UPLOADTHING_TOKEN,
Expand Down
2 changes: 1 addition & 1 deletion packages/create-payload-app/src/lib/replacements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const vercelBlobStorageReplacement: StorageAdapterReplacement = {
configReplacement: [
' vercelBlobStorage({',
' collections: {',
' [Media.slug]: true,',
' media: true,',
' },',
" token: process.env.BLOB_READ_WRITE_TOKEN || '',",
' }),',
Expand Down
11 changes: 9 additions & 2 deletions packages/payload-cloud/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import type { CollectionConfig, Config, FileData, PayloadRequest, TypeWithID } from 'payload'
import type {
CollectionConfig,
Config,
FileData,
PayloadRequest,
TypeWithID,
UploadCollectionSlug,
} from 'payload'

export interface File {
buffer: Buffer
Expand Down Expand Up @@ -94,7 +101,7 @@ export interface PluginOptions {
/**
* Caching configuration per-collection
*/
collections?: Record<string, CollectionCachingConfig>
collections?: Partial<Record<UploadCollectionSlug, CollectionCachingConfig>>
/** Caching in seconds override for all collections
* @default 86400 (24 hours)
*/
Expand Down
6 changes: 3 additions & 3 deletions packages/payload/src/auth/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { DeepRequired } from 'ts-essentials'

import type { Payload } from '../index.js'
import type { CollectionSlug, GlobalSlug, Payload } from '../index.js'
import type { PayloadRequest, Where } from '../types/index.js'

export type Permission = {
Expand Down Expand Up @@ -54,10 +54,10 @@ export type DocumentPermissions = CollectionPermission | GlobalPermission
export type Permissions = {
canAccessAdmin: boolean
collections: {
[collectionSlug: string]: CollectionPermission
[collectionSlug: CollectionSlug]: CollectionPermission
}
globals?: {
[globalSlug: string]: GlobalPermission
[globalSlug: GlobalSlug]: GlobalPermission
}
}

Expand Down
3 changes: 2 additions & 1 deletion packages/payload/src/collections/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -520,11 +520,12 @@ export type SanitizedJoins = {
export interface SanitizedCollectionConfig
extends Omit<
DeepRequired<CollectionConfig>,
'auth' | 'endpoints' | 'fields' | 'upload' | 'versions'
'auth' | 'endpoints' | 'fields' | 'slug' | 'upload' | 'versions'
> {
auth: Auth
endpoints: Endpoint[] | false
fields: Field[]
slug: CollectionSlug
/**
* Object of collections to join 'Join Fields object keyed by collection
*/
Expand Down
33 changes: 17 additions & 16 deletions packages/payload/src/database/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { TypeWithID } from '../collections/config/types.js'
import type { CollectionSlug, GlobalSlug } from '../index.js'
import type {
Document,
JoinQuery,
Expand Down Expand Up @@ -185,7 +186,7 @@ export type RollbackTransaction = (id: number | Promise<number | string> | strin
export type CommitTransaction = (id: number | Promise<number | string> | string) => Promise<void>

export type QueryDraftsArgs = {
collection: string
collection: CollectionSlug
joins?: JoinQuery
limit?: number
locale?: string
Expand All @@ -200,7 +201,7 @@ export type QueryDraftsArgs = {
export type QueryDrafts = <T = TypeWithID>(args: QueryDraftsArgs) => Promise<PaginatedDocs<T>>

export type FindOneArgs = {
collection: string
collection: CollectionSlug
joins?: JoinQuery
locale?: string
req: PayloadRequest
Expand All @@ -211,7 +212,7 @@ export type FindOneArgs = {
export type FindOne = <T extends TypeWithID>(args: FindOneArgs) => Promise<null | T>

export type FindArgs = {
collection: string
collection: CollectionSlug
joins?: JoinQuery
/** Setting limit to 1 is equal to the previous Model.findOne(). Setting limit to 0 disables the limit */
limit?: number
Expand All @@ -230,7 +231,7 @@ export type FindArgs = {
export type Find = <T = TypeWithID>(args: FindArgs) => Promise<PaginatedDocs<T>>

export type CountArgs = {
collection: string
collection: CollectionSlug
locale?: string
req: PayloadRequest
where?: Where
Expand Down Expand Up @@ -263,15 +264,15 @@ type BaseVersionArgs = {
}

export type FindVersionsArgs = {
collection: string
collection: CollectionSlug
} & BaseVersionArgs

export type FindVersions = <T = TypeWithID>(
args: FindVersionsArgs,
) => Promise<PaginatedDocs<TypeWithVersion<T>>>

export type FindGlobalVersionsArgs = {
global: string
global: GlobalSlug
} & BaseVersionArgs

export type FindGlobalArgs = {
Expand All @@ -283,7 +284,7 @@ export type FindGlobalArgs = {
}

export type UpdateGlobalVersionArgs<T = TypeWithID> = {
global: string
global: GlobalSlug
locale?: string
/**
* Additional database adapter specific options to pass to the query
Expand Down Expand Up @@ -340,7 +341,7 @@ export type FindGlobalVersions = <T = TypeWithID>(
) => Promise<PaginatedDocs<TypeWithVersion<T>>>

export type DeleteVersionsArgs = {
collection: string
collection: CollectionSlug
locale?: string
req: PayloadRequest
sort?: {
Expand All @@ -351,7 +352,7 @@ export type DeleteVersionsArgs = {

export type CreateVersionArgs<T = TypeWithID> = {
autosave: boolean
collectionSlug: string
collectionSlug: CollectionSlug
createdAt: string
/** ID of the parent document for which the version should be created for */
parent: number | string
Expand All @@ -370,7 +371,7 @@ export type CreateVersion = <T extends TypeWithID = TypeWithID>(
export type CreateGlobalVersionArgs<T = TypeWithID> = {
autosave: boolean
createdAt: string
globalSlug: string
globalSlug: GlobalSlug
/** ID of the parent document for which the version should be created for */
parent: number | string
publishedLocale?: string
Expand All @@ -388,7 +389,7 @@ export type CreateGlobalVersion = <T extends TypeWithID = TypeWithID>(
export type DeleteVersions = (args: DeleteVersionsArgs) => Promise<void>

export type UpdateVersionArgs<T = TypeWithID> = {
collection: string
collection: CollectionSlug
locale?: string
/**
* Additional database adapter specific options to pass to the query
Expand All @@ -413,7 +414,7 @@ export type UpdateVersion = <T extends TypeWithID = TypeWithID>(
) => Promise<TypeWithVersion<T>>

export type CreateArgs = {
collection: string
collection: CollectionSlug
data: Record<string, unknown>
draft?: boolean
locale?: string
Expand All @@ -424,7 +425,7 @@ export type CreateArgs = {
export type Create = (args: CreateArgs) => Promise<Document>

export type UpdateOneArgs = {
collection: string
collection: CollectionSlug
data: Record<string, unknown>
draft?: boolean
joins?: JoinQuery
Expand All @@ -449,7 +450,7 @@ export type UpdateOneArgs = {
export type UpdateOne = (args: UpdateOneArgs) => Promise<Document>

export type UpsertArgs = {
collection: string
collection: CollectionSlug
data: Record<string, unknown>
joins?: JoinQuery
locale?: string
Expand All @@ -461,7 +462,7 @@ export type UpsertArgs = {
export type Upsert = (args: UpsertArgs) => Promise<Document>

export type DeleteOneArgs = {
collection: string
collection: CollectionSlug
joins?: JoinQuery
req: PayloadRequest
select?: SelectType
Expand All @@ -471,7 +472,7 @@ export type DeleteOneArgs = {
export type DeleteOne = (args: DeleteOneArgs) => Promise<Document>

export type DeleteManyArgs = {
collection: string
collection: CollectionSlug
joins?: JoinQuery
req: PayloadRequest
where: Where
Expand Down
3 changes: 2 additions & 1 deletion packages/payload/src/globals/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,10 @@ export type GlobalConfig = {
}

export interface SanitizedGlobalConfig
extends Omit<DeepRequired<GlobalConfig>, 'endpoints' | 'fields' | 'versions'> {
extends Omit<DeepRequired<GlobalConfig>, 'endpoints' | 'fields' | 'slug' | 'versions'> {
endpoints: Endpoint[] | false
fields: Field[]
slug: GlobalSlug
versions: SanitizedGlobalVersions
}

Expand Down
16 changes: 15 additions & 1 deletion packages/payload/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import type {
} from './collections/config/types.js'
export type { FieldState } from './admin/forms/Form.js'
export type * from './admin/types.js'
import type { NonNever } from 'ts-essentials'

import type { Options as CountOptions } from './collections/operations/local/count.js'
import type { Options as CreateOptions } from './collections/operations/local/create.js'
import type {
Expand Down Expand Up @@ -166,6 +168,16 @@ type ResolveGlobalSelectType<T> = 'globalsSelect' extends keyof T
// Applying helper types to GeneratedTypes
export type TypedCollection = ResolveCollectionType<GeneratedTypes>

export type TypedUploadCollection = NonNever<{
[K in keyof TypedCollection]:
| 'filename'
| 'filesize'
| 'mimeType'
| 'url' extends keyof TypedCollection[K]
? TypedCollection[K]
: never
}>

export type TypedCollectionSelect = ResolveCollectionSelectType<GeneratedTypes>

export type TypedCollectionJoins = ResolveCollectionJoinsType<GeneratedTypes>
Expand All @@ -180,6 +192,8 @@ export type StringKeyOf<T> = Extract<keyof T, string>
// Define the types for slugs using the appropriate collections and globals
export type CollectionSlug = StringKeyOf<TypedCollection>

export type UploadCollectionSlug = StringKeyOf<TypedUploadCollection>

type ResolveDbType<T> = 'db' extends keyof T
? T['db']
: // @ts-expect-error
Expand Down Expand Up @@ -228,7 +242,7 @@ export class BasePayload {
authStrategies: AuthStrategy[]

collections: {
[slug: string]: Collection
[slug: CollectionSlug]: Collection
} = {}

config: SanitizedConfig
Expand Down
3 changes: 2 additions & 1 deletion packages/plugin-cloud-storage/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {
ImageSize,
PayloadRequest,
TypeWithID,
UploadCollectionSlug,
} from 'payload'

export interface File {
Expand Down Expand Up @@ -79,7 +80,7 @@ export interface CollectionOptions {
}

export interface PluginOptions {
collections: Record<string, CollectionOptions>
collections: Partial<Record<UploadCollectionSlug, CollectionOptions>>
/**
* Whether or not to enable the plugin
*
Expand Down
4 changes: 3 additions & 1 deletion packages/plugin-nested-docs/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { CollectionSlug } from 'payload'

export type Breadcrumb = {
doc: string
label: string
Expand All @@ -22,7 +24,7 @@ export type NestedDocsPluginConfig = {
/**
* The slugs of the collections this plugin should extend. If you need different configs for different collections, this plugin can be added to your config more than once having different collections.
*/
collections: string[]
collections: CollectionSlug[]
generateLabel?: GenerateLabel
generateURL?: GenerateURL
/**
Expand Down
4 changes: 2 additions & 2 deletions packages/plugin-stripe/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Payload, Config as PayloadConfig, PayloadRequest } from 'payload'
import type { CollectionSlug, Payload, Config as PayloadConfig, PayloadRequest } from 'payload'
import type Stripe from 'stripe'

export type StripeWebhookHandler<T = any> = (args: {
Expand All @@ -20,7 +20,7 @@ export type FieldSyncConfig = {
}

export type SyncConfig = {
collection: string
collection: CollectionSlug
fields: FieldSyncConfig[]
stripeResourceType: 'customers' | 'products' // TODO: get this from Stripe types
stripeResourceTypeSingular: 'customer' | 'product' // TODO: there must be a better way to do this
Expand Down
Loading

0 comments on commit 810c29b

Please sign in to comment.