SIGN IN SIGN UP
payloadcms / payload UNCLAIMED

Payload is the open-source, fullstack Next.js framework, giving you instant backend superpowers. Get a full TypeScript backend and admin panel instantly. Use Payload as a headless CMS or for building powerful applications.

41461 0 0 TypeScript
2020-11-20 13:39:18 -05:00
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"composite": false,
"noEmit": true,
"baseUrl": ".",
},
"references": [
{
"path": "./packages/admin-bar"
},
{
"path": "./packages/create-payload-app"
},
2024-02-23 13:04:50 -05:00
{
"path": "./packages/db-mongodb"
},
{
"path": "./packages/db-postgres"
},
{
"path": "./packages/drizzle"
},
{
"path": "./packages/graphql"
},
{
"path": "./packages/live-preview"
},
{
"path": "./packages/live-preview-react"
},
{
"path": "./packages/live-preview-vue"
},
feat: add KV storage adapters (#9913) Adds KV storage support to Payload Local API with an adapter pattern, includes 3 adapters. We'll use it for the Realtime API. You can access it via `payload.kv`: ```ts interface KVAdapter { /** * Clears all entries in the store. * @returns A promise that resolves once the store is cleared. */ clear(): Promise<void> /** * Deletes a value from the store by its key. * @param key - The key to delete. * @returns A promise that resolves once the key is deleted. */ delete(key: string): Promise<void> /** * Retrieves a value from the store by its key. * @param key - The key to look up. * @returns A promise that resolves to the value, or `null` if not found. */ get(key: string): Promise<KVStoreValue | null> /** * Checks if a key exists in the store. * @param key - The key to check. * @returns A promise that resolves to `true` if the key exists, otherwise `false`. */ has(key: string): Promise<boolean> /** * Retrieves all the keys in the store. * @returns A promise that resolves to an array of keys. */ keys(): Promise<string[]> /** * Sets a value in the store with the given key. * @param key - The key to associate with the value. * @param value - The value to store. * @returns A promise that resolves once the value is stored. */ set(key: string, value: KVStoreValue): Promise<void> } ``` To configure the adapter you can use the `kv` property of the root config. ```ts buildConfig({ kv: adapter() }) ``` #### Database KV adapter (default) No need to configure, as Payload uses it by default. It generates new collection `payload-kv` and uses the current database adapter to access it. The collection is hidden in the admin panel and access locked. If you want to override the generated collection: ```ts import { databaseKVAdapter } from 'payload' buildConfig({ kv: databaseKVAdapter({ kvCollectionOverrides: { slug: 'custom-kv', ...(process.env.DEBUG === 'true' && { admin: { hidden: false }, access: {}, }), }, }), }) ``` #### In Memory KV adapter Simple and very fast storage using memory. Don't use it on Vercel / multiple instances or if you need data persistence. ```ts import { inMemoryKVAdapter } from 'payload' buildConfig({ kv: inMemoryKVAdapter(), }) ``` #### Redis KV Adapter Uses Redis. Probably the best option as it's faster than database, persistent and works with Vercel / multiple instances, but requires additional setup ```sh pnpm add @payloadcms/kv-redis ``` ```ts import { redisKVAdapter } from '@payloadcms/kv-redis' buildConfig({ kv: redisKVAdapter({ keyPrefix: "custom-prefix:", // defaults to 'payload-kv:' redisURL: "redis://127.0.0.1:6379" // defaults to process.env.REDIS_URL (Vercel generates this variable for you if you connect a project to Redis) }), }) ```
2025-10-30 17:05:38 +02:00
{
"path": "./packages/kv-redis"
},
{
"path": "./packages/next"
},
{
"path": "./packages/payload"
},
{
"path": "./packages/plugin-cloud-storage"
},
{
"path": "./packages/storage-s3"
},
{
"path": "./packages/payload-cloud"
},
{
"path": "./packages/plugin-form-builder"
},
{
"path": "./packages/plugin-nested-docs"
},
{
"path": "./packages/plugin-redirects"
},
{
"path": "./packages/plugin-search"
},
{
"path": "./packages/plugin-seo"
},
{
"path": "./packages/plugin-import-export"
},
{
"path": "./packages/plugin-stripe"
},
feat: adds multi-tenant plugin (#10447) ### Multi Tenant Plugin This PR adds a `@payloadcms/plugin-multi-tenant` package. The goal is to consolidate a source of truth for multi-tenancy. Currently we are maintaining different implementations for clients, users in discord and our examples repo. When updates or new paradigms arise we need to communicate this with everyone and update code examples which is hard to maintain. ### What does it do? - adds a tenant selector to the sidebar, above the nav links - adds a hidden tenant field to every collection that you specify - adds an array field to your users collection, allowing you to assign users to tenants - by default combines the access control (to enabled collections) that you define, with access control based on the tenants assigned to user on the request - by default adds a baseListFilter that filters the documents shown in the list view with the selected tenant in the admin panel ### What does it not do? - it does not implement multi-tenancy for your frontend. You will need to query data for specific tenants to build your website/application - it does not add a tenants collection, you **NEED** to add a tenants collection, where you can define what types of fields you would like on it ### The plugin config Most of the options listed below are _optional_, but it is easier to just lay out all of the configuration options. **TS Type** ```ts type MultiTenantPluginConfig<ConfigTypes = unknown> = { /** * After a tenant is deleted, the plugin will attempt to clean up related documents * - removing documents with the tenant ID * - removing the tenant from users * * @default true */ cleanupAfterTenantDelete?: boolean /** * Automatically */ collections: { [key in CollectionSlug]?: { /** * Set to `true` if you want the collection to behave as a global * * @default false */ isGlobal?: boolean /** * Set to `false` if you want to manually apply the baseListFilter * * @default true */ useBaseListFilter?: boolean /** * Set to `false` if you want to handle collection access manually without the multi-tenant constraints applied * * @default true */ useTenantAccess?: boolean } } /** * Enables debug mode * - Makes the tenant field visible in the admin UI within applicable collections * * @default false */ debug?: boolean /** * Enables the multi-tenant plugin * * @default true */ enabled?: boolean /** * Field configuration for the field added to all tenant enabled collections */ tenantField?: { access?: RelationshipField['access'] /** * The name of the field added to all tenant enabled collections * * @default 'tenant' */ name?: string } /** * Field configuration for the field added to the users collection * * If `includeDefaultField` is `false`, you must include the field on your users collection manually * This is useful if you want to customize the field or place the field in a specific location */ tenantsArrayField?: | { /** * Access configuration for the array field */ arrayFieldAccess?: ArrayField['access'] /** * When `includeDefaultField` is `true`, the field will be added to the users collection automatically */ includeDefaultField?: true /** * Additional fields to include on the tenants array field */ rowFields?: Field[] /** * Access configuration for the tenant field */ tenantFieldAccess?: RelationshipField['access'] } | { arrayFieldAccess?: never /** * When `includeDefaultField` is `false`, you must include the field on your users collection manually */ includeDefaultField?: false rowFields?: never tenantFieldAccess?: never } /** * The slug for the tenant collection * * @default 'tenants' */ tenantsSlug?: string /** * Function that determines if a user has access to _all_ tenants * * Useful for super-admin type users */ userHasAccessToAllTenants?: ( user: ConfigTypes extends { user: User } ? ConfigTypes['user'] : User, ) => boolean } ``` **Example usage** ```ts import type { Config } from './payload-types' import { buildConfig } from 'payload' export default buildConfig({ plugins: [ multiTenantPlugin<Config>({ collections: { pages: {}, }, userHasAccessToAllTenants: (user) => isSuperAdmin(user), }), ], }) ``` ### How to configure Collections as Globals for multi-tenant When using multi-tenant, globals need to actually be configured as collections so the content can be specific per tenant. To do that, you can mark a collection with `isGlobal` and it will behave like a global and users will not see the list view. ```ts multiTenantPlugin({ collections: { navigation: { isGlobal: true, }, }, }) ```
2025-01-15 14:47:46 -05:00
{
"path": "./packages/plugin-multi-tenant"
},
{
"path": "./packages/richtext-slate"
},
{
"path": "./packages/richtext-lexical"
},
{
"path": "./packages/translations"
},
{
"path": "./packages/ui"
feat: adds multi-tenant plugin (#10447) ### Multi Tenant Plugin This PR adds a `@payloadcms/plugin-multi-tenant` package. The goal is to consolidate a source of truth for multi-tenancy. Currently we are maintaining different implementations for clients, users in discord and our examples repo. When updates or new paradigms arise we need to communicate this with everyone and update code examples which is hard to maintain. ### What does it do? - adds a tenant selector to the sidebar, above the nav links - adds a hidden tenant field to every collection that you specify - adds an array field to your users collection, allowing you to assign users to tenants - by default combines the access control (to enabled collections) that you define, with access control based on the tenants assigned to user on the request - by default adds a baseListFilter that filters the documents shown in the list view with the selected tenant in the admin panel ### What does it not do? - it does not implement multi-tenancy for your frontend. You will need to query data for specific tenants to build your website/application - it does not add a tenants collection, you **NEED** to add a tenants collection, where you can define what types of fields you would like on it ### The plugin config Most of the options listed below are _optional_, but it is easier to just lay out all of the configuration options. **TS Type** ```ts type MultiTenantPluginConfig<ConfigTypes = unknown> = { /** * After a tenant is deleted, the plugin will attempt to clean up related documents * - removing documents with the tenant ID * - removing the tenant from users * * @default true */ cleanupAfterTenantDelete?: boolean /** * Automatically */ collections: { [key in CollectionSlug]?: { /** * Set to `true` if you want the collection to behave as a global * * @default false */ isGlobal?: boolean /** * Set to `false` if you want to manually apply the baseListFilter * * @default true */ useBaseListFilter?: boolean /** * Set to `false` if you want to handle collection access manually without the multi-tenant constraints applied * * @default true */ useTenantAccess?: boolean } } /** * Enables debug mode * - Makes the tenant field visible in the admin UI within applicable collections * * @default false */ debug?: boolean /** * Enables the multi-tenant plugin * * @default true */ enabled?: boolean /** * Field configuration for the field added to all tenant enabled collections */ tenantField?: { access?: RelationshipField['access'] /** * The name of the field added to all tenant enabled collections * * @default 'tenant' */ name?: string } /** * Field configuration for the field added to the users collection * * If `includeDefaultField` is `false`, you must include the field on your users collection manually * This is useful if you want to customize the field or place the field in a specific location */ tenantsArrayField?: | { /** * Access configuration for the array field */ arrayFieldAccess?: ArrayField['access'] /** * When `includeDefaultField` is `true`, the field will be added to the users collection automatically */ includeDefaultField?: true /** * Additional fields to include on the tenants array field */ rowFields?: Field[] /** * Access configuration for the tenant field */ tenantFieldAccess?: RelationshipField['access'] } | { arrayFieldAccess?: never /** * When `includeDefaultField` is `false`, you must include the field on your users collection manually */ includeDefaultField?: false rowFields?: never tenantFieldAccess?: never } /** * The slug for the tenant collection * * @default 'tenants' */ tenantsSlug?: string /** * Function that determines if a user has access to _all_ tenants * * Useful for super-admin type users */ userHasAccessToAllTenants?: ( user: ConfigTypes extends { user: User } ? ConfigTypes['user'] : User, ) => boolean } ``` **Example usage** ```ts import type { Config } from './payload-types' import { buildConfig } from 'payload' export default buildConfig({ plugins: [ multiTenantPlugin<Config>({ collections: { pages: {}, }, userHasAccessToAllTenants: (user) => isSuperAdmin(user), }), ], }) ``` ### How to configure Collections as Globals for multi-tenant When using multi-tenant, globals need to actually be configured as collections so the content can be specific per tenant. To do that, you can mark a collection with `isGlobal` and it will behave like a global and users will not see the list view. ```ts multiTenantPlugin({ collections: { navigation: { isGlobal: true, }, }, }) ```
2025-01-15 14:47:46 -05:00
},
feat: add Payload SDK package (#9463) Adds Payload SDK package, which can be used to query Payload REST API in a fully type safe way. Has support for all necessary operations, including auth, type safe `select`, `populate`, `joins` properties and simplified file uploading. Its interface is _very_ similar to the Local API, can't even notice the difference: Example: ```ts import { PayloadSDK } from '@payloadcms/sdk' import type { Config } from './payload-types' // Pass your config from generated types as generic const sdk = new PayloadSDK<Config>({ baseURL: 'https://example.com/api', }) // Find operation const posts = await sdk.find({ collection: 'posts', draft: true, limit: 10, locale: 'en', page: 1, where: { _status: { equals: 'published' } }, }) // Find by ID operation const posts = await sdk.findByID({ id, collection: 'posts', draft: true, locale: 'en', }) // Auth login operation const result = await sdk.login({ collection: 'users', data: { email: 'dev@payloadcms.com', password: '12345', }, }) // Create operation const result = await sdk.create({ collection: 'posts', data: { text: 'text' }, }) // Create operation with a file // `file` can be either a Blob | File object or a string URL const result = await sdk.create({ collection: 'media', file, data: {} }) // Count operation const result = await sdk.count({ collection: 'posts', where: { id: { equals: post.id } } }) // Update (by ID) operation const result = await sdk.update({ collection: 'posts', id: post.id, data: { text: 'updated-text', }, }) // Update (bulk) operation const result = await sdk.update({ collection: 'posts', where: { id: { equals: post.id, }, }, data: { text: 'updated-text-bulk' }, }) // Delete (by ID) operation const result = await sdk.delete({ id: post.id, collection: 'posts' }) // Delete (bulk) operation const result = await sdk.delete({ where: { id: { equals: post.id } }, collection: 'posts' }) // Find Global operation const result = await sdk.findGlobal({ slug: 'global' }) // Update Global operation const result = await sdk.updateGlobal({ slug: 'global', data: { text: 'some-updated-global' } }) // Auth Login operation const result = await sdk.login({ collection: 'users', data: { email: 'dev@payloadcms.com', password: '123456' }, }) // Auth Me operation const result = await sdk.me( { collection: 'users' }, { headers: { Authorization: `JWT ${user.token}`, }, }, ) // Auth Refresh Token operation const result = await sdk.refreshToken( { collection: 'users' }, { headers: { Authorization: `JWT ${user.token}` } }, ) // Auth Forgot Password operation const result = await sdk.forgotPassword({ collection: 'users', data: { email: user.email }, }) // Auth Reset Password operation const result = await sdk.resetPassword({ collection: 'users', data: { password: '1234567', token: resetPasswordToken }, }) // Find Versions operation const result = await sdk.findVersions({ collection: 'posts', where: { parent: { equals: post.id } }, }) // Find Version by ID operation const result = await sdk.findVersionByID({ collection: 'posts', id: version.id }) // Restore Version operation const result = await sdk.restoreVersion({ collection: 'posts', id, }) // Find Global Versions operation const result = await sdk.findGlobalVersions({ slug: 'global', }) // Find Global Version by ID operation const result = await sdk.findGlobalVersionByID({ id: version.id, slug: 'global' }) // Restore Global Version operation const result = await sdk.restoreGlobalVersion({ slug: 'global', id }) ``` Every operation has optional 3rd parameter which is used to add additional data to the RequestInit object (like headers): ```ts await sdk.me({ collection: "users" }, { // RequestInit object headers: { Authorization: `JWT ${token}` } }) ``` To query custom endpoints, you can use the `request` method, which is used internally for all other methods: ```ts await sdk.request({ method: 'POST', path: '/send-data', json: { id: 1, }, }) ``` Custom `fetch` implementation and `baseInit` for shared `RequestInit` properties: ```ts const sdk = new PayloadSDK<Config>({ baseInit: { credentials: 'include' }, baseURL: 'https://example.com/api', fetch: async (url, init) => { console.log('before req') const response = await fetch(url, init) console.log('after req') return response }, }) ```
2025-09-30 00:01:01 +03:00
{
"path": "./packages/sdk"
}
],
2024-04-01 15:55:38 -04:00
"include": [
"${configDir}/src",
feat: adds multi-tenant plugin (#10447) ### Multi Tenant Plugin This PR adds a `@payloadcms/plugin-multi-tenant` package. The goal is to consolidate a source of truth for multi-tenancy. Currently we are maintaining different implementations for clients, users in discord and our examples repo. When updates or new paradigms arise we need to communicate this with everyone and update code examples which is hard to maintain. ### What does it do? - adds a tenant selector to the sidebar, above the nav links - adds a hidden tenant field to every collection that you specify - adds an array field to your users collection, allowing you to assign users to tenants - by default combines the access control (to enabled collections) that you define, with access control based on the tenants assigned to user on the request - by default adds a baseListFilter that filters the documents shown in the list view with the selected tenant in the admin panel ### What does it not do? - it does not implement multi-tenancy for your frontend. You will need to query data for specific tenants to build your website/application - it does not add a tenants collection, you **NEED** to add a tenants collection, where you can define what types of fields you would like on it ### The plugin config Most of the options listed below are _optional_, but it is easier to just lay out all of the configuration options. **TS Type** ```ts type MultiTenantPluginConfig<ConfigTypes = unknown> = { /** * After a tenant is deleted, the plugin will attempt to clean up related documents * - removing documents with the tenant ID * - removing the tenant from users * * @default true */ cleanupAfterTenantDelete?: boolean /** * Automatically */ collections: { [key in CollectionSlug]?: { /** * Set to `true` if you want the collection to behave as a global * * @default false */ isGlobal?: boolean /** * Set to `false` if you want to manually apply the baseListFilter * * @default true */ useBaseListFilter?: boolean /** * Set to `false` if you want to handle collection access manually without the multi-tenant constraints applied * * @default true */ useTenantAccess?: boolean } } /** * Enables debug mode * - Makes the tenant field visible in the admin UI within applicable collections * * @default false */ debug?: boolean /** * Enables the multi-tenant plugin * * @default true */ enabled?: boolean /** * Field configuration for the field added to all tenant enabled collections */ tenantField?: { access?: RelationshipField['access'] /** * The name of the field added to all tenant enabled collections * * @default 'tenant' */ name?: string } /** * Field configuration for the field added to the users collection * * If `includeDefaultField` is `false`, you must include the field on your users collection manually * This is useful if you want to customize the field or place the field in a specific location */ tenantsArrayField?: | { /** * Access configuration for the array field */ arrayFieldAccess?: ArrayField['access'] /** * When `includeDefaultField` is `true`, the field will be added to the users collection automatically */ includeDefaultField?: true /** * Additional fields to include on the tenants array field */ rowFields?: Field[] /** * Access configuration for the tenant field */ tenantFieldAccess?: RelationshipField['access'] } | { arrayFieldAccess?: never /** * When `includeDefaultField` is `false`, you must include the field on your users collection manually */ includeDefaultField?: false rowFields?: never tenantFieldAccess?: never } /** * The slug for the tenant collection * * @default 'tenants' */ tenantsSlug?: string /** * Function that determines if a user has access to _all_ tenants * * Useful for super-admin type users */ userHasAccessToAllTenants?: ( user: ConfigTypes extends { user: User } ? ConfigTypes['user'] : User, ) => boolean } ``` **Example usage** ```ts import type { Config } from './payload-types' import { buildConfig } from 'payload' export default buildConfig({ plugins: [ multiTenantPlugin<Config>({ collections: { pages: {}, }, userHasAccessToAllTenants: (user) => isSuperAdmin(user), }), ], }) ``` ### How to configure Collections as Globals for multi-tenant When using multi-tenant, globals need to actually be configured as collections so the content can be specific per tenant. To do that, you can mark a collection with `isGlobal` and it will behave like a global and users will not see the list view. ```ts multiTenantPlugin({ collections: { navigation: { isGlobal: true, }, }, }) ```
2025-01-15 14:47:46 -05:00
".next/types/**/*.ts",
"./scripts/**/*.ts"
2024-04-01 15:55:38 -04:00
]
}