@payloadcms/plugin-multi-tenant 3.89.0-internal.95c9cba → 3.90.0

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,6 +1,7 @@
1
1
  import type { SingleRelationshipField } from 'payload';
2
- import type { RootTenantFieldConfigOverrides } from '../../types.js';
3
- type Args = {
2
+ import type { MultiTenantPluginConfig, RootTenantFieldConfigOverrides } from '../../types.js';
3
+ type Args<ConfigType = unknown> = {
4
+ adminUsersSlug?: string;
4
5
  debug?: boolean;
5
6
  isAutosaveEnabled?: boolean;
6
7
  name: string;
@@ -9,7 +10,8 @@ type Args = {
9
10
  tenantsArrayTenantFieldName: string;
10
11
  tenantsCollectionSlug: string;
11
12
  unique: boolean;
13
+ userHasAccessToAllTenants?: MultiTenantPluginConfig<ConfigType>['userHasAccessToAllTenants'];
12
14
  };
13
- export declare const tenantField: ({ name, debug, isAutosaveEnabled, overrides: _overrides, tenantsArrayFieldName, tenantsArrayTenantFieldName, tenantsCollectionSlug, unique, }: Args) => SingleRelationshipField;
15
+ export declare const tenantField: <ConfigType = unknown>({ name, adminUsersSlug, debug, isAutosaveEnabled, overrides: _overrides, tenantsArrayFieldName, tenantsArrayTenantFieldName, tenantsCollectionSlug, unique, userHasAccessToAllTenants, }: Args<ConfigType>) => SingleRelationshipField;
14
16
  export {};
15
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/fields/tenantField/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA+B,uBAAuB,EAAE,MAAM,SAAS,CAAA;AAEnF,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,gBAAgB,CAAA;AA8BpE,KAAK,IAAI,GAAG;IACV,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,8BAA8B,CAAA;IAC1C,qBAAqB,EAAE,MAAM,CAAA;IAC7B,2BAA2B,EAAE,MAAM,CAAA;IACnC,qBAAqB,EAAE,MAAM,CAAA;IAC7B,MAAM,EAAE,OAAO,CAAA;CAChB,CAAA;AACD,eAAO,MAAM,WAAW,kJASrB,IAAI,KAAG,uBAmGT,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/fields/tenantField/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA+B,uBAAuB,EAAE,MAAM,SAAS,CAAA;AAEnF,OAAO,KAAK,EAAE,uBAAuB,EAAE,8BAA8B,EAAE,MAAM,gBAAgB,CAAA;AAwD7F,KAAK,IAAI,CAAC,UAAU,GAAG,OAAO,IAAI;IAChC,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,8BAA8B,CAAA;IAC1C,qBAAqB,EAAE,MAAM,CAAA;IAC7B,2BAA2B,EAAE,MAAM,CAAA;IACnC,qBAAqB,EAAE,MAAM,CAAA;IAC7B,MAAM,EAAE,OAAO,CAAA;IACf,yBAAyB,CAAC,EAAE,uBAAuB,CAAC,UAAU,CAAC,CAAC,2BAA2B,CAAC,CAAA;CAC7F,CAAA;AACD,eAAO,MAAM,WAAW,GAAI,UAAU,sMAWnC,IAAI,CAAC,UAAU,CAAC,KAAG,uBAsHrB,CAAA"}
@@ -2,9 +2,10 @@ import { defaults } from '../../defaults.js';
2
2
  import { getCollectionIDType } from '../../utilities/getCollectionIDType.js';
3
3
  import { getTenantFromCookie } from '../../utilities/getTenantFromCookie.js';
4
4
  import { getUserTenantIDs } from '../../utilities/getUserTenantIDs.js';
5
- const fieldValidation = (validateFunction)=>(value, options)=>{
5
+ import { isValidTenantAssignment } from '../../utilities/isValidTenantAssignment.js';
6
+ const fieldValidation = ({ tenantsArrayFieldName, tenantsArrayTenantFieldName, userHasAccessToAllTenants, validateFunction })=>async (value, options)=>{
6
7
  if (validateFunction) {
7
- const result = validateFunction(value, options);
8
+ const result = await validateFunction(value, options);
8
9
  if (result !== true) {
9
10
  return result;
10
11
  }
@@ -18,15 +19,35 @@ const fieldValidation = (validateFunction)=>(value, options)=>{
18
19
  return options.req.t('validation:required');
19
20
  }
20
21
  }
21
- return true;
22
+ const { req } = options;
23
+ if (isValidTenantAssignment({
24
+ previousValue: options.previousValue,
25
+ req,
26
+ tenantsArrayFieldName,
27
+ tenantsArrayTenantFieldName,
28
+ userHasAccessToAllTenants,
29
+ value
30
+ })) {
31
+ return true;
32
+ }
33
+ return req.t('validation:invalidSelection');
22
34
  };
23
- export const tenantField = ({ name = defaults.tenantFieldName, debug, isAutosaveEnabled, overrides: _overrides = {}, tenantsArrayFieldName = defaults.tenantsArrayFieldName, tenantsArrayTenantFieldName = defaults.tenantsArrayTenantFieldName, tenantsCollectionSlug = defaults.tenantCollectionSlug, unique })=>{
35
+ export const tenantField = ({ name = defaults.tenantFieldName, adminUsersSlug, debug, isAutosaveEnabled, overrides: _overrides = {}, tenantsArrayFieldName = defaults.tenantsArrayFieldName, tenantsArrayTenantFieldName = defaults.tenantsArrayTenantFieldName, tenantsCollectionSlug = defaults.tenantCollectionSlug, unique, userHasAccessToAllTenants })=>{
24
36
  const { hasMany = false, validate, ...overrides } = _overrides || {};
25
37
  return {
26
38
  ...overrides || {},
27
39
  name,
28
40
  type: 'relationship',
29
- access: overrides.access || {},
41
+ // Only users of the tenant-managed collection may write the tenant field. Other auth
42
+ // collections carry no tenants, so they must not set or change it. Skipped when
43
+ // `adminUsersSlug` is absent (a config placing this field through `customTenantField`).
44
+ access: {
45
+ ...adminUsersSlug ? {
46
+ create: ({ req })=>Boolean(req.user && req.user.collection === adminUsersSlug),
47
+ update: ({ req })=>Boolean(req.user && req.user.collection === adminUsersSlug)
48
+ } : {},
49
+ ...overrides.access || {}
50
+ },
30
51
  admin: {
31
52
  allowCreate: false,
32
53
  allowEdit: false,
@@ -55,7 +76,7 @@ export const tenantField = ({ name = defaults.tenantFieldName, debug, isAutosave
55
76
  });
56
77
  const tenantFromCookie = getTenantFromCookie(req.headers, idType);
57
78
  if (tenantFromCookie) {
58
- const isValidTenant = await req.payload.count({
79
+ const { totalDocs } = await req.payload.count({
59
80
  collection: tenantsCollectionSlug,
60
81
  overrideAccess: false,
61
82
  req,
@@ -68,7 +89,7 @@ export const tenantField = ({ name = defaults.tenantFieldName, debug, isAutosave
68
89
  }
69
90
  }
70
91
  });
71
- return isValidTenant ? tenantFromCookie : null;
92
+ return totalDocs > 0 ? tenantFromCookie : null;
72
93
  }
73
94
  if (req.user && isAutosaveEnabled) {
74
95
  const userTenants = getUserTenantIDs(req.user, {
@@ -100,12 +121,20 @@ export const tenantField = ({ name = defaults.tenantFieldName, debug, isAutosave
100
121
  unique,
101
122
  ...hasMany ? {
102
123
  hasMany: true,
103
- // TODO: V4 - replace validation with required: true
104
- validate: fieldValidation(validate)
124
+ validate: fieldValidation({
125
+ tenantsArrayFieldName,
126
+ tenantsArrayTenantFieldName,
127
+ userHasAccessToAllTenants,
128
+ validateFunction: validate
129
+ })
105
130
  } : {
106
131
  hasMany: false,
107
- // TODO: V4 - replace validation with required: true
108
- validate: fieldValidation(validate)
132
+ validate: fieldValidation({
133
+ tenantsArrayFieldName,
134
+ tenantsArrayTenantFieldName,
135
+ userHasAccessToAllTenants,
136
+ validateFunction: validate
137
+ })
109
138
  },
110
139
  // @ts-expect-error translations are not typed for this plugin
111
140
  label: overrides.label || (({ t })=>t('plugin-multi-tenant:field-assignedTenant-label'))
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/fields/tenantField/index.ts"],"sourcesContent":["import type { RelationshipFieldValidation, SingleRelationshipField } from 'payload'\n\nimport type { RootTenantFieldConfigOverrides } from '../../types.js'\n\nimport { defaults } from '../../defaults.js'\nimport { getCollectionIDType } from '../../utilities/getCollectionIDType.js'\nimport { getTenantFromCookie } from '../../utilities/getTenantFromCookie.js'\nimport { getUserTenantIDs } from '../../utilities/getUserTenantIDs.js'\n\nconst fieldValidation =\n (validateFunction?: RelationshipFieldValidation): RelationshipFieldValidation =>\n (value, options) => {\n if (validateFunction) {\n const result = validateFunction(value, options)\n if (result !== true) {\n return result\n }\n }\n\n if (options.hasMany) {\n if (!value || (Array.isArray(value) && value.length === 0)) {\n return options.req.t('validation:required')\n }\n } else {\n if (!value) {\n return options.req.t('validation:required')\n }\n }\n\n return true\n }\n\ntype Args = {\n debug?: boolean\n isAutosaveEnabled?: boolean\n name: string\n overrides?: RootTenantFieldConfigOverrides\n tenantsArrayFieldName: string\n tenantsArrayTenantFieldName: string\n tenantsCollectionSlug: string\n unique: boolean\n}\nexport const tenantField = ({\n name = defaults.tenantFieldName,\n debug,\n isAutosaveEnabled,\n overrides: _overrides = {},\n tenantsArrayFieldName = defaults.tenantsArrayFieldName,\n tenantsArrayTenantFieldName = defaults.tenantsArrayTenantFieldName,\n tenantsCollectionSlug = defaults.tenantCollectionSlug,\n unique,\n}: Args): SingleRelationshipField => {\n const { hasMany = false, validate, ...overrides } = _overrides || {}\n return {\n ...(overrides || {}),\n name,\n type: 'relationship',\n access: overrides.access || {},\n admin: {\n allowCreate: false,\n allowEdit: false,\n disableGroupBy: true,\n disableListColumn: true,\n disableListFilter: true,\n position: 'sidebar',\n ...(overrides.admin || {}),\n components: {\n ...(overrides.admin?.components || {}),\n Field: {\n path: '@payloadcms/plugin-multi-tenant/client#TenantField',\n ...(typeof overrides.admin?.components?.Field !== 'string'\n ? overrides.admin?.components?.Field || {}\n : {}),\n clientProps: {\n ...(typeof overrides.admin?.components?.Field !== 'string'\n ? (overrides.admin?.components?.Field || {})?.clientProps\n : {}),\n debug,\n unique,\n },\n },\n },\n },\n defaultValue:\n overrides.defaultValue ||\n (async ({ req }) => {\n const idType = getCollectionIDType({\n collectionSlug: tenantsCollectionSlug,\n payload: req.payload,\n })\n const tenantFromCookie = getTenantFromCookie(req.headers, idType)\n if (tenantFromCookie) {\n const isValidTenant = await req.payload.count({\n collection: tenantsCollectionSlug,\n overrideAccess: false,\n req,\n user: req.user,\n where: {\n id: {\n in: [tenantFromCookie],\n },\n },\n })\n return isValidTenant ? tenantFromCookie : null\n }\n if (req.user && isAutosaveEnabled) {\n const userTenants = getUserTenantIDs(req.user, {\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n })\n if (userTenants.length > 0) {\n return userTenants[0]\n }\n }\n return null\n }),\n filterOptions:\n overrides.filterOptions ||\n (({ req }) => {\n const userAssignedTenants = getUserTenantIDs(req.user, {\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n })\n if (userAssignedTenants.length > 0) {\n return {\n id: {\n in: userAssignedTenants,\n },\n }\n }\n\n return true\n }),\n index: true,\n relationTo: tenantsCollectionSlug,\n unique,\n ...(hasMany\n ? {\n hasMany: true,\n // TODO: V4 - replace validation with required: true\n validate: fieldValidation(validate as RelationshipFieldValidation),\n }\n : {\n hasMany: false,\n // TODO: V4 - replace validation with required: true\n validate: fieldValidation(validate as RelationshipFieldValidation),\n }),\n // @ts-expect-error translations are not typed for this plugin\n label: overrides.label || (({ t }) => t('plugin-multi-tenant:field-assignedTenant-label')),\n }\n}\n"],"names":["defaults","getCollectionIDType","getTenantFromCookie","getUserTenantIDs","fieldValidation","validateFunction","value","options","result","hasMany","Array","isArray","length","req","t","tenantField","name","tenantFieldName","debug","isAutosaveEnabled","overrides","_overrides","tenantsArrayFieldName","tenantsArrayTenantFieldName","tenantsCollectionSlug","tenantCollectionSlug","unique","validate","type","access","admin","allowCreate","allowEdit","disableGroupBy","disableListColumn","disableListFilter","position","components","Field","path","clientProps","defaultValue","idType","collectionSlug","payload","tenantFromCookie","headers","isValidTenant","count","collection","overrideAccess","user","where","id","in","userTenants","filterOptions","userAssignedTenants","index","relationTo","label"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/fields/tenantField/index.ts"],"sourcesContent":["import type { RelationshipFieldValidation, SingleRelationshipField } from 'payload'\n\nimport type { MultiTenantPluginConfig, RootTenantFieldConfigOverrides } from '../../types.js'\n\nimport { defaults } from '../../defaults.js'\nimport { getCollectionIDType } from '../../utilities/getCollectionIDType.js'\nimport { getTenantFromCookie } from '../../utilities/getTenantFromCookie.js'\nimport { getUserTenantIDs } from '../../utilities/getUserTenantIDs.js'\nimport { isValidTenantAssignment } from '../../utilities/isValidTenantAssignment.js'\n\nconst fieldValidation =\n <ConfigType = unknown>({\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n validateFunction,\n }: {\n tenantsArrayFieldName: string\n tenantsArrayTenantFieldName: string\n userHasAccessToAllTenants?: MultiTenantPluginConfig<ConfigType>['userHasAccessToAllTenants']\n validateFunction?: RelationshipFieldValidation\n }): RelationshipFieldValidation =>\n async (value, options) => {\n if (validateFunction) {\n const result = await validateFunction(value, options)\n if (result !== true) {\n return result\n }\n }\n\n if (options.hasMany) {\n if (!value || (Array.isArray(value) && value.length === 0)) {\n return options.req.t('validation:required')\n }\n } else {\n if (!value) {\n return options.req.t('validation:required')\n }\n }\n\n const { req } = options\n\n if (\n isValidTenantAssignment<ConfigType>({\n previousValue: options.previousValue,\n req,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n value,\n })\n ) {\n return true\n }\n\n return req.t('validation:invalidSelection')\n }\n\ntype Args<ConfigType = unknown> = {\n adminUsersSlug?: string\n debug?: boolean\n isAutosaveEnabled?: boolean\n name: string\n overrides?: RootTenantFieldConfigOverrides\n tenantsArrayFieldName: string\n tenantsArrayTenantFieldName: string\n tenantsCollectionSlug: string\n unique: boolean\n userHasAccessToAllTenants?: MultiTenantPluginConfig<ConfigType>['userHasAccessToAllTenants']\n}\nexport const tenantField = <ConfigType = unknown>({\n name = defaults.tenantFieldName,\n adminUsersSlug,\n debug,\n isAutosaveEnabled,\n overrides: _overrides = {},\n tenantsArrayFieldName = defaults.tenantsArrayFieldName,\n tenantsArrayTenantFieldName = defaults.tenantsArrayTenantFieldName,\n tenantsCollectionSlug = defaults.tenantCollectionSlug,\n unique,\n userHasAccessToAllTenants,\n}: Args<ConfigType>): SingleRelationshipField => {\n const { hasMany = false, validate, ...overrides } = _overrides || {}\n return {\n ...(overrides || {}),\n name,\n type: 'relationship',\n // Only users of the tenant-managed collection may write the tenant field. Other auth\n // collections carry no tenants, so they must not set or change it. Skipped when\n // `adminUsersSlug` is absent (a config placing this field through `customTenantField`).\n access: {\n ...(adminUsersSlug\n ? {\n create: ({ req }) => Boolean(req.user && req.user.collection === adminUsersSlug),\n update: ({ req }) => Boolean(req.user && req.user.collection === adminUsersSlug),\n }\n : {}),\n ...(overrides.access || {}),\n },\n admin: {\n allowCreate: false,\n allowEdit: false,\n disableGroupBy: true,\n disableListColumn: true,\n disableListFilter: true,\n position: 'sidebar',\n ...(overrides.admin || {}),\n components: {\n ...(overrides.admin?.components || {}),\n Field: {\n path: '@payloadcms/plugin-multi-tenant/client#TenantField',\n ...(typeof overrides.admin?.components?.Field !== 'string'\n ? overrides.admin?.components?.Field || {}\n : {}),\n clientProps: {\n ...(typeof overrides.admin?.components?.Field !== 'string'\n ? (overrides.admin?.components?.Field || {})?.clientProps\n : {}),\n debug,\n unique,\n },\n },\n },\n },\n defaultValue:\n overrides.defaultValue ||\n (async ({ req }) => {\n const idType = getCollectionIDType({\n collectionSlug: tenantsCollectionSlug,\n payload: req.payload,\n })\n const tenantFromCookie = getTenantFromCookie(req.headers, idType)\n if (tenantFromCookie) {\n const { totalDocs } = await req.payload.count({\n collection: tenantsCollectionSlug,\n overrideAccess: false,\n req,\n user: req.user,\n where: {\n id: {\n in: [tenantFromCookie],\n },\n },\n })\n return totalDocs > 0 ? tenantFromCookie : null\n }\n if (req.user && isAutosaveEnabled) {\n const userTenants = getUserTenantIDs(req.user, {\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n })\n if (userTenants.length > 0) {\n return userTenants[0]\n }\n }\n return null\n }),\n filterOptions:\n overrides.filterOptions ||\n (({ req }) => {\n const userAssignedTenants = getUserTenantIDs(req.user, {\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n })\n if (userAssignedTenants.length > 0) {\n return {\n id: {\n in: userAssignedTenants,\n },\n }\n }\n\n return true\n }),\n index: true,\n relationTo: tenantsCollectionSlug,\n unique,\n ...(hasMany\n ? {\n hasMany: true,\n validate: fieldValidation<ConfigType>({\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n validateFunction: validate as RelationshipFieldValidation,\n }),\n }\n : {\n hasMany: false,\n validate: fieldValidation<ConfigType>({\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n validateFunction: validate as RelationshipFieldValidation,\n }),\n }),\n // @ts-expect-error translations are not typed for this plugin\n label: overrides.label || (({ t }) => t('plugin-multi-tenant:field-assignedTenant-label')),\n }\n}\n"],"names":["defaults","getCollectionIDType","getTenantFromCookie","getUserTenantIDs","isValidTenantAssignment","fieldValidation","tenantsArrayFieldName","tenantsArrayTenantFieldName","userHasAccessToAllTenants","validateFunction","value","options","result","hasMany","Array","isArray","length","req","t","previousValue","tenantField","name","tenantFieldName","adminUsersSlug","debug","isAutosaveEnabled","overrides","_overrides","tenantsCollectionSlug","tenantCollectionSlug","unique","validate","type","access","create","Boolean","user","collection","update","admin","allowCreate","allowEdit","disableGroupBy","disableListColumn","disableListFilter","position","components","Field","path","clientProps","defaultValue","idType","collectionSlug","payload","tenantFromCookie","headers","totalDocs","count","overrideAccess","where","id","in","userTenants","filterOptions","userAssignedTenants","index","relationTo","label"],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { tenantField } from './index.js';
3
+ const baseArgs = {
4
+ adminUsersSlug: 'users',
5
+ name: 'tenant',
6
+ tenantsArrayFieldName: 'tenants',
7
+ tenantsArrayTenantFieldName: 'tenant',
8
+ tenantsCollectionSlug: 'tenants',
9
+ unique: false
10
+ };
11
+ describe('tenantField access', ()=>{
12
+ it('should let the admin users collection write the tenant field', ()=>{
13
+ const field = tenantField(baseArgs);
14
+ const req = {
15
+ user: {
16
+ collection: 'users'
17
+ }
18
+ };
19
+ expect(field.access.create({
20
+ req
21
+ })).toBe(true);
22
+ expect(field.access.update({
23
+ req
24
+ })).toBe(true);
25
+ });
26
+ it('should block other auth collections from writing the tenant field', ()=>{
27
+ const field = tenantField(baseArgs);
28
+ const req = {
29
+ user: {
30
+ collection: 'customers'
31
+ }
32
+ };
33
+ expect(field.access.create({
34
+ req
35
+ })).toBe(false);
36
+ expect(field.access.update({
37
+ req
38
+ })).toBe(false);
39
+ });
40
+ it('should block an unauthenticated request from writing the tenant field', ()=>{
41
+ const field = tenantField(baseArgs);
42
+ const req = {
43
+ user: null
44
+ };
45
+ expect(field.access.create({
46
+ req
47
+ })).toBe(false);
48
+ expect(field.access.update({
49
+ req
50
+ })).toBe(false);
51
+ });
52
+ });
53
+
54
+ //# sourceMappingURL=index.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/fields/tenantField/index.spec.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest'\n\nimport { tenantField } from './index.js'\n\nconst baseArgs = {\n adminUsersSlug: 'users',\n name: 'tenant',\n tenantsArrayFieldName: 'tenants',\n tenantsArrayTenantFieldName: 'tenant',\n tenantsCollectionSlug: 'tenants',\n unique: false,\n}\n\ndescribe('tenantField access', () => {\n it('should let the admin users collection write the tenant field', () => {\n const field = tenantField(baseArgs)\n const req = { user: { collection: 'users' } }\n\n expect(field.access!.create!({ req } as never)).toBe(true)\n expect(field.access!.update!({ req } as never)).toBe(true)\n })\n\n it('should block other auth collections from writing the tenant field', () => {\n const field = tenantField(baseArgs)\n const req = { user: { collection: 'customers' } }\n\n expect(field.access!.create!({ req } as never)).toBe(false)\n expect(field.access!.update!({ req } as never)).toBe(false)\n })\n\n it('should block an unauthenticated request from writing the tenant field', () => {\n const field = tenantField(baseArgs)\n const req = { user: null }\n\n expect(field.access!.create!({ req } as never)).toBe(false)\n expect(field.access!.update!({ req } as never)).toBe(false)\n })\n})\n"],"names":["describe","expect","it","tenantField","baseArgs","adminUsersSlug","name","tenantsArrayFieldName","tenantsArrayTenantFieldName","tenantsCollectionSlug","unique","field","req","user","collection","access","create","toBe","update"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAE7C,SAASC,WAAW,QAAQ,aAAY;AAExC,MAAMC,WAAW;IACfC,gBAAgB;IAChBC,MAAM;IACNC,uBAAuB;IACvBC,6BAA6B;IAC7BC,uBAAuB;IACvBC,QAAQ;AACV;AAEAV,SAAS,sBAAsB;IAC7BE,GAAG,gEAAgE;QACjE,MAAMS,QAAQR,YAAYC;QAC1B,MAAMQ,MAAM;YAAEC,MAAM;gBAAEC,YAAY;YAAQ;QAAE;QAE5Cb,OAAOU,MAAMI,MAAM,CAAEC,MAAM,CAAE;YAAEJ;QAAI,IAAaK,IAAI,CAAC;QACrDhB,OAAOU,MAAMI,MAAM,CAAEG,MAAM,CAAE;YAAEN;QAAI,IAAaK,IAAI,CAAC;IACvD;IAEAf,GAAG,qEAAqE;QACtE,MAAMS,QAAQR,YAAYC;QAC1B,MAAMQ,MAAM;YAAEC,MAAM;gBAAEC,YAAY;YAAY;QAAE;QAEhDb,OAAOU,MAAMI,MAAM,CAAEC,MAAM,CAAE;YAAEJ;QAAI,IAAaK,IAAI,CAAC;QACrDhB,OAAOU,MAAMI,MAAM,CAAEG,MAAM,CAAE;YAAEN;QAAI,IAAaK,IAAI,CAAC;IACvD;IAEAf,GAAG,yEAAyE;QAC1E,MAAMS,QAAQR,YAAYC;QAC1B,MAAMQ,MAAM;YAAEC,MAAM;QAAK;QAEzBZ,OAAOU,MAAMI,MAAM,CAAEC,MAAM,CAAE;YAAEJ;QAAI,IAAaK,IAAI,CAAC;QACrDhB,OAAOU,MAAMI,MAAM,CAAEG,MAAM,CAAE;YAAEN;QAAI,IAAaK,IAAI,CAAC;IACvD;AACF"}
@@ -0,0 +1,20 @@
1
+ import type { CollectionConfig } from 'payload';
2
+ import type { MultiTenantPluginConfig } from '../types.js';
3
+ type Args<ConfigType = unknown> = {
4
+ collection: CollectionConfig;
5
+ tenantFieldName: string;
6
+ tenantsArrayFieldName: string;
7
+ tenantsArrayTenantFieldName: string;
8
+ userHasAccessToAllTenants: Required<MultiTenantPluginConfig<ConfigType>>['userHasAccessToAllTenants'];
9
+ };
10
+ /**
11
+ * Reject writes that assign a tenant the user is not a member of.
12
+ *
13
+ * The tenant field's own `validate` covers this on ordinary writes and gives the
14
+ * admin panel an inline field error, but Payload skips field validation for draft,
15
+ * autosave, trash and restore-version writes. A collection `beforeValidate` hook
16
+ * always runs, so this is the check that actually closes those paths.
17
+ */
18
+ export declare const addCollectionBeforeValidateHook: <ConfigType = unknown>({ collection, tenantFieldName, tenantsArrayFieldName, tenantsArrayTenantFieldName, userHasAccessToAllTenants, }: Args<ConfigType>) => void;
19
+ export {};
20
+ //# sourceMappingURL=enforceTenantMembership.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enforceTenantMembership.d.ts","sourceRoot":"","sources":["../../src/hooks/enforceTenantMembership.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgC,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAI7E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAI1D,KAAK,IAAI,CAAC,UAAU,GAAG,OAAO,IAAI;IAChC,UAAU,EAAE,gBAAgB,CAAA;IAC5B,eAAe,EAAE,MAAM,CAAA;IACvB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,2BAA2B,EAAE,MAAM,CAAA;IACnC,yBAAyB,EAAE,QAAQ,CACjC,uBAAuB,CAAC,UAAU,CAAC,CACpC,CAAC,2BAA2B,CAAC,CAAA;CAC/B,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,+BAA+B,GAAI,UAAU,6HAMvD,IAAI,CAAC,UAAU,CAAC,SAYlB,CAAA"}
@@ -0,0 +1,46 @@
1
+ import { ValidationError } from 'payload';
2
+ import { isValidTenantAssignment } from '../utilities/isValidTenantAssignment.js';
3
+ /**
4
+ * Reject writes that assign a tenant the user is not a member of.
5
+ *
6
+ * The tenant field's own `validate` covers this on ordinary writes and gives the
7
+ * admin panel an inline field error, but Payload skips field validation for draft,
8
+ * autosave, trash and restore-version writes. A collection `beforeValidate` hook
9
+ * always runs, so this is the check that actually closes those paths.
10
+ */ export const addCollectionBeforeValidateHook = ({ collection, tenantFieldName, tenantsArrayFieldName, tenantsArrayTenantFieldName, userHasAccessToAllTenants })=>{
11
+ collection.hooks ??= {};
12
+ collection.hooks.beforeValidate ??= [];
13
+ collection.hooks.beforeValidate.push(enforceTenantMembership({
14
+ collectionSlug: collection.slug,
15
+ tenantFieldName,
16
+ tenantsArrayFieldName,
17
+ tenantsArrayTenantFieldName,
18
+ userHasAccessToAllTenants
19
+ }));
20
+ };
21
+ const enforceTenantMembership = ({ collectionSlug, tenantFieldName, tenantsArrayFieldName, tenantsArrayTenantFieldName, userHasAccessToAllTenants })=>({ data, originalDoc, req })=>{
22
+ if (!data || !(tenantFieldName in data)) {
23
+ return data;
24
+ }
25
+ if (!isValidTenantAssignment({
26
+ previousValue: originalDoc?.[tenantFieldName],
27
+ req,
28
+ tenantsArrayFieldName,
29
+ tenantsArrayTenantFieldName,
30
+ userHasAccessToAllTenants,
31
+ value: data[tenantFieldName]
32
+ })) {
33
+ throw new ValidationError({
34
+ collection: collectionSlug,
35
+ errors: [
36
+ {
37
+ message: req.t('validation:invalidSelection'),
38
+ path: tenantFieldName
39
+ }
40
+ ]
41
+ }, req.t);
42
+ }
43
+ return data;
44
+ };
45
+
46
+ //# sourceMappingURL=enforceTenantMembership.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/hooks/enforceTenantMembership.ts"],"sourcesContent":["import type { CollectionBeforeValidateHook, CollectionConfig } from 'payload'\n\nimport { ValidationError } from 'payload'\n\nimport type { MultiTenantPluginConfig } from '../types.js'\n\nimport { isValidTenantAssignment } from '../utilities/isValidTenantAssignment.js'\n\ntype Args<ConfigType = unknown> = {\n collection: CollectionConfig\n tenantFieldName: string\n tenantsArrayFieldName: string\n tenantsArrayTenantFieldName: string\n userHasAccessToAllTenants: Required<\n MultiTenantPluginConfig<ConfigType>\n >['userHasAccessToAllTenants']\n}\n\n/**\n * Reject writes that assign a tenant the user is not a member of.\n *\n * The tenant field's own `validate` covers this on ordinary writes and gives the\n * admin panel an inline field error, but Payload skips field validation for draft,\n * autosave, trash and restore-version writes. A collection `beforeValidate` hook\n * always runs, so this is the check that actually closes those paths.\n */\nexport const addCollectionBeforeValidateHook = <ConfigType = unknown>({\n collection,\n tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n}: Args<ConfigType>) => {\n collection.hooks ??= {}\n collection.hooks.beforeValidate ??= []\n collection.hooks.beforeValidate.push(\n enforceTenantMembership<ConfigType>({\n collectionSlug: collection.slug,\n tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n }),\n )\n}\n\nconst enforceTenantMembership =\n <ConfigType = unknown>({\n collectionSlug,\n tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n }: { collectionSlug: string } & Omit<\n Args<ConfigType>,\n 'collection'\n >): CollectionBeforeValidateHook =>\n ({ data, originalDoc, req }) => {\n if (!data || !(tenantFieldName in data)) {\n return data\n }\n\n if (\n !isValidTenantAssignment<ConfigType>({\n previousValue: originalDoc?.[tenantFieldName],\n req,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n value: (data as Record<string, unknown>)[tenantFieldName],\n })\n ) {\n throw new ValidationError(\n {\n collection: collectionSlug,\n errors: [{ message: req.t('validation:invalidSelection'), path: tenantFieldName }],\n },\n req.t,\n )\n }\n\n return data\n }\n"],"names":["ValidationError","isValidTenantAssignment","addCollectionBeforeValidateHook","collection","tenantFieldName","tenantsArrayFieldName","tenantsArrayTenantFieldName","userHasAccessToAllTenants","hooks","beforeValidate","push","enforceTenantMembership","collectionSlug","slug","data","originalDoc","req","previousValue","value","errors","message","t","path"],"mappings":"AAEA,SAASA,eAAe,QAAQ,UAAS;AAIzC,SAASC,uBAAuB,QAAQ,0CAAyC;AAYjF;;;;;;;CAOC,GACD,OAAO,MAAMC,kCAAkC,CAAuB,EACpEC,UAAU,EACVC,eAAe,EACfC,qBAAqB,EACrBC,2BAA2B,EAC3BC,yBAAyB,EACR;IACjBJ,WAAWK,KAAK,KAAK,CAAC;IACtBL,WAAWK,KAAK,CAACC,cAAc,KAAK,EAAE;IACtCN,WAAWK,KAAK,CAACC,cAAc,CAACC,IAAI,CAClCC,wBAAoC;QAClCC,gBAAgBT,WAAWU,IAAI;QAC/BT;QACAC;QACAC;QACAC;IACF;AAEJ,EAAC;AAED,MAAMI,0BACJ,CAAuB,EACrBC,cAAc,EACdR,eAAe,EACfC,qBAAqB,EACrBC,2BAA2B,EAC3BC,yBAAyB,EAI1B,GACD,CAAC,EAAEO,IAAI,EAAEC,WAAW,EAAEC,GAAG,EAAE;QACzB,IAAI,CAACF,QAAQ,CAAEV,CAAAA,mBAAmBU,IAAG,GAAI;YACvC,OAAOA;QACT;QAEA,IACE,CAACb,wBAAoC;YACnCgB,eAAeF,aAAa,CAACX,gBAAgB;YAC7CY;YACAX;YACAC;YACAC;YACAW,OAAO,AAACJ,IAAgC,CAACV,gBAAgB;QAC3D,IACA;YACA,MAAM,IAAIJ,gBACR;gBACEG,YAAYS;gBACZO,QAAQ;oBAAC;wBAAEC,SAASJ,IAAIK,CAAC,CAAC;wBAAgCC,MAAMlB;oBAAgB;iBAAE;YACpF,GACAY,IAAIK,CAAC;QAET;QAEA,OAAOP;IACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAoB,MAAM,EAAa,MAAM,SAAS,CAAA;AAMlE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAczD,eAAO,MAAM,iBAAiB,GAC3B,UAAU,gBAAgB,uBAAuB,CAAC,UAAU,CAAC,sBAC7C,MAAM,KAAG,MAshBzB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAoB,MAAM,EAAa,MAAM,SAAS,CAAA;AAMlE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAezD,eAAO,MAAM,iBAAiB,GAC3B,UAAU,gBAAgB,uBAAuB,CAAC,UAAU,CAAC,sBAC7C,MAAM,KAAG,MAkjBzB,CAAA"}
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import { tenantField } from './fields/tenantField/index.js';
5
5
  import { tenantsArrayField } from './fields/tenantsArrayField/index.js';
6
6
  import { filterDocumentsByTenants } from './filters/filterDocumentsByTenants.js';
7
7
  import { addTenantCleanup } from './hooks/afterTenantDelete.js';
8
+ import { addCollectionBeforeValidateHook } from './hooks/enforceTenantMembership.js';
8
9
  import { translations } from './translations/index.js';
9
10
  import { addCollectionAccess } from './utilities/addCollectionAccess.js';
10
11
  import { addFilterOptionsToFields } from './utilities/addFilterOptionsToFields.js';
@@ -146,15 +147,27 @@ export const multiTenantPlugin = (pluginConfig)=>(incomingConfig)=>{
146
147
  * Add tenant field to enabled collections
147
148
  */ collection.fields.unshift(tenantField({
148
149
  name: tenantFieldName,
150
+ adminUsersSlug: adminUsersCollection.slug,
149
151
  debug: pluginConfig.debug,
150
152
  isAutosaveEnabled: hasAutosaveEnabled(collection),
151
153
  overrides: pluginConfig.collections[collection.slug]?.tenantFieldOverrides ? pluginConfig.collections[collection.slug]?.tenantFieldOverrides : pluginConfig.tenantField || {},
152
154
  tenantsArrayFieldName,
153
155
  tenantsArrayTenantFieldName,
154
156
  tenantsCollectionSlug,
155
- unique: false
157
+ unique: false,
158
+ userHasAccessToAllTenants
156
159
  }));
157
160
  }
161
+ /**
162
+ * Reject writes that assign a tenant the user is not a member of
163
+ * - covers drafts, autosave and restore-version, which skip field validation
164
+ */ addCollectionBeforeValidateHook({
165
+ collection,
166
+ tenantFieldName,
167
+ tenantsArrayFieldName,
168
+ tenantsArrayTenantFieldName,
169
+ userHasAccessToAllTenants
170
+ });
158
171
  const { useBaseFilter, useBaseListFilter } = pluginConfig.collections[collection.slug] || {};
159
172
  if (useBaseFilter ?? useBaseListFilter ?? true) {
160
173
  /**
@@ -311,15 +324,27 @@ export const multiTenantPlugin = (pluginConfig)=>(incomingConfig)=>{
311
324
  * Add tenant field to enabled collections
312
325
  */ collection.fields.unshift(tenantField({
313
326
  name: tenantFieldName,
327
+ adminUsersSlug: adminUsersCollection.slug,
314
328
  debug: pluginConfig.debug,
315
329
  isAutosaveEnabled: hasAutosaveEnabled(collection),
316
330
  overrides: pluginConfig.collections[collection.slug]?.tenantFieldOverrides ? pluginConfig.collections[collection.slug]?.tenantFieldOverrides : pluginConfig.tenantField || {},
317
331
  tenantsArrayFieldName,
318
332
  tenantsArrayTenantFieldName,
319
333
  tenantsCollectionSlug,
320
- unique: isGlobal
334
+ unique: isGlobal,
335
+ userHasAccessToAllTenants
321
336
  }));
322
337
  }
338
+ /**
339
+ * Reject writes that assign a tenant the user is not a member of
340
+ * - covers drafts, autosave and restore-version, which skip field validation
341
+ */ addCollectionBeforeValidateHook({
342
+ collection,
343
+ tenantFieldName,
344
+ tenantsArrayFieldName,
345
+ tenantsArrayTenantFieldName,
346
+ userHasAccessToAllTenants
347
+ });
323
348
  const { useBaseFilter, useBaseListFilter } = pluginConfig.collections[collection.slug] || {};
324
349
  if (useBaseFilter ?? useBaseListFilter ?? true) {
325
350
  /**
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, Config, TypedUser } from 'payload'\n\nimport chalk from 'chalk'\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 =\n <ConfigType>(pluginConfig: MultiTenantPluginConfig<ConfigType>) =>\n (incomingConfig: Config): Config => {\n if (pluginConfig.enabled === false) {\n return incomingConfig\n }\n\n /**\n * Set defaults\n */\n const userHasAccessToAllTenants: Required<\n MultiTenantPluginConfig<ConfigType>\n >['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 }) =>\n Boolean(\n req.user &&\n userHasAccessToAllTenants(\n req.user as ConfigType extends { user: unknown }\n ? ConfigType['user']\n : TypedUser,\n ),\n ),\n update: ({ req }) =>\n Boolean(\n req.user &&\n userHasAccessToAllTenants(\n req.user as ConfigType extends { user: unknown }\n ? ConfigType['user']\n : TypedUser,\n ),\n ),\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<ConfigType>({\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 * The folders collection is added AFTER the plugin is initialized\n * so if they added the folder slug to the plugin collections,\n * we can assume that they have folders enabled\n */\n const foldersSlug = incomingConfig.folders\n ? incomingConfig.folders.slug || 'payload-folders'\n : 'payload-folders'\n\n if (collectionSlugs.includes(foldersSlug)) {\n multiTenantCollectionsFound.push(foldersSlug)\n incomingConfig.folders = incomingConfig.folders || {}\n incomingConfig.folders.collectionOverrides = incomingConfig.folders.collectionOverrides || []\n incomingConfig.folders.collectionOverrides.push(({ collection }) => {\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[foldersSlug]?.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: false,\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<ConfigType>({\n filterFieldName: tenantFieldName,\n req: args.req,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n userHasAccessToAllTenants,\n }),\n })\n }\n\n if (pluginConfig.collections[foldersSlug]?.useTenantAccess !== false) {\n /**\n * Add access control constraint to tenant enabled folders collection\n */\n addCollectionAccess({\n accessResultCallback: pluginConfig.collections[foldersSlug]?.accessResultOverride,\n adminUsersSlug: adminUsersCollection.slug,\n collection,\n fieldName: tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n })\n }\n\n return collection\n })\n }\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 disableBulkEdit: true,\n disableListColumn: 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"],"names":["hasAutosaveEnabled","defaults","getTenantOptionsEndpoint","tenantField","tenantsArrayField","filterDocumentsByTenants","addTenantCleanup","translations","addCollectionAccess","addFilterOptionsToFields","combineFilters","miniChalk","multiTenantPlugin","pluginConfig","incomingConfig","enabled","userHasAccessToAllTenants","tenantsCollectionSlug","tenantsSlug","tenantCollectionSlug","tenantFieldName","name","tenantsArrayFieldName","arrayFieldName","tenantsArrayTenantFieldName","arrayTenantFieldName","admin","components","actions","beforeNav","providers","collections","adminUsersCollection","find","slug","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","foldersSlug","folders","includes","collectionOverrides","config","tenantEnabledCollectionSlugs","tenantEnabledGlobalSlugs","customTenantField","unshift","debug","isAutosaveEnabled","overrides","tenantFieldOverrides","unique","useBaseFilter","useBaseListFilter","useTenantAccess","accessResultOverride","forEach","useTenantsCollectionAccess","useTenantsListFilter","cleanupAfterTenantDelete","enabledSlugs","usersSlug","usersTenantsArrayFieldName","usersTenantsArrayTenantFieldName","type","Field","path","disableBulkEdit","disableListColumn","endpoints","useAsTitle","console","warn","disableDuplicate","edit","editMenuItems","length","missingSlugs","filter","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, Config, TypedUser } from 'payload'\n\nimport chalk from 'chalk'\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 { addCollectionBeforeValidateHook } from './hooks/enforceTenantMembership.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 =\n <ConfigType>(pluginConfig: MultiTenantPluginConfig<ConfigType>) =>\n (incomingConfig: Config): Config => {\n if (pluginConfig.enabled === false) {\n return incomingConfig\n }\n\n /**\n * Set defaults\n */\n const userHasAccessToAllTenants: Required<\n MultiTenantPluginConfig<ConfigType>\n >['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 }) =>\n Boolean(\n req.user &&\n userHasAccessToAllTenants(\n req.user as ConfigType extends { user: unknown }\n ? ConfigType['user']\n : TypedUser,\n ),\n ),\n update: ({ req }) =>\n Boolean(\n req.user &&\n userHasAccessToAllTenants(\n req.user as ConfigType extends { user: unknown }\n ? ConfigType['user']\n : TypedUser,\n ),\n ),\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<ConfigType>({\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 * The folders collection is added AFTER the plugin is initialized\n * so if they added the folder slug to the plugin collections,\n * we can assume that they have folders enabled\n */\n const foldersSlug = incomingConfig.folders\n ? incomingConfig.folders.slug || 'payload-folders'\n : 'payload-folders'\n\n if (collectionSlugs.includes(foldersSlug)) {\n multiTenantCollectionsFound.push(foldersSlug)\n incomingConfig.folders = incomingConfig.folders || {}\n incomingConfig.folders.collectionOverrides = incomingConfig.folders.collectionOverrides || []\n incomingConfig.folders.collectionOverrides.push(({ collection }) => {\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[foldersSlug]?.customTenantField !== true) {\n /**\n * Add tenant field to enabled collections\n */\n collection.fields.unshift(\n tenantField<ConfigType>({\n name: tenantFieldName,\n adminUsersSlug: adminUsersCollection.slug,\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: false,\n userHasAccessToAllTenants,\n }),\n )\n }\n\n /**\n * Reject writes that assign a tenant the user is not a member of\n * - covers drafts, autosave and restore-version, which skip field validation\n */\n addCollectionBeforeValidateHook<ConfigType>({\n collection,\n tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\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<ConfigType>({\n filterFieldName: tenantFieldName,\n req: args.req,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n userHasAccessToAllTenants,\n }),\n })\n }\n\n if (pluginConfig.collections[foldersSlug]?.useTenantAccess !== false) {\n /**\n * Add access control constraint to tenant enabled folders collection\n */\n addCollectionAccess({\n accessResultCallback: pluginConfig.collections[foldersSlug]?.accessResultOverride,\n adminUsersSlug: adminUsersCollection.slug,\n collection,\n fieldName: tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n })\n }\n\n return collection\n })\n }\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 disableBulkEdit: true,\n disableListColumn: 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<ConfigType>({\n name: tenantFieldName,\n adminUsersSlug: adminUsersCollection.slug,\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 userHasAccessToAllTenants,\n }),\n )\n }\n\n /**\n * Reject writes that assign a tenant the user is not a member of\n * - covers drafts, autosave and restore-version, which skip field validation\n */\n addCollectionBeforeValidateHook<ConfigType>({\n collection,\n tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\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"],"names":["hasAutosaveEnabled","defaults","getTenantOptionsEndpoint","tenantField","tenantsArrayField","filterDocumentsByTenants","addTenantCleanup","addCollectionBeforeValidateHook","translations","addCollectionAccess","addFilterOptionsToFields","combineFilters","miniChalk","multiTenantPlugin","pluginConfig","incomingConfig","enabled","userHasAccessToAllTenants","tenantsCollectionSlug","tenantsSlug","tenantCollectionSlug","tenantFieldName","name","tenantsArrayFieldName","arrayFieldName","tenantsArrayTenantFieldName","arrayTenantFieldName","admin","components","actions","beforeNav","providers","collections","adminUsersCollection","find","slug","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","foldersSlug","folders","includes","collectionOverrides","config","tenantEnabledCollectionSlugs","tenantEnabledGlobalSlugs","customTenantField","unshift","debug","isAutosaveEnabled","overrides","tenantFieldOverrides","unique","useBaseFilter","useBaseListFilter","useTenantAccess","accessResultOverride","forEach","useTenantsCollectionAccess","useTenantsListFilter","cleanupAfterTenantDelete","enabledSlugs","usersSlug","usersTenantsArrayFieldName","usersTenantsArrayTenantFieldName","type","Field","path","disableBulkEdit","disableListColumn","endpoints","useAsTitle","console","warn","disableDuplicate","edit","editMenuItems","length","missingSlugs","filter","error","yellowBold","clientProps","serverProps","globalSlugs","label","tenantSelectorLabel","undefined","i18n","entries","locale","pluginI18nObject","typedLocale"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const getTenantIDsFromValue: (value: unknown) => string[];
2
+ //# sourceMappingURL=getTenantIDsFromValue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getTenantIDsFromValue.d.ts","sourceRoot":"","sources":["../../src/utilities/getTenantIDsFromValue.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,qBAAqB,UAAW,OAAO,KAAG,MAAM,EAU5D,CAAA"}
@@ -0,0 +1,14 @@
1
+ import { extractID } from './extractID.js';
2
+ export const getTenantIDsFromValue = (value)=>{
3
+ if (value === undefined || value === null) {
4
+ return [];
5
+ }
6
+ return (Array.isArray(value) ? value : [
7
+ value
8
+ ]).map((entry)=>{
9
+ const id = entry === null || entry === undefined ? undefined : extractID(entry);
10
+ return typeof id === 'number' || typeof id === 'string' ? String(id) : '';
11
+ });
12
+ };
13
+
14
+ //# sourceMappingURL=getTenantIDsFromValue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utilities/getTenantIDsFromValue.ts"],"sourcesContent":["import type { Tenant } from '../types.js'\n\nimport { extractID } from './extractID.js'\n\nexport const getTenantIDsFromValue = (value: unknown): string[] => {\n if (value === undefined || value === null) {\n return []\n }\n\n return (Array.isArray(value) ? value : [value]).map((entry) => {\n const id = entry === null || entry === undefined ? undefined : extractID(entry as Tenant)\n\n return typeof id === 'number' || typeof id === 'string' ? String(id) : ''\n })\n}\n"],"names":["extractID","getTenantIDsFromValue","value","undefined","Array","isArray","map","entry","id","String"],"mappings":"AAEA,SAASA,SAAS,QAAQ,iBAAgB;AAE1C,OAAO,MAAMC,wBAAwB,CAACC;IACpC,IAAIA,UAAUC,aAAaD,UAAU,MAAM;QACzC,OAAO,EAAE;IACX;IAEA,OAAO,AAACE,CAAAA,MAAMC,OAAO,CAACH,SAASA,QAAQ;QAACA;KAAM,AAAD,EAAGI,GAAG,CAAC,CAACC;QACnD,MAAMC,KAAKD,UAAU,QAAQA,UAAUJ,YAAYA,YAAYH,UAAUO;QAEzE,OAAO,OAAOC,OAAO,YAAY,OAAOA,OAAO,WAAWC,OAAOD,MAAM;IACzE;AACF,EAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"getUserTenantIDs.d.ts","sourceRoot":"","sources":["../../src/utilities/getUserTenantIDs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAK/D;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM,SAAS,MAAM,GAAG,MAAM,QACvD,IAAI,GAAG,oBAAoB,YACvB;IACR,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,2BAA2B,CAAC,EAAE,MAAM,CAAA;CACrC,KACA,MAAM,EAoBR,CAAA"}
1
+ {"version":3,"file":"getUserTenantIDs.d.ts","sourceRoot":"","sources":["../../src/utilities/getUserTenantIDs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAK/D;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM,SAAS,MAAM,GAAG,MAAM,QACvD,IAAI,GAAG,oBAAoB,YACvB;IACR,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,2BAA2B,CAAC,EAAE,MAAM,CAAA;CACrC,KACA,MAAM,EAqBR,CAAA"}
@@ -11,8 +11,9 @@ import { extractID } from './extractID.js';
11
11
  const tenantsArrayFieldName = options?.tenantsArrayFieldName || defaults.tenantsArrayFieldName;
12
12
  const tenantsArrayTenantFieldName = options?.tenantsArrayTenantFieldName || defaults.tenantsArrayTenantFieldName;
13
13
  return (Array.isArray(user[tenantsArrayFieldName]) ? user[tenantsArrayFieldName] : [])?.reduce((acc, row)=>{
14
- if (row[tenantsArrayTenantFieldName]) {
15
- acc.push(extractID(row[tenantsArrayTenantFieldName]));
14
+ const tenantRow = row[tenantsArrayTenantFieldName];
15
+ if (tenantRow !== undefined && tenantRow !== null) {
16
+ acc.push(extractID(tenantRow));
16
17
  }
17
18
  return acc;
18
19
  }, []) || [];
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/getUserTenantIDs.ts"],"sourcesContent":["import type { Tenant, UserWithTenantsField } from '../types.js'\n\nimport { defaults } from '../defaults.js'\nimport { extractID } from './extractID.js'\n\n/**\n * Returns array of all tenant IDs assigned to a user\n *\n * @param user - User object with tenants field\n */\nexport const getUserTenantIDs = <IDType extends number | string>(\n user: null | UserWithTenantsField,\n options?: {\n tenantsArrayFieldName?: string\n tenantsArrayTenantFieldName?: string\n },\n): IDType[] => {\n if (!user) {\n return []\n }\n\n const tenantsArrayFieldName = options?.tenantsArrayFieldName || defaults.tenantsArrayFieldName\n const tenantsArrayTenantFieldName =\n options?.tenantsArrayTenantFieldName || defaults.tenantsArrayTenantFieldName\n\n return (\n (Array.isArray(user[tenantsArrayFieldName]) ? user[tenantsArrayFieldName] : [])?.reduce<\n IDType[]\n >((acc, row) => {\n if (row[tenantsArrayTenantFieldName]) {\n acc.push(extractID<IDType>(row[tenantsArrayTenantFieldName] as Tenant<IDType>))\n }\n\n return acc\n }, []) || []\n )\n}\n"],"names":["defaults","extractID","getUserTenantIDs","user","options","tenantsArrayFieldName","tenantsArrayTenantFieldName","Array","isArray","reduce","acc","row","push"],"mappings":"AAEA,SAASA,QAAQ,QAAQ,iBAAgB;AACzC,SAASC,SAAS,QAAQ,iBAAgB;AAE1C;;;;CAIC,GACD,OAAO,MAAMC,mBAAmB,CAC9BC,MACAC;IAKA,IAAI,CAACD,MAAM;QACT,OAAO,EAAE;IACX;IAEA,MAAME,wBAAwBD,SAASC,yBAAyBL,SAASK,qBAAqB;IAC9F,MAAMC,8BACJF,SAASE,+BAA+BN,SAASM,2BAA2B;IAE9E,OACE,AAACC,CAAAA,MAAMC,OAAO,CAACL,IAAI,CAACE,sBAAsB,IAAIF,IAAI,CAACE,sBAAsB,GAAG,EAAE,AAAD,GAAII,OAE/E,CAACC,KAAKC;QACN,IAAIA,GAAG,CAACL,4BAA4B,EAAE;YACpCI,IAAIE,IAAI,CAACX,UAAkBU,GAAG,CAACL,4BAA4B;QAC7D;QAEA,OAAOI;IACT,GAAG,EAAE,KAAK,EAAE;AAEhB,EAAC"}
1
+ {"version":3,"sources":["../../src/utilities/getUserTenantIDs.ts"],"sourcesContent":["import type { Tenant, UserWithTenantsField } from '../types.js'\n\nimport { defaults } from '../defaults.js'\nimport { extractID } from './extractID.js'\n\n/**\n * Returns array of all tenant IDs assigned to a user\n *\n * @param user - User object with tenants field\n */\nexport const getUserTenantIDs = <IDType extends number | string>(\n user: null | UserWithTenantsField,\n options?: {\n tenantsArrayFieldName?: string\n tenantsArrayTenantFieldName?: string\n },\n): IDType[] => {\n if (!user) {\n return []\n }\n\n const tenantsArrayFieldName = options?.tenantsArrayFieldName || defaults.tenantsArrayFieldName\n const tenantsArrayTenantFieldName =\n options?.tenantsArrayTenantFieldName || defaults.tenantsArrayTenantFieldName\n\n return (\n (Array.isArray(user[tenantsArrayFieldName]) ? user[tenantsArrayFieldName] : [])?.reduce<\n IDType[]\n >((acc, row) => {\n const tenantRow = row[tenantsArrayTenantFieldName] as Tenant<IDType>\n if (tenantRow !== undefined && tenantRow !== null) {\n acc.push(extractID(tenantRow))\n }\n\n return acc\n }, []) || []\n )\n}\n"],"names":["defaults","extractID","getUserTenantIDs","user","options","tenantsArrayFieldName","tenantsArrayTenantFieldName","Array","isArray","reduce","acc","row","tenantRow","undefined","push"],"mappings":"AAEA,SAASA,QAAQ,QAAQ,iBAAgB;AACzC,SAASC,SAAS,QAAQ,iBAAgB;AAE1C;;;;CAIC,GACD,OAAO,MAAMC,mBAAmB,CAC9BC,MACAC;IAKA,IAAI,CAACD,MAAM;QACT,OAAO,EAAE;IACX;IAEA,MAAME,wBAAwBD,SAASC,yBAAyBL,SAASK,qBAAqB;IAC9F,MAAMC,8BACJF,SAASE,+BAA+BN,SAASM,2BAA2B;IAE9E,OACE,AAACC,CAAAA,MAAMC,OAAO,CAACL,IAAI,CAACE,sBAAsB,IAAIF,IAAI,CAACE,sBAAsB,GAAG,EAAE,AAAD,GAAII,OAE/E,CAACC,KAAKC;QACN,MAAMC,YAAYD,GAAG,CAACL,4BAA4B;QAClD,IAAIM,cAAcC,aAAaD,cAAc,MAAM;YACjDF,IAAII,IAAI,CAACb,UAAUW;QACrB;QAEA,OAAOF;IACT,GAAG,EAAE,KAAK,EAAE;AAEhB,EAAC"}
@@ -0,0 +1,23 @@
1
+ import type { PayloadRequest } from 'payload';
2
+ import type { MultiTenantPluginConfig } from '../types.js';
3
+ type Args<ConfigType = unknown> = {
4
+ /**
5
+ * The tenant already stored on the document, when there is one.
6
+ */
7
+ previousValue?: unknown;
8
+ req: PayloadRequest;
9
+ tenantsArrayFieldName: string;
10
+ tenantsArrayTenantFieldName: string;
11
+ userHasAccessToAllTenants?: MultiTenantPluginConfig<ConfigType>['userHasAccessToAllTenants'];
12
+ value: unknown;
13
+ };
14
+ /**
15
+ * Whether the submitted tenant value is one the user is allowed to assign.
16
+ *
17
+ * Reads the user's assignments from `req` rather than querying, so it can't conflict with the
18
+ * write's own transaction. Allows all-tenants users, unchanged values, and userless Local API
19
+ * writes (seeds, migrations); rejects assigning an unassigned tenant or clearing an existing one.
20
+ */
21
+ export declare const isValidTenantAssignment: <ConfigType = unknown>({ previousValue, req, tenantsArrayFieldName, tenantsArrayTenantFieldName, userHasAccessToAllTenants, value, }: Args<ConfigType>) => boolean;
22
+ export {};
23
+ //# sourceMappingURL=isValidTenantAssignment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isValidTenantAssignment.d.ts","sourceRoot":"","sources":["../../src/utilities/isValidTenantAssignment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAa,MAAM,SAAS,CAAA;AAExD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAK1D,KAAK,IAAI,CAAC,UAAU,GAAG,OAAO,IAAI;IAChC;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,GAAG,EAAE,cAAc,CAAA;IACnB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,2BAA2B,EAAE,MAAM,CAAA;IACnC,yBAAyB,CAAC,EAAE,uBAAuB,CAAC,UAAU,CAAC,CAAC,2BAA2B,CAAC,CAAA;IAC5F,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,GAAI,UAAU,2HAO/C,IAAI,CAAC,UAAU,CAAC,KAAG,OAwCrB,CAAA"}
@@ -0,0 +1,38 @@
1
+ import { getTenantIDsFromValue } from './getTenantIDsFromValue.js';
2
+ import { getUserTenantIDs } from './getUserTenantIDs.js';
3
+ /**
4
+ * Whether the submitted tenant value is one the user is allowed to assign.
5
+ *
6
+ * Reads the user's assignments from `req` rather than querying, so it can't conflict with the
7
+ * write's own transaction. Allows all-tenants users, unchanged values, and userless Local API
8
+ * writes (seeds, migrations); rejects assigning an unassigned tenant or clearing an existing one.
9
+ */ export const isValidTenantAssignment = ({ previousValue, req, tenantsArrayFieldName, tenantsArrayTenantFieldName, userHasAccessToAllTenants, value })=>{
10
+ const { user } = req;
11
+ if (user) {
12
+ if (userHasAccessToAllTenants?.(user)) {
13
+ return true;
14
+ }
15
+ } else if (req.payloadAPI === 'local') {
16
+ // Seeds, migrations and scripts. There is no user to check against, and this is
17
+ // server-side code rather than an inbound request. An unauthenticated REST or
18
+ // GraphQL request keeps `payloadAPI` set to that API, so it is still checked.
19
+ return true;
20
+ }
21
+ const submittedDocTenantIDs = getTenantIDsFromValue(value);
22
+ const storedDocTenantIDs = getTenantIDsFromValue(previousValue);
23
+ if (!hasTenantValueChanged(submittedDocTenantIDs, storedDocTenantIDs)) {
24
+ return true;
25
+ }
26
+ if (submittedDocTenantIDs.length === 0) {
27
+ // deny clearing an existing tenant
28
+ return false;
29
+ }
30
+ const userAssignedTenantIDs = getUserTenantIDs(user, {
31
+ tenantsArrayFieldName,
32
+ tenantsArrayTenantFieldName
33
+ });
34
+ return submittedDocTenantIDs.every((tenantID)=>userAssignedTenantIDs.some((userAssignedTenantID)=>String(userAssignedTenantID) === String(tenantID)));
35
+ };
36
+ const hasTenantValueChanged = (submittedTenantIDs, storedTenantIDs)=>submittedTenantIDs.length !== storedTenantIDs.length || submittedTenantIDs.some((tenantID)=>!storedTenantIDs.includes(tenantID));
37
+
38
+ //# sourceMappingURL=isValidTenantAssignment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utilities/isValidTenantAssignment.ts"],"sourcesContent":["import type { PayloadRequest, TypedUser } from 'payload'\n\nimport type { MultiTenantPluginConfig } from '../types.js'\n\nimport { getTenantIDsFromValue } from './getTenantIDsFromValue.js'\nimport { getUserTenantIDs } from './getUserTenantIDs.js'\n\ntype Args<ConfigType = unknown> = {\n /**\n * The tenant already stored on the document, when there is one.\n */\n previousValue?: unknown\n req: PayloadRequest\n tenantsArrayFieldName: string\n tenantsArrayTenantFieldName: string\n userHasAccessToAllTenants?: MultiTenantPluginConfig<ConfigType>['userHasAccessToAllTenants']\n value: unknown\n}\n\n/**\n * Whether the submitted tenant value is one the user is allowed to assign.\n *\n * Reads the user's assignments from `req` rather than querying, so it can't conflict with the\n * write's own transaction. Allows all-tenants users, unchanged values, and userless Local API\n * writes (seeds, migrations); rejects assigning an unassigned tenant or clearing an existing one.\n */\nexport const isValidTenantAssignment = <ConfigType = unknown>({\n previousValue,\n req,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n value,\n}: Args<ConfigType>): boolean => {\n const { user } = req\n\n if (user) {\n if (\n userHasAccessToAllTenants?.(\n user as ConfigType extends { user: unknown } ? ConfigType['user'] : TypedUser,\n )\n ) {\n return true\n }\n } else if (req.payloadAPI === 'local') {\n // Seeds, migrations and scripts. There is no user to check against, and this is\n // server-side code rather than an inbound request. An unauthenticated REST or\n // GraphQL request keeps `payloadAPI` set to that API, so it is still checked.\n return true\n }\n\n const submittedDocTenantIDs = getTenantIDsFromValue(value)\n const storedDocTenantIDs = getTenantIDsFromValue(previousValue)\n\n if (!hasTenantValueChanged(submittedDocTenantIDs, storedDocTenantIDs)) {\n return true\n }\n\n if (submittedDocTenantIDs.length === 0) {\n // deny clearing an existing tenant\n return false\n }\n\n const userAssignedTenantIDs = getUserTenantIDs(user, {\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n })\n\n return submittedDocTenantIDs.every((tenantID) =>\n userAssignedTenantIDs.some(\n (userAssignedTenantID) => String(userAssignedTenantID) === String(tenantID),\n ),\n )\n}\n\nconst hasTenantValueChanged = (\n submittedTenantIDs: (number | string)[],\n storedTenantIDs: (number | string)[],\n): boolean =>\n submittedTenantIDs.length !== storedTenantIDs.length ||\n submittedTenantIDs.some((tenantID) => !storedTenantIDs.includes(tenantID))\n"],"names":["getTenantIDsFromValue","getUserTenantIDs","isValidTenantAssignment","previousValue","req","tenantsArrayFieldName","tenantsArrayTenantFieldName","userHasAccessToAllTenants","value","user","payloadAPI","submittedDocTenantIDs","storedDocTenantIDs","hasTenantValueChanged","length","userAssignedTenantIDs","every","tenantID","some","userAssignedTenantID","String","submittedTenantIDs","storedTenantIDs","includes"],"mappings":"AAIA,SAASA,qBAAqB,QAAQ,6BAA4B;AAClE,SAASC,gBAAgB,QAAQ,wBAAuB;AAcxD;;;;;;CAMC,GACD,OAAO,MAAMC,0BAA0B,CAAuB,EAC5DC,aAAa,EACbC,GAAG,EACHC,qBAAqB,EACrBC,2BAA2B,EAC3BC,yBAAyB,EACzBC,KAAK,EACY;IACjB,MAAM,EAAEC,IAAI,EAAE,GAAGL;IAEjB,IAAIK,MAAM;QACR,IACEF,4BACEE,OAEF;YACA,OAAO;QACT;IACF,OAAO,IAAIL,IAAIM,UAAU,KAAK,SAAS;QACrC,gFAAgF;QAChF,8EAA8E;QAC9E,8EAA8E;QAC9E,OAAO;IACT;IAEA,MAAMC,wBAAwBX,sBAAsBQ;IACpD,MAAMI,qBAAqBZ,sBAAsBG;IAEjD,IAAI,CAACU,sBAAsBF,uBAAuBC,qBAAqB;QACrE,OAAO;IACT;IAEA,IAAID,sBAAsBG,MAAM,KAAK,GAAG;QACtC,mCAAmC;QACnC,OAAO;IACT;IAEA,MAAMC,wBAAwBd,iBAAiBQ,MAAM;QACnDJ;QACAC;IACF;IAEA,OAAOK,sBAAsBK,KAAK,CAAC,CAACC,WAClCF,sBAAsBG,IAAI,CACxB,CAACC,uBAAyBC,OAAOD,0BAA0BC,OAAOH;AAGxE,EAAC;AAED,MAAMJ,wBAAwB,CAC5BQ,oBACAC,kBAEAD,mBAAmBP,MAAM,KAAKQ,gBAAgBR,MAAM,IACpDO,mBAAmBH,IAAI,CAAC,CAACD,WAAa,CAACK,gBAAgBC,QAAQ,CAACN"}
@@ -0,0 +1,117 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { isValidTenantAssignment } from './isValidTenantAssignment.js';
3
+ const tenantsArrayFieldName = 'tenants';
4
+ const tenantsArrayTenantFieldName = 'tenant';
5
+ const memberOfTenantA = {
6
+ id: 'user-1',
7
+ collection: 'users',
8
+ tenants: [
9
+ {
10
+ tenant: 'tenant-a'
11
+ }
12
+ ]
13
+ };
14
+ const check = ({ payloadAPI = 'REST', previousValue, user = memberOfTenantA, userHasAccessToAllTenants, value })=>isValidTenantAssignment({
15
+ previousValue,
16
+ req: {
17
+ payloadAPI,
18
+ user
19
+ },
20
+ tenantsArrayFieldName,
21
+ tenantsArrayTenantFieldName,
22
+ userHasAccessToAllTenants,
23
+ value
24
+ });
25
+ describe('isValidTenantAssignment', ()=>{
26
+ it('should allow a tenant the user is assigned to', ()=>{
27
+ expect(check({
28
+ value: 'tenant-a'
29
+ })).toBe(true);
30
+ });
31
+ it('should reject a tenant the user is not assigned to', ()=>{
32
+ expect(check({
33
+ value: 'tenant-b'
34
+ })).toBe(false);
35
+ });
36
+ it('should allow an unchanged tenant even when it sits outside the user list', ()=>{
37
+ expect(check({
38
+ previousValue: 'tenant-b',
39
+ value: 'tenant-b'
40
+ })).toBe(true);
41
+ });
42
+ it('should reject clearing an existing tenant', ()=>{
43
+ expect(check({
44
+ previousValue: 'tenant-a',
45
+ value: null
46
+ })).toBe(false);
47
+ });
48
+ it('should allow a userless Local API write', ()=>{
49
+ expect(check({
50
+ payloadAPI: 'local',
51
+ user: null,
52
+ value: 'tenant-b'
53
+ })).toBe(true);
54
+ });
55
+ it('should reject a userless request that names a tenant', ()=>{
56
+ expect(check({
57
+ user: null,
58
+ value: 'tenant-b'
59
+ })).toBe(false);
60
+ });
61
+ it('should allow any tenant for a user with access to all tenants', ()=>{
62
+ expect(check({
63
+ userHasAccessToAllTenants: ()=>true,
64
+ value: 'tenant-b'
65
+ })).toBe(true);
66
+ });
67
+ it('should never call userHasAccessToAllTenants with a null user', ()=>{
68
+ // A config predicate may dereference `user`; a userless write must not reach it.
69
+ const predicate = (user)=>user.roles.includes('a');
70
+ expect(()=>check({
71
+ payloadAPI: 'local',
72
+ user: null,
73
+ userHasAccessToAllTenants: predicate,
74
+ value: null
75
+ })).not.toThrow();
76
+ });
77
+ it('should reject a hasMany value that mixes assigned and unassigned tenants', ()=>{
78
+ expect(check({
79
+ value: [
80
+ 'tenant-a',
81
+ 'tenant-b'
82
+ ]
83
+ })).toBe(false);
84
+ });
85
+ it('should treat a numeric ID and its string form as the same tenant', ()=>{
86
+ const user = {
87
+ id: 1,
88
+ collection: 'users',
89
+ tenants: [
90
+ {
91
+ tenant: 1
92
+ }
93
+ ]
94
+ };
95
+ expect(check({
96
+ user,
97
+ value: '1'
98
+ })).toBe(true);
99
+ expect(check({
100
+ user,
101
+ value: 1
102
+ })).toBe(true);
103
+ expect(check({
104
+ user,
105
+ value: '2'
106
+ })).toBe(false);
107
+ });
108
+ it('should reject a tenant value it cannot read rather than throwing', ()=>{
109
+ expect(check({
110
+ value: [
111
+ null
112
+ ]
113
+ })).toBe(false);
114
+ });
115
+ });
116
+
117
+ //# sourceMappingURL=isValidTenantAssignment.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utilities/isValidTenantAssignment.spec.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { describe, expect, it } from 'vitest'\n\nimport { isValidTenantAssignment } from './isValidTenantAssignment.js'\n\nconst tenantsArrayFieldName = 'tenants'\nconst tenantsArrayTenantFieldName = 'tenant'\n\nconst memberOfTenantA = {\n id: 'user-1',\n collection: 'users',\n tenants: [{ tenant: 'tenant-a' }],\n}\n\ntype CheckArgs = {\n payloadAPI?: string\n previousValue?: unknown\n user?: unknown\n userHasAccessToAllTenants?: (user: unknown) => boolean\n value: unknown\n}\n\nconst check = ({\n payloadAPI = 'REST',\n previousValue,\n user = memberOfTenantA,\n userHasAccessToAllTenants,\n value,\n}: CheckArgs): boolean =>\n isValidTenantAssignment({\n previousValue,\n req: { payloadAPI, user } as unknown as PayloadRequest,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n value,\n })\n\ndescribe('isValidTenantAssignment', () => {\n it('should allow a tenant the user is assigned to', () => {\n expect(check({ value: 'tenant-a' })).toBe(true)\n })\n\n it('should reject a tenant the user is not assigned to', () => {\n expect(check({ value: 'tenant-b' })).toBe(false)\n })\n\n it('should allow an unchanged tenant even when it sits outside the user list', () => {\n expect(check({ previousValue: 'tenant-b', value: 'tenant-b' })).toBe(true)\n })\n\n it('should reject clearing an existing tenant', () => {\n expect(check({ previousValue: 'tenant-a', value: null })).toBe(false)\n })\n\n it('should allow a userless Local API write', () => {\n expect(check({ payloadAPI: 'local', user: null, value: 'tenant-b' })).toBe(true)\n })\n\n it('should reject a userless request that names a tenant', () => {\n expect(check({ user: null, value: 'tenant-b' })).toBe(false)\n })\n\n it('should allow any tenant for a user with access to all tenants', () => {\n expect(check({ userHasAccessToAllTenants: () => true, value: 'tenant-b' })).toBe(true)\n })\n\n it('should never call userHasAccessToAllTenants with a null user', () => {\n // A config predicate may dereference `user`; a userless write must not reach it.\n const predicate = (user: unknown): boolean => (user as { roles: string[] }).roles.includes('a')\n\n expect(() =>\n check({ payloadAPI: 'local', user: null, userHasAccessToAllTenants: predicate, value: null }),\n ).not.toThrow()\n })\n\n it('should reject a hasMany value that mixes assigned and unassigned tenants', () => {\n expect(check({ value: ['tenant-a', 'tenant-b'] })).toBe(false)\n })\n\n it('should treat a numeric ID and its string form as the same tenant', () => {\n const user = { id: 1, collection: 'users', tenants: [{ tenant: 1 }] }\n\n expect(check({ user, value: '1' })).toBe(true)\n expect(check({ user, value: 1 })).toBe(true)\n expect(check({ user, value: '2' })).toBe(false)\n })\n\n it('should reject a tenant value it cannot read rather than throwing', () => {\n expect(check({ value: [null] })).toBe(false)\n })\n})\n"],"names":["describe","expect","it","isValidTenantAssignment","tenantsArrayFieldName","tenantsArrayTenantFieldName","memberOfTenantA","id","collection","tenants","tenant","check","payloadAPI","previousValue","user","userHasAccessToAllTenants","value","req","toBe","predicate","roles","includes","not","toThrow"],"mappings":"AAEA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAE7C,SAASC,uBAAuB,QAAQ,+BAA8B;AAEtE,MAAMC,wBAAwB;AAC9B,MAAMC,8BAA8B;AAEpC,MAAMC,kBAAkB;IACtBC,IAAI;IACJC,YAAY;IACZC,SAAS;QAAC;YAAEC,QAAQ;QAAW;KAAE;AACnC;AAUA,MAAMC,QAAQ,CAAC,EACbC,aAAa,MAAM,EACnBC,aAAa,EACbC,OAAOR,eAAe,EACtBS,yBAAyB,EACzBC,KAAK,EACK,GACVb,wBAAwB;QACtBU;QACAI,KAAK;YAAEL;YAAYE;QAAK;QACxBV;QACAC;QACAU;QACAC;IACF;AAEFhB,SAAS,2BAA2B;IAClCE,GAAG,iDAAiD;QAClDD,OAAOU,MAAM;YAAEK,OAAO;QAAW,IAAIE,IAAI,CAAC;IAC5C;IAEAhB,GAAG,sDAAsD;QACvDD,OAAOU,MAAM;YAAEK,OAAO;QAAW,IAAIE,IAAI,CAAC;IAC5C;IAEAhB,GAAG,4EAA4E;QAC7ED,OAAOU,MAAM;YAAEE,eAAe;YAAYG,OAAO;QAAW,IAAIE,IAAI,CAAC;IACvE;IAEAhB,GAAG,6CAA6C;QAC9CD,OAAOU,MAAM;YAAEE,eAAe;YAAYG,OAAO;QAAK,IAAIE,IAAI,CAAC;IACjE;IAEAhB,GAAG,2CAA2C;QAC5CD,OAAOU,MAAM;YAAEC,YAAY;YAASE,MAAM;YAAME,OAAO;QAAW,IAAIE,IAAI,CAAC;IAC7E;IAEAhB,GAAG,wDAAwD;QACzDD,OAAOU,MAAM;YAAEG,MAAM;YAAME,OAAO;QAAW,IAAIE,IAAI,CAAC;IACxD;IAEAhB,GAAG,iEAAiE;QAClED,OAAOU,MAAM;YAAEI,2BAA2B,IAAM;YAAMC,OAAO;QAAW,IAAIE,IAAI,CAAC;IACnF;IAEAhB,GAAG,gEAAgE;QACjE,iFAAiF;QACjF,MAAMiB,YAAY,CAACL,OAA2B,AAACA,KAA6BM,KAAK,CAACC,QAAQ,CAAC;QAE3FpB,OAAO,IACLU,MAAM;gBAAEC,YAAY;gBAASE,MAAM;gBAAMC,2BAA2BI;gBAAWH,OAAO;YAAK,IAC3FM,GAAG,CAACC,OAAO;IACf;IAEArB,GAAG,4EAA4E;QAC7ED,OAAOU,MAAM;YAAEK,OAAO;gBAAC;gBAAY;aAAW;QAAC,IAAIE,IAAI,CAAC;IAC1D;IAEAhB,GAAG,oEAAoE;QACrE,MAAMY,OAAO;YAAEP,IAAI;YAAGC,YAAY;YAASC,SAAS;gBAAC;oBAAEC,QAAQ;gBAAE;aAAE;QAAC;QAEpET,OAAOU,MAAM;YAAEG;YAAME,OAAO;QAAI,IAAIE,IAAI,CAAC;QACzCjB,OAAOU,MAAM;YAAEG;YAAME,OAAO;QAAE,IAAIE,IAAI,CAAC;QACvCjB,OAAOU,MAAM;YAAEG;YAAME,OAAO;QAAI,IAAIE,IAAI,CAAC;IAC3C;IAEAhB,GAAG,oEAAoE;QACrED,OAAOU,MAAM;YAAEK,OAAO;gBAAC;aAAK;QAAC,IAAIE,IAAI,CAAC;IACxC;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloadcms/plugin-multi-tenant",
3
- "version": "3.89.0-internal.95c9cba",
3
+ "version": "3.90.0",
4
4
  "description": "Multi Tenant plugin for Payload",
5
5
  "keywords": [
6
6
  "payload",
@@ -80,14 +80,14 @@
80
80
  "types.d.ts"
81
81
  ],
82
82
  "devDependencies": {
83
- "@payloadcms/ui": "3.89.0-internal.95c9cba",
84
- "payload": "3.89.0-internal.95c9cba",
85
83
  "@payloadcms/eslint-config": "3.28.0",
86
- "@payloadcms/translations": "3.89.0-internal.95c9cba"
84
+ "@payloadcms/ui": "3.90.0",
85
+ "@payloadcms/translations": "3.90.0",
86
+ "payload": "3.90.0"
87
87
  },
88
88
  "peerDependencies": {
89
- "@payloadcms/ui": "3.89.0-internal.95c9cba",
90
- "payload": "3.89.0-internal.95c9cba"
89
+ "@payloadcms/ui": "3.90.0",
90
+ "payload": "3.90.0"
91
91
  },
92
92
  "homepage:": "https://payloadcms.com",
93
93
  "scripts": {