@payloadcms/plugin-multi-tenant 4.0.0-canary.26 → 4.0.0-canary.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAczD,eAAO,MAAM,iBAAiB,gEAua5B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAczD,eAAO,MAAM,iBAAiB,gEA4a5B,CAAA"}
package/dist/index.js CHANGED
@@ -65,6 +65,11 @@ export const multiTenantPlugin = definePlugin({
65
65
  */ if (pluginConfig?.tenantsArrayField?.includeDefaultField !== false) {
66
66
  adminUsersCollection.fields.push(tenantsArrayField({
67
67
  ...pluginConfig?.tenantsArrayField || {},
68
+ arrayFieldAccess: {
69
+ create: ({ req })=>Boolean(req.user && userHasAccessToAllTenants(req.user)),
70
+ update: ({ req })=>Boolean(req.user && userHasAccessToAllTenants(req.user)),
71
+ ...pluginConfig?.tenantsArrayField?.arrayFieldAccess || {}
72
+ },
68
73
  tenantsArrayFieldName,
69
74
  tenantsArrayTenantFieldName,
70
75
  tenantsCollectionSlug
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { AcceptedLanguages } from '@payloadcms/translations'\nimport type { CollectionConfig } from 'payload'\n\nimport { definePlugin } from 'payload'\nimport { hasAutosaveEnabled } from 'payload/shared'\n\nimport type { PluginDefaultTranslationsObject } from './translations/types.js'\nimport type { MultiTenantPluginConfig } from './types.js'\n\nimport { defaults } from './defaults.js'\nimport { getTenantOptionsEndpoint } from './endpoints/getTenantOptionsEndpoint.js'\nimport { tenantField } from './fields/tenantField/index.js'\nimport { tenantsArrayField } from './fields/tenantsArrayField/index.js'\nimport { filterDocumentsByTenants } from './filters/filterDocumentsByTenants.js'\nimport { addTenantCleanup } from './hooks/afterTenantDelete.js'\nimport { translations } from './translations/index.js'\nimport { addCollectionAccess } from './utilities/addCollectionAccess.js'\nimport { addFilterOptionsToFields } from './utilities/addFilterOptionsToFields.js'\nimport { combineFilters } from './utilities/combineFilters.js'\nimport { miniChalk } from './utilities/miniChalk.js'\n\nexport const multiTenantPlugin = definePlugin<MultiTenantPluginConfig>({\n slug: '@payloadcms/plugin-multi-tenant',\n plugin: ({ config: incomingConfig, options: pluginConfig }) => {\n if (pluginConfig.enabled === false) {\n return incomingConfig\n }\n\n /**\n * Set defaults\n */\n const userHasAccessToAllTenants: Required<MultiTenantPluginConfig>['userHasAccessToAllTenants'] =\n typeof pluginConfig.userHasAccessToAllTenants === 'function'\n ? pluginConfig.userHasAccessToAllTenants\n : () => false\n const tenantsCollectionSlug = (pluginConfig.tenantsSlug =\n pluginConfig.tenantsSlug || defaults.tenantCollectionSlug)\n const tenantFieldName = pluginConfig?.tenantField?.name || defaults.tenantFieldName\n const tenantsArrayFieldName =\n pluginConfig?.tenantsArrayField?.arrayFieldName || defaults.tenantsArrayFieldName\n const tenantsArrayTenantFieldName =\n pluginConfig?.tenantsArrayField?.arrayTenantFieldName || defaults.tenantsArrayTenantFieldName\n\n /**\n * Add defaults for admin properties\n */\n if (!incomingConfig.admin) {\n incomingConfig.admin = {}\n }\n if (!incomingConfig.admin?.components) {\n incomingConfig.admin.components = {\n actions: [],\n beforeNav: [],\n providers: [],\n }\n }\n if (!incomingConfig.admin.components?.providers) {\n incomingConfig.admin.components.providers = []\n }\n if (!incomingConfig.admin.components?.actions) {\n incomingConfig.admin.components.actions = []\n }\n if (!incomingConfig.admin.components?.beforeNav) {\n incomingConfig.admin.components.beforeNav = []\n }\n if (!incomingConfig.collections) {\n incomingConfig.collections = []\n }\n\n /**\n * Add tenants array field to users collection\n */\n const adminUsersCollection = incomingConfig.collections.find(({ slug, auth }) => {\n if (incomingConfig.admin?.user) {\n return slug === incomingConfig.admin.user\n } else if (auth) {\n return true\n }\n })\n\n if (!adminUsersCollection) {\n throw Error('An auth enabled collection was not found')\n }\n\n /**\n * Add tenants array field to users collection\n */\n if (pluginConfig?.tenantsArrayField?.includeDefaultField !== false) {\n adminUsersCollection.fields.push(\n tenantsArrayField({\n ...(pluginConfig?.tenantsArrayField || {}),\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n }),\n )\n }\n\n addCollectionAccess({\n accessResultCallback: pluginConfig.usersAccessResultOverride,\n adminUsersSlug: adminUsersCollection.slug,\n collection: adminUsersCollection,\n fieldName: `${tenantsArrayFieldName}.${tenantsArrayTenantFieldName}`,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n })\n\n if (pluginConfig.useUsersTenantFilter !== false) {\n if (!adminUsersCollection.admin) {\n adminUsersCollection.admin = {}\n }\n\n const baseFilter =\n adminUsersCollection.admin?.baseFilter ?? adminUsersCollection.admin?.baseListFilter\n adminUsersCollection.admin.baseFilter = combineFilters({\n baseFilter,\n customFilter: (args) =>\n filterDocumentsByTenants({\n filterFieldName: `${tenantsArrayFieldName}.${tenantsArrayTenantFieldName}`,\n req: args.req,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n userHasAccessToAllTenants,\n }),\n })\n }\n\n let tenantCollection: CollectionConfig | undefined\n\n const [collectionSlugs, globalCollectionSlugs] = Object.keys(pluginConfig.collections).reduce<\n [string[], string[]]\n >(\n (acc, slug) => {\n if (slug === adminUsersCollection.slug) {\n return acc\n }\n if (pluginConfig?.collections?.[slug]?.isGlobal) {\n acc[1].push(slug)\n } else {\n acc[0].push(slug)\n }\n\n return acc\n },\n [[], []],\n )\n\n // used to track and not duplicate filterOptions on referenced blocks\n const blockReferencesWithFilters: string[] = []\n\n // used to validate enabled collection slugs\n const multiTenantCollectionsFound: string[] = []\n\n /**\n * Modify collections\n */\n incomingConfig.collections.forEach((collection) => {\n /**\n * Modify tenants collection\n */\n if (collection.slug === tenantsCollectionSlug) {\n tenantCollection = collection\n\n if (pluginConfig.useTenantsCollectionAccess !== false) {\n /**\n * Add access control constraint to tenants collection\n * - constrains access a users assigned tenants\n */\n addCollectionAccess({\n adminUsersSlug: adminUsersCollection.slug,\n collection,\n fieldName: 'id',\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n })\n }\n\n if (pluginConfig.useTenantsListFilter !== false) {\n /**\n * Add list filter to tenants collection\n * - filter by selected tenant\n */\n if (!collection.admin) {\n collection.admin = {}\n }\n\n const baseFilter = collection.admin?.baseFilter ?? collection.admin?.baseListFilter\n collection.admin.baseFilter = combineFilters({\n baseFilter,\n customFilter: (args) =>\n filterDocumentsByTenants({\n filterFieldName: 'id',\n req: args.req,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n userHasAccessToAllTenants,\n }),\n })\n }\n\n if (pluginConfig.cleanupAfterTenantDelete !== false) {\n /**\n * Add cleanup logic when tenant is deleted\n * - delete documents related to tenant\n * - remove tenant from users\n */\n addTenantCleanup({\n collection,\n enabledSlugs: [...collectionSlugs, ...globalCollectionSlugs],\n tenantFieldName,\n tenantsCollectionSlug,\n usersSlug: adminUsersCollection.slug,\n usersTenantsArrayFieldName: tenantsArrayFieldName,\n usersTenantsArrayTenantFieldName: tenantsArrayTenantFieldName,\n })\n }\n\n /**\n * Add custom tenant field that watches and dispatches updates to the selector\n */\n collection.fields.push({\n name: '_watchTenant',\n type: 'ui',\n admin: {\n components: {\n Field: {\n path: '@payloadcms/plugin-multi-tenant/client#WatchTenantCollection',\n },\n },\n disabled: { bulkEdit: true, column: true },\n },\n })\n\n collection.endpoints = [\n ...(collection.endpoints || []),\n getTenantOptionsEndpoint({\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n useAsTitle: tenantCollection.admin?.useAsTitle || 'id',\n userHasAccessToAllTenants,\n }),\n ]\n } else if (pluginConfig.collections?.[collection.slug]) {\n if (collection.slug === adminUsersCollection.slug) {\n // eslint-disable-next-line no-console\n console.warn(\n `[plugin-multi-tenant] The admin users collection \"${collection.slug}\" should not be listed in pluginConfig.collections — it is already handled by the plugin. Skipping tenant-field processing for this collection to avoid double access control and validation errors.`,\n )\n return\n }\n multiTenantCollectionsFound.push(collection.slug)\n const isGlobal = Boolean(pluginConfig.collections[collection.slug]?.isGlobal)\n\n if (isGlobal) {\n collection.disableDuplicate = true\n }\n\n if (!pluginConfig.debug && !isGlobal) {\n collection.admin ??= {}\n collection.admin.components ??= {}\n collection.admin.components.edit ??= {}\n collection.admin.components.edit.editMenuItems ??= []\n collection.admin.components.edit.editMenuItems.push({\n path: '@payloadcms/plugin-multi-tenant/client#AssignTenantFieldTrigger',\n })\n }\n\n /**\n * Add filter options to all relationship fields\n */\n collection.fields = addFilterOptionsToFields({\n blockReferencesWithFilters,\n config: incomingConfig,\n fields: collection.fields,\n tenantEnabledCollectionSlugs: collectionSlugs,\n tenantEnabledGlobalSlugs: globalCollectionSlugs,\n tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n userHasAccessToAllTenants,\n })\n\n if (pluginConfig.collections[collection.slug]?.customTenantField !== true) {\n /**\n * Add tenant field to enabled collections\n */\n collection.fields.unshift(\n tenantField({\n name: tenantFieldName,\n debug: pluginConfig.debug,\n isAutosaveEnabled: hasAutosaveEnabled(collection),\n overrides: pluginConfig.collections[collection.slug]?.tenantFieldOverrides\n ? pluginConfig.collections[collection.slug]?.tenantFieldOverrides\n : pluginConfig.tenantField || {},\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n unique: isGlobal,\n }),\n )\n }\n\n const { useBaseFilter, useBaseListFilter } = pluginConfig.collections[collection.slug] || {}\n if (useBaseFilter ?? useBaseListFilter ?? true) {\n /**\n * Add list filter to enabled collections\n * - filters results by selected tenant\n */\n collection.admin = collection.admin || {}\n collection.admin.baseFilter = combineFilters({\n baseFilter: collection.admin?.baseFilter ?? collection.admin?.baseListFilter,\n customFilter: (args) =>\n filterDocumentsByTenants({\n filterFieldName: tenantFieldName,\n req: args.req,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n userHasAccessToAllTenants,\n }),\n })\n }\n\n if (pluginConfig.collections[collection.slug]?.useTenantAccess !== false) {\n /**\n * Add access control constraint to tenant enabled collection\n */\n addCollectionAccess({\n accessResultCallback: pluginConfig.collections[collection.slug]?.accessResultOverride,\n adminUsersSlug: adminUsersCollection.slug,\n collection,\n fieldName: tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n })\n }\n }\n })\n\n if (!tenantCollection) {\n throw new Error(`Tenants collection not found with slug: ${tenantsCollectionSlug}`)\n }\n\n if (\n multiTenantCollectionsFound.length !==\n collectionSlugs.length + globalCollectionSlugs.length\n ) {\n const missingSlugs = [...collectionSlugs, ...globalCollectionSlugs].filter(\n (slug) => !multiTenantCollectionsFound.includes(slug),\n )\n // eslint-disable-next-line no-console\n console.error(\n miniChalk.yellowBold('WARNING (plugin-multi-tenant)'),\n 'missing collections',\n missingSlugs,\n 'try placing the multi-tenant plugin after other plugins.',\n )\n }\n\n /**\n * Add TenantSelectionProvider to admin providers\n */\n incomingConfig.admin.components.providers.push({\n clientProps: {\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug: tenantCollection.slug,\n useAsTitle: tenantCollection.admin?.useAsTitle || 'id',\n userHasAccessToAllTenants,\n },\n path: '@payloadcms/plugin-multi-tenant/rsc#TenantSelectionProvider',\n })\n\n /**\n * Add global redirect action\n */\n if (globalCollectionSlugs.length) {\n incomingConfig.admin.components.actions.push({\n path: '@payloadcms/plugin-multi-tenant/rsc#GlobalViewRedirect',\n serverProps: {\n globalSlugs: globalCollectionSlugs,\n tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n useAsTitle: tenantCollection.admin?.useAsTitle || 'id',\n userHasAccessToAllTenants,\n },\n })\n }\n\n /**\n * Add tenant selector to admin UI\n */\n incomingConfig.admin.components.beforeNav.push({\n clientProps: {\n enabledSlugs: [\n ...collectionSlugs,\n ...globalCollectionSlugs,\n adminUsersCollection.slug,\n tenantCollection.slug,\n ],\n label: pluginConfig.tenantSelectorLabel || undefined,\n },\n path: '@payloadcms/plugin-multi-tenant/rsc#TenantSelector',\n })\n\n /**\n * Merge plugin translations\n */\n if (!incomingConfig.i18n) {\n incomingConfig.i18n = {}\n }\n Object.entries(translations).forEach(([locale, pluginI18nObject]) => {\n const typedLocale = locale as AcceptedLanguages\n if (!incomingConfig.i18n!.translations) {\n incomingConfig.i18n!.translations = {}\n }\n if (!(typedLocale in incomingConfig.i18n!.translations)) {\n incomingConfig.i18n!.translations[typedLocale] = {}\n }\n if (!('plugin-multi-tenant' in incomingConfig.i18n!.translations[typedLocale]!)) {\n ;(incomingConfig.i18n!.translations[typedLocale] as PluginDefaultTranslationsObject)[\n 'plugin-multi-tenant'\n ] = {} as PluginDefaultTranslationsObject['plugin-multi-tenant']\n }\n\n ;(incomingConfig.i18n!.translations[typedLocale] as PluginDefaultTranslationsObject)[\n 'plugin-multi-tenant'\n ] = {\n ...pluginI18nObject.translations['plugin-multi-tenant'],\n ...(pluginConfig.i18n?.translations?.[typedLocale] || {}),\n }\n })\n\n return incomingConfig\n },\n})\n"],"names":["definePlugin","hasAutosaveEnabled","defaults","getTenantOptionsEndpoint","tenantField","tenantsArrayField","filterDocumentsByTenants","addTenantCleanup","translations","addCollectionAccess","addFilterOptionsToFields","combineFilters","miniChalk","multiTenantPlugin","slug","plugin","config","incomingConfig","options","pluginConfig","enabled","userHasAccessToAllTenants","tenantsCollectionSlug","tenantsSlug","tenantCollectionSlug","tenantFieldName","name","tenantsArrayFieldName","arrayFieldName","tenantsArrayTenantFieldName","arrayTenantFieldName","admin","components","actions","beforeNav","providers","collections","adminUsersCollection","find","auth","user","Error","includeDefaultField","fields","push","accessResultCallback","usersAccessResultOverride","adminUsersSlug","collection","fieldName","useUsersTenantFilter","baseFilter","baseListFilter","customFilter","args","filterFieldName","req","tenantCollection","collectionSlugs","globalCollectionSlugs","Object","keys","reduce","acc","isGlobal","blockReferencesWithFilters","multiTenantCollectionsFound","forEach","useTenantsCollectionAccess","useTenantsListFilter","cleanupAfterTenantDelete","enabledSlugs","usersSlug","usersTenantsArrayFieldName","usersTenantsArrayTenantFieldName","type","Field","path","disabled","bulkEdit","column","endpoints","useAsTitle","console","warn","Boolean","disableDuplicate","debug","edit","editMenuItems","tenantEnabledCollectionSlugs","tenantEnabledGlobalSlugs","customTenantField","unshift","isAutosaveEnabled","overrides","tenantFieldOverrides","unique","useBaseFilter","useBaseListFilter","useTenantAccess","accessResultOverride","length","missingSlugs","filter","includes","error","yellowBold","clientProps","serverProps","globalSlugs","label","tenantSelectorLabel","undefined","i18n","entries","locale","pluginI18nObject","typedLocale"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { AcceptedLanguages } from '@payloadcms/translations'\nimport type { CollectionConfig } from 'payload'\n\nimport { definePlugin } from 'payload'\nimport { hasAutosaveEnabled } from 'payload/shared'\n\nimport type { PluginDefaultTranslationsObject } from './translations/types.js'\nimport type { MultiTenantPluginConfig } from './types.js'\n\nimport { defaults } from './defaults.js'\nimport { getTenantOptionsEndpoint } from './endpoints/getTenantOptionsEndpoint.js'\nimport { tenantField } from './fields/tenantField/index.js'\nimport { tenantsArrayField } from './fields/tenantsArrayField/index.js'\nimport { filterDocumentsByTenants } from './filters/filterDocumentsByTenants.js'\nimport { addTenantCleanup } from './hooks/afterTenantDelete.js'\nimport { translations } from './translations/index.js'\nimport { addCollectionAccess } from './utilities/addCollectionAccess.js'\nimport { addFilterOptionsToFields } from './utilities/addFilterOptionsToFields.js'\nimport { combineFilters } from './utilities/combineFilters.js'\nimport { miniChalk } from './utilities/miniChalk.js'\n\nexport const multiTenantPlugin = definePlugin<MultiTenantPluginConfig>({\n slug: '@payloadcms/plugin-multi-tenant',\n plugin: ({ config: incomingConfig, options: pluginConfig }) => {\n if (pluginConfig.enabled === false) {\n return incomingConfig\n }\n\n /**\n * Set defaults\n */\n const userHasAccessToAllTenants: Required<MultiTenantPluginConfig>['userHasAccessToAllTenants'] =\n typeof pluginConfig.userHasAccessToAllTenants === 'function'\n ? pluginConfig.userHasAccessToAllTenants\n : () => false\n const tenantsCollectionSlug = (pluginConfig.tenantsSlug =\n pluginConfig.tenantsSlug || defaults.tenantCollectionSlug)\n const tenantFieldName = pluginConfig?.tenantField?.name || defaults.tenantFieldName\n const tenantsArrayFieldName =\n pluginConfig?.tenantsArrayField?.arrayFieldName || defaults.tenantsArrayFieldName\n const tenantsArrayTenantFieldName =\n pluginConfig?.tenantsArrayField?.arrayTenantFieldName || defaults.tenantsArrayTenantFieldName\n\n /**\n * Add defaults for admin properties\n */\n if (!incomingConfig.admin) {\n incomingConfig.admin = {}\n }\n if (!incomingConfig.admin?.components) {\n incomingConfig.admin.components = {\n actions: [],\n beforeNav: [],\n providers: [],\n }\n }\n if (!incomingConfig.admin.components?.providers) {\n incomingConfig.admin.components.providers = []\n }\n if (!incomingConfig.admin.components?.actions) {\n incomingConfig.admin.components.actions = []\n }\n if (!incomingConfig.admin.components?.beforeNav) {\n incomingConfig.admin.components.beforeNav = []\n }\n if (!incomingConfig.collections) {\n incomingConfig.collections = []\n }\n\n /**\n * Add tenants array field to users collection\n */\n const adminUsersCollection = incomingConfig.collections.find(({ slug, auth }) => {\n if (incomingConfig.admin?.user) {\n return slug === incomingConfig.admin.user\n } else if (auth) {\n return true\n }\n })\n\n if (!adminUsersCollection) {\n throw Error('An auth enabled collection was not found')\n }\n\n /**\n * Add tenants array field to users collection\n */\n if (pluginConfig?.tenantsArrayField?.includeDefaultField !== false) {\n adminUsersCollection.fields.push(\n tenantsArrayField({\n ...(pluginConfig?.tenantsArrayField || {}),\n arrayFieldAccess: {\n create: ({ req }) => Boolean(req.user && userHasAccessToAllTenants(req.user)),\n update: ({ req }) => Boolean(req.user && userHasAccessToAllTenants(req.user)),\n ...(pluginConfig?.tenantsArrayField?.arrayFieldAccess || {}),\n },\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n }),\n )\n }\n\n addCollectionAccess({\n accessResultCallback: pluginConfig.usersAccessResultOverride,\n adminUsersSlug: adminUsersCollection.slug,\n collection: adminUsersCollection,\n fieldName: `${tenantsArrayFieldName}.${tenantsArrayTenantFieldName}`,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n })\n\n if (pluginConfig.useUsersTenantFilter !== false) {\n if (!adminUsersCollection.admin) {\n adminUsersCollection.admin = {}\n }\n\n const baseFilter =\n adminUsersCollection.admin?.baseFilter ?? adminUsersCollection.admin?.baseListFilter\n adminUsersCollection.admin.baseFilter = combineFilters({\n baseFilter,\n customFilter: (args) =>\n filterDocumentsByTenants({\n filterFieldName: `${tenantsArrayFieldName}.${tenantsArrayTenantFieldName}`,\n req: args.req,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n userHasAccessToAllTenants,\n }),\n })\n }\n\n let tenantCollection: CollectionConfig | undefined\n\n const [collectionSlugs, globalCollectionSlugs] = Object.keys(pluginConfig.collections).reduce<\n [string[], string[]]\n >(\n (acc, slug) => {\n if (slug === adminUsersCollection.slug) {\n return acc\n }\n if (pluginConfig?.collections?.[slug]?.isGlobal) {\n acc[1].push(slug)\n } else {\n acc[0].push(slug)\n }\n\n return acc\n },\n [[], []],\n )\n\n // used to track and not duplicate filterOptions on referenced blocks\n const blockReferencesWithFilters: string[] = []\n\n // used to validate enabled collection slugs\n const multiTenantCollectionsFound: string[] = []\n\n /**\n * Modify collections\n */\n incomingConfig.collections.forEach((collection) => {\n /**\n * Modify tenants collection\n */\n if (collection.slug === tenantsCollectionSlug) {\n tenantCollection = collection\n\n if (pluginConfig.useTenantsCollectionAccess !== false) {\n /**\n * Add access control constraint to tenants collection\n * - constrains access a users assigned tenants\n */\n addCollectionAccess({\n adminUsersSlug: adminUsersCollection.slug,\n collection,\n fieldName: 'id',\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n })\n }\n\n if (pluginConfig.useTenantsListFilter !== false) {\n /**\n * Add list filter to tenants collection\n * - filter by selected tenant\n */\n if (!collection.admin) {\n collection.admin = {}\n }\n\n const baseFilter = collection.admin?.baseFilter ?? collection.admin?.baseListFilter\n collection.admin.baseFilter = combineFilters({\n baseFilter,\n customFilter: (args) =>\n filterDocumentsByTenants({\n filterFieldName: 'id',\n req: args.req,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n userHasAccessToAllTenants,\n }),\n })\n }\n\n if (pluginConfig.cleanupAfterTenantDelete !== false) {\n /**\n * Add cleanup logic when tenant is deleted\n * - delete documents related to tenant\n * - remove tenant from users\n */\n addTenantCleanup({\n collection,\n enabledSlugs: [...collectionSlugs, ...globalCollectionSlugs],\n tenantFieldName,\n tenantsCollectionSlug,\n usersSlug: adminUsersCollection.slug,\n usersTenantsArrayFieldName: tenantsArrayFieldName,\n usersTenantsArrayTenantFieldName: tenantsArrayTenantFieldName,\n })\n }\n\n /**\n * Add custom tenant field that watches and dispatches updates to the selector\n */\n collection.fields.push({\n name: '_watchTenant',\n type: 'ui',\n admin: {\n components: {\n Field: {\n path: '@payloadcms/plugin-multi-tenant/client#WatchTenantCollection',\n },\n },\n disabled: { bulkEdit: true, column: true },\n },\n })\n\n collection.endpoints = [\n ...(collection.endpoints || []),\n getTenantOptionsEndpoint({\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n useAsTitle: tenantCollection.admin?.useAsTitle || 'id',\n userHasAccessToAllTenants,\n }),\n ]\n } else if (pluginConfig.collections?.[collection.slug]) {\n if (collection.slug === adminUsersCollection.slug) {\n // eslint-disable-next-line no-console\n console.warn(\n `[plugin-multi-tenant] The admin users collection \"${collection.slug}\" should not be listed in pluginConfig.collections — it is already handled by the plugin. Skipping tenant-field processing for this collection to avoid double access control and validation errors.`,\n )\n return\n }\n multiTenantCollectionsFound.push(collection.slug)\n const isGlobal = Boolean(pluginConfig.collections[collection.slug]?.isGlobal)\n\n if (isGlobal) {\n collection.disableDuplicate = true\n }\n\n if (!pluginConfig.debug && !isGlobal) {\n collection.admin ??= {}\n collection.admin.components ??= {}\n collection.admin.components.edit ??= {}\n collection.admin.components.edit.editMenuItems ??= []\n collection.admin.components.edit.editMenuItems.push({\n path: '@payloadcms/plugin-multi-tenant/client#AssignTenantFieldTrigger',\n })\n }\n\n /**\n * Add filter options to all relationship fields\n */\n collection.fields = addFilterOptionsToFields({\n blockReferencesWithFilters,\n config: incomingConfig,\n fields: collection.fields,\n tenantEnabledCollectionSlugs: collectionSlugs,\n tenantEnabledGlobalSlugs: globalCollectionSlugs,\n tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n userHasAccessToAllTenants,\n })\n\n if (pluginConfig.collections[collection.slug]?.customTenantField !== true) {\n /**\n * Add tenant field to enabled collections\n */\n collection.fields.unshift(\n tenantField({\n name: tenantFieldName,\n debug: pluginConfig.debug,\n isAutosaveEnabled: hasAutosaveEnabled(collection),\n overrides: pluginConfig.collections[collection.slug]?.tenantFieldOverrides\n ? pluginConfig.collections[collection.slug]?.tenantFieldOverrides\n : pluginConfig.tenantField || {},\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n unique: isGlobal,\n }),\n )\n }\n\n const { useBaseFilter, useBaseListFilter } = pluginConfig.collections[collection.slug] || {}\n if (useBaseFilter ?? useBaseListFilter ?? true) {\n /**\n * Add list filter to enabled collections\n * - filters results by selected tenant\n */\n collection.admin = collection.admin || {}\n collection.admin.baseFilter = combineFilters({\n baseFilter: collection.admin?.baseFilter ?? collection.admin?.baseListFilter,\n customFilter: (args) =>\n filterDocumentsByTenants({\n filterFieldName: tenantFieldName,\n req: args.req,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n userHasAccessToAllTenants,\n }),\n })\n }\n\n if (pluginConfig.collections[collection.slug]?.useTenantAccess !== false) {\n /**\n * Add access control constraint to tenant enabled collection\n */\n addCollectionAccess({\n accessResultCallback: pluginConfig.collections[collection.slug]?.accessResultOverride,\n adminUsersSlug: adminUsersCollection.slug,\n collection,\n fieldName: tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n })\n }\n }\n })\n\n if (!tenantCollection) {\n throw new Error(`Tenants collection not found with slug: ${tenantsCollectionSlug}`)\n }\n\n if (\n multiTenantCollectionsFound.length !==\n collectionSlugs.length + globalCollectionSlugs.length\n ) {\n const missingSlugs = [...collectionSlugs, ...globalCollectionSlugs].filter(\n (slug) => !multiTenantCollectionsFound.includes(slug),\n )\n // eslint-disable-next-line no-console\n console.error(\n miniChalk.yellowBold('WARNING (plugin-multi-tenant)'),\n 'missing collections',\n missingSlugs,\n 'try placing the multi-tenant plugin after other plugins.',\n )\n }\n\n /**\n * Add TenantSelectionProvider to admin providers\n */\n incomingConfig.admin.components.providers.push({\n clientProps: {\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug: tenantCollection.slug,\n useAsTitle: tenantCollection.admin?.useAsTitle || 'id',\n userHasAccessToAllTenants,\n },\n path: '@payloadcms/plugin-multi-tenant/rsc#TenantSelectionProvider',\n })\n\n /**\n * Add global redirect action\n */\n if (globalCollectionSlugs.length) {\n incomingConfig.admin.components.actions.push({\n path: '@payloadcms/plugin-multi-tenant/rsc#GlobalViewRedirect',\n serverProps: {\n globalSlugs: globalCollectionSlugs,\n tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n useAsTitle: tenantCollection.admin?.useAsTitle || 'id',\n userHasAccessToAllTenants,\n },\n })\n }\n\n /**\n * Add tenant selector to admin UI\n */\n incomingConfig.admin.components.beforeNav.push({\n clientProps: {\n enabledSlugs: [\n ...collectionSlugs,\n ...globalCollectionSlugs,\n adminUsersCollection.slug,\n tenantCollection.slug,\n ],\n label: pluginConfig.tenantSelectorLabel || undefined,\n },\n path: '@payloadcms/plugin-multi-tenant/rsc#TenantSelector',\n })\n\n /**\n * Merge plugin translations\n */\n if (!incomingConfig.i18n) {\n incomingConfig.i18n = {}\n }\n Object.entries(translations).forEach(([locale, pluginI18nObject]) => {\n const typedLocale = locale as AcceptedLanguages\n if (!incomingConfig.i18n!.translations) {\n incomingConfig.i18n!.translations = {}\n }\n if (!(typedLocale in incomingConfig.i18n!.translations)) {\n incomingConfig.i18n!.translations[typedLocale] = {}\n }\n if (!('plugin-multi-tenant' in incomingConfig.i18n!.translations[typedLocale]!)) {\n ;(incomingConfig.i18n!.translations[typedLocale] as PluginDefaultTranslationsObject)[\n 'plugin-multi-tenant'\n ] = {} as PluginDefaultTranslationsObject['plugin-multi-tenant']\n }\n\n ;(incomingConfig.i18n!.translations[typedLocale] as PluginDefaultTranslationsObject)[\n 'plugin-multi-tenant'\n ] = {\n ...pluginI18nObject.translations['plugin-multi-tenant'],\n ...(pluginConfig.i18n?.translations?.[typedLocale] || {}),\n }\n })\n\n return incomingConfig\n },\n})\n"],"names":["definePlugin","hasAutosaveEnabled","defaults","getTenantOptionsEndpoint","tenantField","tenantsArrayField","filterDocumentsByTenants","addTenantCleanup","translations","addCollectionAccess","addFilterOptionsToFields","combineFilters","miniChalk","multiTenantPlugin","slug","plugin","config","incomingConfig","options","pluginConfig","enabled","userHasAccessToAllTenants","tenantsCollectionSlug","tenantsSlug","tenantCollectionSlug","tenantFieldName","name","tenantsArrayFieldName","arrayFieldName","tenantsArrayTenantFieldName","arrayTenantFieldName","admin","components","actions","beforeNav","providers","collections","adminUsersCollection","find","auth","user","Error","includeDefaultField","fields","push","arrayFieldAccess","create","req","Boolean","update","accessResultCallback","usersAccessResultOverride","adminUsersSlug","collection","fieldName","useUsersTenantFilter","baseFilter","baseListFilter","customFilter","args","filterFieldName","tenantCollection","collectionSlugs","globalCollectionSlugs","Object","keys","reduce","acc","isGlobal","blockReferencesWithFilters","multiTenantCollectionsFound","forEach","useTenantsCollectionAccess","useTenantsListFilter","cleanupAfterTenantDelete","enabledSlugs","usersSlug","usersTenantsArrayFieldName","usersTenantsArrayTenantFieldName","type","Field","path","disabled","bulkEdit","column","endpoints","useAsTitle","console","warn","disableDuplicate","debug","edit","editMenuItems","tenantEnabledCollectionSlugs","tenantEnabledGlobalSlugs","customTenantField","unshift","isAutosaveEnabled","overrides","tenantFieldOverrides","unique","useBaseFilter","useBaseListFilter","useTenantAccess","accessResultOverride","length","missingSlugs","filter","includes","error","yellowBold","clientProps","serverProps","globalSlugs","label","tenantSelectorLabel","undefined","i18n","entries","locale","pluginI18nObject","typedLocale"],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { multiTenantPlugin } from './index.js';
3
+ describe('multiTenantPlugin', ()=>{
4
+ it('applies tenant assignment access defaults', async ()=>{
5
+ let hasAllTenantAccess = false;
6
+ const plugin = multiTenantPlugin({
7
+ collections: {},
8
+ userHasAccessToAllTenants: ()=>hasAllTenantAccess
9
+ });
10
+ const config = await plugin({
11
+ collections: [
12
+ {
13
+ slug: 'users',
14
+ auth: true,
15
+ fields: []
16
+ },
17
+ {
18
+ slug: 'tenants',
19
+ fields: []
20
+ }
21
+ ]
22
+ });
23
+ const usersCollection = config.collections?.find(({ slug })=>slug === 'users');
24
+ const tenantsField = usersCollection?.fields.find((field)=>'name' in field && field.name === 'tenants');
25
+ const accessArgs = {
26
+ req: {
27
+ user: {
28
+ id: 'test-user'
29
+ }
30
+ }
31
+ };
32
+ expect(await tenantsField?.access?.create?.(accessArgs)).toBe(false);
33
+ expect(await tenantsField?.access?.update?.(accessArgs)).toBe(false);
34
+ hasAllTenantAccess = true;
35
+ expect(await tenantsField?.access?.create?.(accessArgs)).toBe(true);
36
+ expect(await tenantsField?.access?.update?.(accessArgs)).toBe(true);
37
+ });
38
+ it('retains configured tenant assignment access callbacks', async ()=>{
39
+ const createAccess = ()=>false;
40
+ const updateAccess = ()=>true;
41
+ const plugin = multiTenantPlugin({
42
+ collections: {},
43
+ tenantsArrayField: {
44
+ arrayFieldAccess: {
45
+ create: createAccess,
46
+ update: updateAccess
47
+ }
48
+ }
49
+ });
50
+ const config = await plugin({
51
+ collections: [
52
+ {
53
+ slug: 'users',
54
+ auth: true,
55
+ fields: []
56
+ },
57
+ {
58
+ slug: 'tenants',
59
+ fields: []
60
+ }
61
+ ]
62
+ });
63
+ const usersCollection = config.collections?.find(({ slug })=>slug === 'users');
64
+ const tenantsField = usersCollection?.fields.find((field)=>'name' in field && field.name === 'tenants');
65
+ expect(tenantsField?.access?.create).toBe(createAccess);
66
+ expect(tenantsField?.access?.update).toBe(updateAccess);
67
+ });
68
+ });
69
+
70
+ //# sourceMappingURL=index.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.spec.ts"],"sourcesContent":["import type { ArrayField, Config } from 'payload'\n\nimport { describe, expect, it } from 'vitest'\n\nimport { multiTenantPlugin } from './index.js'\n\ndescribe('multiTenantPlugin', () => {\n it('applies tenant assignment access defaults', async () => {\n let hasAllTenantAccess = false\n const plugin = multiTenantPlugin({\n collections: {},\n userHasAccessToAllTenants: () => hasAllTenantAccess,\n })\n const config = await plugin({\n collections: [\n { slug: 'users', auth: true, fields: [] },\n { slug: 'tenants', fields: [] },\n ],\n } as Config)\n const usersCollection = config.collections?.find(({ slug }) => slug === 'users')\n const tenantsField = usersCollection?.fields.find(\n (field): field is ArrayField => 'name' in field && field.name === 'tenants',\n )\n const accessArgs = { req: { user: { id: 'test-user' } } } as never\n\n expect(await tenantsField?.access?.create?.(accessArgs)).toBe(false)\n expect(await tenantsField?.access?.update?.(accessArgs)).toBe(false)\n\n hasAllTenantAccess = true\n\n expect(await tenantsField?.access?.create?.(accessArgs)).toBe(true)\n expect(await tenantsField?.access?.update?.(accessArgs)).toBe(true)\n })\n\n it('retains configured tenant assignment access callbacks', async () => {\n const createAccess = () => false\n const updateAccess = () => true\n const plugin = multiTenantPlugin({\n collections: {},\n tenantsArrayField: {\n arrayFieldAccess: {\n create: createAccess,\n update: updateAccess,\n },\n },\n })\n const config = await plugin({\n collections: [\n { slug: 'users', auth: true, fields: [] },\n { slug: 'tenants', fields: [] },\n ],\n } as Config)\n const usersCollection = config.collections?.find(({ slug }) => slug === 'users')\n const tenantsField = usersCollection?.fields.find(\n (field): field is ArrayField => 'name' in field && field.name === 'tenants',\n )\n\n expect(tenantsField?.access?.create).toBe(createAccess)\n expect(tenantsField?.access?.update).toBe(updateAccess)\n })\n})\n"],"names":["describe","expect","it","multiTenantPlugin","hasAllTenantAccess","plugin","collections","userHasAccessToAllTenants","config","slug","auth","fields","usersCollection","find","tenantsField","field","name","accessArgs","req","user","id","access","create","toBe","update","createAccess","updateAccess","tenantsArrayField","arrayFieldAccess"],"mappings":"AAEA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAE7C,SAASC,iBAAiB,QAAQ,aAAY;AAE9CH,SAAS,qBAAqB;IAC5BE,GAAG,6CAA6C;QAC9C,IAAIE,qBAAqB;QACzB,MAAMC,SAASF,kBAAkB;YAC/BG,aAAa,CAAC;YACdC,2BAA2B,IAAMH;QACnC;QACA,MAAMI,SAAS,MAAMH,OAAO;YAC1BC,aAAa;gBACX;oBAAEG,MAAM;oBAASC,MAAM;oBAAMC,QAAQ,EAAE;gBAAC;gBACxC;oBAAEF,MAAM;oBAAWE,QAAQ,EAAE;gBAAC;aAC/B;QACH;QACA,MAAMC,kBAAkBJ,OAAOF,WAAW,EAAEO,KAAK,CAAC,EAAEJ,IAAI,EAAE,GAAKA,SAAS;QACxE,MAAMK,eAAeF,iBAAiBD,OAAOE,KAC3C,CAACE,QAA+B,UAAUA,SAASA,MAAMC,IAAI,KAAK;QAEpE,MAAMC,aAAa;YAAEC,KAAK;gBAAEC,MAAM;oBAAEC,IAAI;gBAAY;YAAE;QAAE;QAExDnB,OAAO,MAAMa,cAAcO,QAAQC,SAASL,aAAaM,IAAI,CAAC;QAC9DtB,OAAO,MAAMa,cAAcO,QAAQG,SAASP,aAAaM,IAAI,CAAC;QAE9DnB,qBAAqB;QAErBH,OAAO,MAAMa,cAAcO,QAAQC,SAASL,aAAaM,IAAI,CAAC;QAC9DtB,OAAO,MAAMa,cAAcO,QAAQG,SAASP,aAAaM,IAAI,CAAC;IAChE;IAEArB,GAAG,yDAAyD;QAC1D,MAAMuB,eAAe,IAAM;QAC3B,MAAMC,eAAe,IAAM;QAC3B,MAAMrB,SAASF,kBAAkB;YAC/BG,aAAa,CAAC;YACdqB,mBAAmB;gBACjBC,kBAAkB;oBAChBN,QAAQG;oBACRD,QAAQE;gBACV;YACF;QACF;QACA,MAAMlB,SAAS,MAAMH,OAAO;YAC1BC,aAAa;gBACX;oBAAEG,MAAM;oBAASC,MAAM;oBAAMC,QAAQ,EAAE;gBAAC;gBACxC;oBAAEF,MAAM;oBAAWE,QAAQ,EAAE;gBAAC;aAC/B;QACH;QACA,MAAMC,kBAAkBJ,OAAOF,WAAW,EAAEO,KAAK,CAAC,EAAEJ,IAAI,EAAE,GAAKA,SAAS;QACxE,MAAMK,eAAeF,iBAAiBD,OAAOE,KAC3C,CAACE,QAA+B,UAAUA,SAASA,MAAMC,IAAI,KAAK;QAGpEf,OAAOa,cAAcO,QAAQC,QAAQC,IAAI,CAACE;QAC1CxB,OAAOa,cAAcO,QAAQG,QAAQD,IAAI,CAACG;IAC5C;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloadcms/plugin-multi-tenant",
3
- "version": "4.0.0-canary.26",
3
+ "version": "4.0.0-canary.27",
4
4
  "description": "Multi Tenant plugin for Payload",
5
5
  "keywords": [
6
6
  "payload",
@@ -80,13 +80,13 @@
80
80
  ],
81
81
  "devDependencies": {
82
82
  "@payloadcms/eslint-config": "3.28.0",
83
- "payload": "4.0.0-canary.26",
84
- "@payloadcms/ui": "4.0.0-canary.26",
85
- "@payloadcms/translations": "4.0.0-canary.26"
83
+ "@payloadcms/ui": "4.0.0-canary.27",
84
+ "payload": "4.0.0-canary.27",
85
+ "@payloadcms/translations": "4.0.0-canary.27"
86
86
  },
87
87
  "peerDependencies": {
88
- "@payloadcms/ui": "4.0.0-canary.26",
89
- "payload": "4.0.0-canary.26"
88
+ "@payloadcms/ui": "4.0.0-canary.27",
89
+ "payload": "4.0.0-canary.27"
90
90
  },
91
91
  "homepage:": "https://payloadcms.com",
92
92
  "scripts": {