@payloadcms/plugin-multi-tenant 4.0.0-internal.688c4d0 → 4.0.0-internal.77191e5
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.
- package/LICENSE.md +1 -1
- package/dist/components/AssignTenantFieldModal/index.client.d.ts +2 -2
- package/dist/components/AssignTenantFieldModal/index.client.d.ts.map +1 -1
- package/dist/components/AssignTenantFieldModal/index.client.js.map +1 -1
- package/dist/components/GlobalViewRedirect/index.d.ts +1 -1
- package/dist/components/GlobalViewRedirect/index.d.ts.map +1 -1
- package/dist/components/GlobalViewRedirect/index.js.map +1 -1
- package/dist/components/TenantField/index.client.d.ts.map +1 -1
- package/dist/components/TenantField/index.client.js +84 -74
- package/dist/components/TenantField/index.client.js.map +1 -1
- package/dist/components/TenantSelector/index.client.d.ts +1 -1
- package/dist/components/TenantSelector/index.client.d.ts.map +1 -1
- package/dist/components/TenantSelector/index.d.ts.map +1 -1
- package/dist/defaults.d.ts.map +1 -1
- package/dist/endpoints/getTenantOptionsEndpoint.d.ts +2 -2
- package/dist/endpoints/getTenantOptionsEndpoint.d.ts.map +1 -1
- package/dist/endpoints/getTenantOptionsEndpoint.js.map +1 -1
- package/dist/fields/tenantField/index.d.ts +4 -2
- package/dist/fields/tenantField/index.d.ts.map +1 -1
- package/dist/fields/tenantField/index.js +36 -9
- package/dist/fields/tenantField/index.js.map +1 -1
- package/dist/fields/tenantsArrayField/index.d.ts.map +1 -1
- package/dist/filters/filterDocumentsByTenants.d.ts +3 -3
- package/dist/filters/filterDocumentsByTenants.d.ts.map +1 -1
- package/dist/filters/filterDocumentsByTenants.js.map +1 -1
- package/dist/hooks/afterTenantDelete.d.ts +1 -1
- package/dist/hooks/afterTenantDelete.d.ts.map +1 -1
- package/dist/hooks/afterTenantDelete.js +4 -1
- package/dist/hooks/afterTenantDelete.js.map +1 -1
- package/dist/hooks/enforceTenantMembership.d.ts +15 -0
- package/dist/hooks/enforceTenantMembership.d.ts.map +1 -0
- package/dist/hooks/enforceTenantMembership.js +39 -0
- package/dist/hooks/enforceTenantMembership.js.map +1 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -6
- package/dist/index.js.map +1 -1
- package/dist/providers/TenantSelectionProvider/index.client.d.ts.map +1 -1
- package/dist/providers/TenantSelectionProvider/index.client.js +44 -24
- package/dist/providers/TenantSelectionProvider/index.client.js.map +1 -1
- package/dist/providers/TenantSelectionProvider/index.d.ts +5 -5
- package/dist/providers/TenantSelectionProvider/index.d.ts.map +1 -1
- package/dist/providers/TenantSelectionProvider/index.js.map +1 -1
- package/dist/translations/languages/en.d.ts.map +1 -1
- package/dist/types.d.ts +5 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utilities/addCollectionAccess.d.ts +8 -10
- package/dist/utilities/addCollectionAccess.d.ts.map +1 -1
- package/dist/utilities/addCollectionAccess.js +91 -20
- package/dist/utilities/addCollectionAccess.js.map +1 -1
- package/dist/utilities/addFilterOptionsToFields.d.ts +3 -3
- package/dist/utilities/addFilterOptionsToFields.d.ts.map +1 -1
- package/dist/utilities/addFilterOptionsToFields.js.map +1 -1
- package/dist/utilities/combineFilters.d.ts.map +1 -1
- package/dist/utilities/extractID.d.ts.map +1 -1
- package/dist/utilities/generateCookie.d.ts.map +1 -1
- package/dist/utilities/getCollectionIDType.d.ts +1 -1
- package/dist/utilities/getCollectionIDType.d.ts.map +1 -1
- package/dist/utilities/getGlobalViewRedirect.d.ts +3 -3
- package/dist/utilities/getGlobalViewRedirect.d.ts.map +1 -1
- package/dist/utilities/getGlobalViewRedirect.js.map +1 -1
- package/dist/utilities/getTenantIDsFromValue.d.ts +2 -0
- package/dist/utilities/getTenantIDsFromValue.d.ts.map +1 -0
- package/dist/utilities/getTenantIDsFromValue.js +14 -0
- package/dist/utilities/getTenantIDsFromValue.js.map +1 -0
- package/dist/utilities/getTenantOptions.d.ts +3 -3
- package/dist/utilities/getTenantOptions.d.ts.map +1 -1
- package/dist/utilities/getTenantOptions.js.map +1 -1
- package/dist/utilities/getUserTenantIDs.d.ts.map +1 -1
- package/dist/utilities/getUserTenantIDs.js +5 -3
- package/dist/utilities/getUserTenantIDs.js.map +1 -1
- package/dist/utilities/isValidTenantAssignment.d.ts +13 -0
- package/dist/utilities/isValidTenantAssignment.d.ts.map +1 -0
- package/dist/utilities/isValidTenantAssignment.js +28 -0
- package/dist/utilities/isValidTenantAssignment.js.map +1 -0
- package/dist/utilities/miniChalk.d.ts.map +1 -1
- package/dist/utilities/shouldRefreshTenantSelection.d.ts +5 -0
- package/dist/utilities/shouldRefreshTenantSelection.d.ts.map +1 -0
- package/dist/utilities/shouldRefreshTenantSelection.js +3 -0
- package/dist/utilities/shouldRefreshTenantSelection.js.map +1 -0
- package/package.json +7 -8
- package/dist/@types/assets.d.js +0 -2
- package/dist/@types/assets.d.js.map +0 -1
- package/dist/utilities/combineWhereConstraints.d.ts +0 -3
- package/dist/utilities/combineWhereConstraints.d.ts.map +0 -1
- package/dist/utilities/combineWhereConstraints.js +0 -19
- package/dist/utilities/combineWhereConstraints.js.map +0 -1
- package/dist/utilities/withTenantAccess.d.ts +0 -16
- package/dist/utilities/withTenantAccess.d.ts.map +0 -1
- package/dist/utilities/withTenantAccess.js +0 -76
- package/dist/utilities/withTenantAccess.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filterDocumentsByTenants.d.ts","sourceRoot":"","sources":["../../src/filters/filterDocumentsByTenants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"filterDocumentsByTenants.d.ts","sourceRoot":"","sources":["../../src/filters/filterDocumentsByTenants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAQ,KAAK,EAAE,MAAM,SAAS,CAAA;AAE1D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAO1D,KAAK,IAAI,GAAG;IACV;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,GAAG,MAAM,EAAE,CAAA;IACnD,eAAe,EAAE,MAAM,CAAA;IACvB,GAAG,EAAE,cAAc,CAAA;IACnB,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,2BAA2B,CAAC,EAAE,MAAM,CAAA;IACpC,qBAAqB,EAAE,MAAM,CAAA;IAC7B,yBAAyB,EAAE,QAAQ,CAAC,uBAAuB,CAAC,CAAC,2BAA2B,CAAC,CAAA;CAC1F,CAAA;AACD,eAAO,MAAM,wBAAwB,iJAQlC,IAAI,KAAG,IAAI,GAAG,KAmChB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/filters/filterDocumentsByTenants.ts"],"sourcesContent":["import type { PayloadRequest,
|
|
1
|
+
{"version":3,"sources":["../../src/filters/filterDocumentsByTenants.ts"],"sourcesContent":["import type { PayloadRequest, User, Where } from 'payload'\n\nimport type { MultiTenantPluginConfig } 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\ntype Args = {\n /**\n * If the document this filter is run belongs to a tenant, the tenant ID should be passed here.\n * If set, this will be used instead of the tenant cookie\n * Can be an array when hasMany is true\n */\n docTenantID?: number | number[] | string | string[]\n filterFieldName: string\n req: PayloadRequest\n tenantsArrayFieldName?: string\n tenantsArrayTenantFieldName?: string\n tenantsCollectionSlug: string\n userHasAccessToAllTenants: Required<MultiTenantPluginConfig>['userHasAccessToAllTenants']\n}\nexport const filterDocumentsByTenants = ({\n docTenantID,\n filterFieldName,\n req,\n tenantsArrayFieldName = defaults.tenantsArrayFieldName,\n tenantsArrayTenantFieldName = defaults.tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n userHasAccessToAllTenants,\n}: Args): null | Where => {\n const idType = getCollectionIDType({\n collectionSlug: tenantsCollectionSlug,\n payload: req.payload,\n })\n\n // scope results to selected tenant\n const selectedTenant = docTenantID ?? getTenantFromCookie(req.headers, idType)\n if (selectedTenant) {\n return {\n [filterFieldName]: {\n in: Array.isArray(selectedTenant) ? selectedTenant : [selectedTenant],\n },\n }\n }\n\n if (req.user && userHasAccessToAllTenants(req?.user as User)) {\n return null\n }\n\n // scope to user assigned tenants\n const userAssignedTenants = getUserTenantIDs(req.user, {\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n })\n if (userAssignedTenants.length > 0) {\n return {\n [filterFieldName]: {\n in: userAssignedTenants,\n },\n }\n }\n\n // no tenant selected and no user tenants, return null to allow access control to handle it\n return null\n}\n"],"names":["defaults","getCollectionIDType","getTenantFromCookie","getUserTenantIDs","filterDocumentsByTenants","docTenantID","filterFieldName","req","tenantsArrayFieldName","tenantsArrayTenantFieldName","tenantsCollectionSlug","userHasAccessToAllTenants","idType","collectionSlug","payload","selectedTenant","headers","in","Array","isArray","user","userAssignedTenants","length"],"mappings":"AAIA,SAASA,QAAQ,QAAQ,iBAAgB;AACzC,SAASC,mBAAmB,QAAQ,sCAAqC;AACzE,SAASC,mBAAmB,QAAQ,sCAAqC;AACzE,SAASC,gBAAgB,QAAQ,mCAAkC;AAgBnE,OAAO,MAAMC,2BAA2B,CAAC,EACvCC,WAAW,EACXC,eAAe,EACfC,GAAG,EACHC,wBAAwBR,SAASQ,qBAAqB,EACtDC,8BAA8BT,SAASS,2BAA2B,EAClEC,qBAAqB,EACrBC,yBAAyB,EACpB;IACL,MAAMC,SAASX,oBAAoB;QACjCY,gBAAgBH;QAChBI,SAASP,IAAIO,OAAO;IACtB;IAEA,mCAAmC;IACnC,MAAMC,iBAAiBV,eAAeH,oBAAoBK,IAAIS,OAAO,EAAEJ;IACvE,IAAIG,gBAAgB;QAClB,OAAO;YACL,CAACT,gBAAgB,EAAE;gBACjBW,IAAIC,MAAMC,OAAO,CAACJ,kBAAkBA,iBAAiB;oBAACA;iBAAe;YACvE;QACF;IACF;IAEA,IAAIR,IAAIa,IAAI,IAAIT,0BAA0BJ,KAAKa,OAAe;QAC5D,OAAO;IACT;IAEA,iCAAiC;IACjC,MAAMC,sBAAsBlB,iBAAiBI,IAAIa,IAAI,EAAE;QACrDZ;QACAC;IACF;IACA,IAAIY,oBAAoBC,MAAM,GAAG,GAAG;QAClC,OAAO;YACL,CAAChB,gBAAgB,EAAE;gBACjBW,IAAII;YACN;QACF;IACF;IAEA,2FAA2F;IAC3F,OAAO;AACT,EAAC"}
|
|
@@ -14,6 +14,6 @@ type Args = {
|
|
|
14
14
|
* - remove tenant from users
|
|
15
15
|
*/
|
|
16
16
|
export declare const addTenantCleanup: ({ collection, enabledSlugs, tenantFieldName, tenantsCollectionSlug, usersSlug, usersTenantsArrayFieldName, usersTenantsArrayTenantFieldName, }: Args) => void;
|
|
17
|
-
export declare const afterTenantDelete: ({ enabledSlugs, tenantFieldName, tenantsCollectionSlug, usersSlug, usersTenantsArrayFieldName, usersTenantsArrayTenantFieldName, }: Omit<Args,
|
|
17
|
+
export declare const afterTenantDelete: ({ enabledSlugs, tenantFieldName, tenantsCollectionSlug, usersSlug, usersTenantsArrayFieldName, usersTenantsArrayTenantFieldName, }: Omit<Args, 'collection'>) => CollectionAfterDeleteHook;
|
|
18
18
|
export {};
|
|
19
19
|
//# sourceMappingURL=afterTenantDelete.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"afterTenantDelete.d.ts","sourceRoot":"","sources":["../../src/hooks/afterTenantDelete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,gBAAgB,EAGjB,MAAM,SAAS,CAAA;AAShB,KAAK,IAAI,GAAG;IACV,UAAU,EAAE,gBAAgB,CAAA;IAC5B,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,0BAA0B,EAAE,MAAM,CAAA;IAClC,gCAAgC,EAAE,MAAM,CAAA;CACzC,CAAA;AACD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,
|
|
1
|
+
{"version":3,"file":"afterTenantDelete.d.ts","sourceRoot":"","sources":["../../src/hooks/afterTenantDelete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,gBAAgB,EAGjB,MAAM,SAAS,CAAA;AAShB,KAAK,IAAI,GAAG;IACV,UAAU,EAAE,gBAAgB,CAAA;IAC5B,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,0BAA0B,EAAE,MAAM,CAAA;IAClC,gCAAgC,EAAE,MAAM,CAAA;CACzC,CAAA;AACD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,mJAQ1B,IAAI,SAiBN,CAAA;AAED,eAAO,MAAM,iBAAiB,uIAQzB,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,KAAG,yBA4E7B,CAAA"}
|
|
@@ -43,6 +43,7 @@ export const afterTenantDelete = ({ enabledSlugs, tenantFieldName, tenantsCollec
|
|
|
43
43
|
enabledSlugs.forEach((slug)=>{
|
|
44
44
|
cleanupPromises.push(req.payload.delete({
|
|
45
45
|
collection: slug,
|
|
46
|
+
req,
|
|
46
47
|
where: {
|
|
47
48
|
[tenantFieldName]: {
|
|
48
49
|
in: [
|
|
@@ -57,6 +58,7 @@ export const afterTenantDelete = ({ enabledSlugs, tenantFieldName, tenantsCollec
|
|
|
57
58
|
collection: usersSlug,
|
|
58
59
|
depth: 0,
|
|
59
60
|
limit: 0,
|
|
61
|
+
req,
|
|
60
62
|
where: {
|
|
61
63
|
[`${usersTenantsArrayFieldName}.${usersTenantsArrayTenantFieldName}`]: {
|
|
62
64
|
in: [
|
|
@@ -75,7 +77,8 @@ export const afterTenantDelete = ({ enabledSlugs, tenantFieldName, tenantsCollec
|
|
|
75
77
|
return row[usersTenantsArrayTenantFieldName] !== id;
|
|
76
78
|
}
|
|
77
79
|
})
|
|
78
|
-
}
|
|
80
|
+
},
|
|
81
|
+
req
|
|
79
82
|
}));
|
|
80
83
|
});
|
|
81
84
|
} catch (e) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/afterTenantDelete.ts"],"sourcesContent":["import type {\n CollectionAfterDeleteHook,\n CollectionConfig,\n JsonObject,\n PaginatedDocs,\n} from 'payload'\n\nimport { generateCookie, mergeHeaders } from 'payload'\n\nimport type { UserWithTenantsField } from '../types.js'\n\nimport { getCollectionIDType } from '../utilities/getCollectionIDType.js'\nimport { getTenantFromCookie } from '../utilities/getTenantFromCookie.js'\n\ntype Args = {\n collection: CollectionConfig\n enabledSlugs: string[]\n tenantFieldName: string\n tenantsCollectionSlug: string\n usersSlug: string\n usersTenantsArrayFieldName: string\n usersTenantsArrayTenantFieldName: string\n}\n/**\n * Add cleanup logic when tenant is deleted\n * - delete documents related to tenant\n * - remove tenant from users\n */\nexport const addTenantCleanup = ({\n collection,\n enabledSlugs,\n tenantFieldName,\n tenantsCollectionSlug,\n usersSlug,\n usersTenantsArrayFieldName,\n usersTenantsArrayTenantFieldName,\n}: Args) => {\n if (!collection.hooks) {\n collection.hooks = {}\n }\n if (!collection.hooks?.afterDelete) {\n collection.hooks.afterDelete = []\n }\n collection.hooks.afterDelete.push(\n afterTenantDelete({\n enabledSlugs,\n tenantFieldName,\n tenantsCollectionSlug,\n usersSlug,\n usersTenantsArrayFieldName,\n usersTenantsArrayTenantFieldName,\n }),\n )\n}\n\nexport const afterTenantDelete =\n ({\n enabledSlugs,\n tenantFieldName,\n tenantsCollectionSlug,\n usersSlug,\n usersTenantsArrayFieldName,\n usersTenantsArrayTenantFieldName,\n }: Omit<Args, 'collection'>): CollectionAfterDeleteHook =>\n async ({ id, req }) => {\n const idType = getCollectionIDType({\n collectionSlug: tenantsCollectionSlug,\n payload: req.payload,\n })\n const currentTenantCookieID = getTenantFromCookie(req.headers, idType)\n if (currentTenantCookieID === id) {\n const newHeaders = new Headers({\n 'Set-Cookie': generateCookie<string>({\n name: 'payload-tenant',\n expires: new Date(Date.now() - 1000),\n path: '/',\n returnCookieAsObject: false,\n value: '',\n }),\n })\n\n req.responseHeaders = req.responseHeaders\n ? mergeHeaders(req.responseHeaders, newHeaders)\n : newHeaders\n }\n const cleanupPromises: Promise<JsonObject>[] = []\n enabledSlugs.forEach((slug) => {\n cleanupPromises.push(\n req.payload.delete({\n collection: slug,\n where: {\n [tenantFieldName]: {\n in: [id],\n },\n },\n }),\n )\n })\n\n try {\n const usersWithTenant = (await req.payload.find({\n collection: usersSlug,\n depth: 0,\n limit: 0,\n where: {\n [`${usersTenantsArrayFieldName}.${usersTenantsArrayTenantFieldName}`]: {\n in: [id],\n },\n },\n })) as PaginatedDocs<UserWithTenantsField>\n\n usersWithTenant?.docs?.forEach((user) => {\n cleanupPromises.push(\n req.payload.update({\n id: user.id,\n collection: usersSlug,\n data: {\n [usersTenantsArrayFieldName]: (user[usersTenantsArrayFieldName] || []).filter(
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/afterTenantDelete.ts"],"sourcesContent":["import type {\n CollectionAfterDeleteHook,\n CollectionConfig,\n JsonObject,\n PaginatedDocs,\n} from 'payload'\n\nimport { generateCookie, mergeHeaders } from 'payload'\n\nimport type { UserWithTenantsField } from '../types.js'\n\nimport { getCollectionIDType } from '../utilities/getCollectionIDType.js'\nimport { getTenantFromCookie } from '../utilities/getTenantFromCookie.js'\n\ntype Args = {\n collection: CollectionConfig\n enabledSlugs: string[]\n tenantFieldName: string\n tenantsCollectionSlug: string\n usersSlug: string\n usersTenantsArrayFieldName: string\n usersTenantsArrayTenantFieldName: string\n}\n/**\n * Add cleanup logic when tenant is deleted\n * - delete documents related to tenant\n * - remove tenant from users\n */\nexport const addTenantCleanup = ({\n collection,\n enabledSlugs,\n tenantFieldName,\n tenantsCollectionSlug,\n usersSlug,\n usersTenantsArrayFieldName,\n usersTenantsArrayTenantFieldName,\n}: Args) => {\n if (!collection.hooks) {\n collection.hooks = {}\n }\n if (!collection.hooks?.afterDelete) {\n collection.hooks.afterDelete = []\n }\n collection.hooks.afterDelete.push(\n afterTenantDelete({\n enabledSlugs,\n tenantFieldName,\n tenantsCollectionSlug,\n usersSlug,\n usersTenantsArrayFieldName,\n usersTenantsArrayTenantFieldName,\n }),\n )\n}\n\nexport const afterTenantDelete =\n ({\n enabledSlugs,\n tenantFieldName,\n tenantsCollectionSlug,\n usersSlug,\n usersTenantsArrayFieldName,\n usersTenantsArrayTenantFieldName,\n }: Omit<Args, 'collection'>): CollectionAfterDeleteHook =>\n async ({ id, req }) => {\n const idType = getCollectionIDType({\n collectionSlug: tenantsCollectionSlug,\n payload: req.payload,\n })\n const currentTenantCookieID = getTenantFromCookie(req.headers, idType)\n if (currentTenantCookieID === id) {\n const newHeaders = new Headers({\n 'Set-Cookie': generateCookie<string>({\n name: 'payload-tenant',\n expires: new Date(Date.now() - 1000),\n path: '/',\n returnCookieAsObject: false,\n value: '',\n }),\n })\n\n req.responseHeaders = req.responseHeaders\n ? mergeHeaders(req.responseHeaders, newHeaders)\n : newHeaders\n }\n const cleanupPromises: Promise<JsonObject>[] = []\n enabledSlugs.forEach((slug) => {\n cleanupPromises.push(\n req.payload.delete({\n collection: slug,\n req,\n where: {\n [tenantFieldName]: {\n in: [id],\n },\n },\n }),\n )\n })\n\n try {\n const usersWithTenant = (await req.payload.find({\n collection: usersSlug,\n depth: 0,\n limit: 0,\n req,\n where: {\n [`${usersTenantsArrayFieldName}.${usersTenantsArrayTenantFieldName}`]: {\n in: [id],\n },\n },\n })) as PaginatedDocs<UserWithTenantsField>\n\n usersWithTenant?.docs?.forEach((user) => {\n cleanupPromises.push(\n req.payload.update({\n id: user.id,\n collection: usersSlug,\n data: {\n [usersTenantsArrayFieldName]: (\n ((user as Record<string, unknown>)[usersTenantsArrayFieldName] as Record<\n string,\n string\n >[]) || []\n ).filter((row: Record<string, string>) => {\n if (row[usersTenantsArrayTenantFieldName]) {\n return row[usersTenantsArrayTenantFieldName] !== id\n }\n }),\n },\n req,\n }),\n )\n })\n } catch (e) {\n console.error('Error deleting tenants from users:', e)\n }\n\n await Promise.all(cleanupPromises)\n }\n"],"names":["generateCookie","mergeHeaders","getCollectionIDType","getTenantFromCookie","addTenantCleanup","collection","enabledSlugs","tenantFieldName","tenantsCollectionSlug","usersSlug","usersTenantsArrayFieldName","usersTenantsArrayTenantFieldName","hooks","afterDelete","push","afterTenantDelete","id","req","idType","collectionSlug","payload","currentTenantCookieID","headers","newHeaders","Headers","name","expires","Date","now","path","returnCookieAsObject","value","responseHeaders","cleanupPromises","forEach","slug","delete","where","in","usersWithTenant","find","depth","limit","docs","user","update","data","filter","row","e","console","error","Promise","all"],"mappings":"AAOA,SAASA,cAAc,EAAEC,YAAY,QAAQ,UAAS;AAItD,SAASC,mBAAmB,QAAQ,sCAAqC;AACzE,SAASC,mBAAmB,QAAQ,sCAAqC;AAWzE;;;;CAIC,GACD,OAAO,MAAMC,mBAAmB,CAAC,EAC/BC,UAAU,EACVC,YAAY,EACZC,eAAe,EACfC,qBAAqB,EACrBC,SAAS,EACTC,0BAA0B,EAC1BC,gCAAgC,EAC3B;IACL,IAAI,CAACN,WAAWO,KAAK,EAAE;QACrBP,WAAWO,KAAK,GAAG,CAAC;IACtB;IACA,IAAI,CAACP,WAAWO,KAAK,EAAEC,aAAa;QAClCR,WAAWO,KAAK,CAACC,WAAW,GAAG,EAAE;IACnC;IACAR,WAAWO,KAAK,CAACC,WAAW,CAACC,IAAI,CAC/BC,kBAAkB;QAChBT;QACAC;QACAC;QACAC;QACAC;QACAC;IACF;AAEJ,EAAC;AAED,OAAO,MAAMI,oBACX,CAAC,EACCT,YAAY,EACZC,eAAe,EACfC,qBAAqB,EACrBC,SAAS,EACTC,0BAA0B,EAC1BC,gCAAgC,EACP,GAC3B,OAAO,EAAEK,EAAE,EAAEC,GAAG,EAAE;QAChB,MAAMC,SAAShB,oBAAoB;YACjCiB,gBAAgBX;YAChBY,SAASH,IAAIG,OAAO;QACtB;QACA,MAAMC,wBAAwBlB,oBAAoBc,IAAIK,OAAO,EAAEJ;QAC/D,IAAIG,0BAA0BL,IAAI;YAChC,MAAMO,aAAa,IAAIC,QAAQ;gBAC7B,cAAcxB,eAAuB;oBACnCyB,MAAM;oBACNC,SAAS,IAAIC,KAAKA,KAAKC,GAAG,KAAK;oBAC/BC,MAAM;oBACNC,sBAAsB;oBACtBC,OAAO;gBACT;YACF;YAEAd,IAAIe,eAAe,GAAGf,IAAIe,eAAe,GACrC/B,aAAagB,IAAIe,eAAe,EAAET,cAClCA;QACN;QACA,MAAMU,kBAAyC,EAAE;QACjD3B,aAAa4B,OAAO,CAAC,CAACC;YACpBF,gBAAgBnB,IAAI,CAClBG,IAAIG,OAAO,CAACgB,MAAM,CAAC;gBACjB/B,YAAY8B;gBACZlB;gBACAoB,OAAO;oBACL,CAAC9B,gBAAgB,EAAE;wBACjB+B,IAAI;4BAACtB;yBAAG;oBACV;gBACF;YACF;QAEJ;QAEA,IAAI;YACF,MAAMuB,kBAAmB,MAAMtB,IAAIG,OAAO,CAACoB,IAAI,CAAC;gBAC9CnC,YAAYI;gBACZgC,OAAO;gBACPC,OAAO;gBACPzB;gBACAoB,OAAO;oBACL,CAAC,GAAG3B,2BAA2B,CAAC,EAAEC,kCAAkC,CAAC,EAAE;wBACrE2B,IAAI;4BAACtB;yBAAG;oBACV;gBACF;YACF;YAEAuB,iBAAiBI,MAAMT,QAAQ,CAACU;gBAC9BX,gBAAgBnB,IAAI,CAClBG,IAAIG,OAAO,CAACyB,MAAM,CAAC;oBACjB7B,IAAI4B,KAAK5B,EAAE;oBACXX,YAAYI;oBACZqC,MAAM;wBACJ,CAACpC,2BAA2B,EAAE,AAC5B,CAAA,AAAC,AAACkC,IAAgC,CAAClC,2BAA2B,IAGtD,EAAE,AAAD,EACTqC,MAAM,CAAC,CAACC;4BACR,IAAIA,GAAG,CAACrC,iCAAiC,EAAE;gCACzC,OAAOqC,GAAG,CAACrC,iCAAiC,KAAKK;4BACnD;wBACF;oBACF;oBACAC;gBACF;YAEJ;QACF,EAAE,OAAOgC,GAAG;YACVC,QAAQC,KAAK,CAAC,sCAAsCF;QACtD;QAEA,MAAMG,QAAQC,GAAG,CAACpB;IACpB,EAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CollectionBeforeValidateHook, CollectionConfig } from 'payload';
|
|
2
|
+
import type { MultiTenantPluginConfig } from '../types.js';
|
|
3
|
+
type Args = {
|
|
4
|
+
collection: CollectionConfig;
|
|
5
|
+
tenantFieldName: string;
|
|
6
|
+
tenantsArrayFieldName: string;
|
|
7
|
+
tenantsArrayTenantFieldName: string;
|
|
8
|
+
userHasAccessToAllTenants: Required<MultiTenantPluginConfig>['userHasAccessToAllTenants'];
|
|
9
|
+
};
|
|
10
|
+
export declare const addCollectionBeforeValidateHook: ({ collection, tenantFieldName, tenantsArrayFieldName, tenantsArrayTenantFieldName, userHasAccessToAllTenants, }: Args) => void;
|
|
11
|
+
export declare const enforceTenantMembership: ({ collectionSlug, tenantFieldName, tenantsArrayFieldName, tenantsArrayTenantFieldName, userHasAccessToAllTenants, }: {
|
|
12
|
+
collectionSlug: string;
|
|
13
|
+
} & Omit<Args, 'collection'>) => CollectionBeforeValidateHook;
|
|
14
|
+
export {};
|
|
15
|
+
//# 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,EAAE,4BAA4B,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAI7E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAI1D,KAAK,IAAI,GAAG;IACV,UAAU,EAAE,gBAAgB,CAAA;IAC5B,eAAe,EAAE,MAAM,CAAA;IACvB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,2BAA2B,EAAE,MAAM,CAAA;IACnC,yBAAyB,EAAE,QAAQ,CAAC,uBAAuB,CAAC,CAAC,2BAA2B,CAAC,CAAA;CAC1F,CAAA;AAED,eAAO,MAAM,+BAA+B,oHAMzC,IAAI,SAYN,CAAA;AAED,eAAO,MAAM,uBAAuB,wHAO/B;IAAE,cAAc,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,KAAG,4BA0B1D,CAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ValidationError } from 'payload';
|
|
2
|
+
import { isValidTenantAssignment } from '../utilities/isValidTenantAssignment.js';
|
|
3
|
+
export const addCollectionBeforeValidateHook = ({ collection, tenantFieldName, tenantsArrayFieldName, tenantsArrayTenantFieldName, userHasAccessToAllTenants })=>{
|
|
4
|
+
collection.hooks ??= {};
|
|
5
|
+
collection.hooks.beforeValidate ??= [];
|
|
6
|
+
collection.hooks.beforeValidate.push(enforceTenantMembership({
|
|
7
|
+
collectionSlug: collection.slug,
|
|
8
|
+
tenantFieldName,
|
|
9
|
+
tenantsArrayFieldName,
|
|
10
|
+
tenantsArrayTenantFieldName,
|
|
11
|
+
userHasAccessToAllTenants
|
|
12
|
+
}));
|
|
13
|
+
};
|
|
14
|
+
export const enforceTenantMembership = ({ collectionSlug, tenantFieldName, tenantsArrayFieldName, tenantsArrayTenantFieldName, userHasAccessToAllTenants })=>({ data, originalDoc, req })=>{
|
|
15
|
+
if (!data || !(tenantFieldName in data)) {
|
|
16
|
+
return data;
|
|
17
|
+
}
|
|
18
|
+
if (!isValidTenantAssignment({
|
|
19
|
+
previousValue: originalDoc?.[tenantFieldName],
|
|
20
|
+
req,
|
|
21
|
+
tenantsArrayFieldName,
|
|
22
|
+
tenantsArrayTenantFieldName,
|
|
23
|
+
userHasAccessToAllTenants,
|
|
24
|
+
value: data[tenantFieldName]
|
|
25
|
+
})) {
|
|
26
|
+
throw new ValidationError({
|
|
27
|
+
collection: collectionSlug,
|
|
28
|
+
errors: [
|
|
29
|
+
{
|
|
30
|
+
message: req.t('validation:invalidSelection'),
|
|
31
|
+
path: tenantFieldName
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}, req.t);
|
|
35
|
+
}
|
|
36
|
+
return data;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
//# 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 = {\n collection: CollectionConfig\n tenantFieldName: string\n tenantsArrayFieldName: string\n tenantsArrayTenantFieldName: string\n userHasAccessToAllTenants: Required<MultiTenantPluginConfig>['userHasAccessToAllTenants']\n}\n\nexport const addCollectionBeforeValidateHook = ({\n collection,\n tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n}: Args) => {\n collection.hooks ??= {}\n collection.hooks.beforeValidate ??= []\n collection.hooks.beforeValidate.push(\n enforceTenantMembership({\n collectionSlug: collection.slug,\n tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n }),\n )\n}\n\nexport const enforceTenantMembership =\n ({\n collectionSlug,\n tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n }: { collectionSlug: string } & Omit<Args, 'collection'>): CollectionBeforeValidateHook =>\n ({ data, originalDoc, req }) => {\n if (!data || !(tenantFieldName in data)) {\n return data\n }\n\n if (\n !isValidTenantAssignment({\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;AAUjF,OAAO,MAAMC,kCAAkC,CAAC,EAC9CC,UAAU,EACVC,eAAe,EACfC,qBAAqB,EACrBC,2BAA2B,EAC3BC,yBAAyB,EACpB;IACLJ,WAAWK,KAAK,KAAK,CAAC;IACtBL,WAAWK,KAAK,CAACC,cAAc,KAAK,EAAE;IACtCN,WAAWK,KAAK,CAACC,cAAc,CAACC,IAAI,CAClCC,wBAAwB;QACtBC,gBAAgBT,WAAWU,IAAI;QAC/BT;QACAC;QACAC;QACAC;IACF;AAEJ,EAAC;AAED,OAAO,MAAMI,0BACX,CAAC,EACCC,cAAc,EACdR,eAAe,EACfC,qBAAqB,EACrBC,2BAA2B,EAC3BC,yBAAyB,EAC6B,GACxD,CAAC,EAAEO,IAAI,EAAEC,WAAW,EAAEC,GAAG,EAAE;QACzB,IAAI,CAACF,QAAQ,CAAEV,CAAAA,mBAAmBU,IAAG,GAAI;YACvC,OAAOA;QACT;QAEA,IACE,CAACb,wBAAwB;YACvBgB,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,EAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Config } from 'payload';
|
|
2
1
|
import type { MultiTenantPluginConfig } from './types.js';
|
|
3
|
-
export declare const multiTenantPlugin:
|
|
2
|
+
export declare const multiTenantPlugin: (options: MultiTenantPluginConfig) => import("payload").Plugin;
|
|
4
3
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAezD,eAAO,MAAM,iBAAiB,gEA6b5B,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { definePlugin } from 'payload';
|
|
1
2
|
import { hasAutosaveEnabled } from 'payload/shared';
|
|
2
3
|
import { defaults } from './defaults.js';
|
|
3
4
|
import { getTenantOptionsEndpoint } from './endpoints/getTenantOptionsEndpoint.js';
|
|
@@ -5,12 +6,15 @@ import { tenantField } from './fields/tenantField/index.js';
|
|
|
5
6
|
import { tenantsArrayField } from './fields/tenantsArrayField/index.js';
|
|
6
7
|
import { filterDocumentsByTenants } from './filters/filterDocumentsByTenants.js';
|
|
7
8
|
import { addTenantCleanup } from './hooks/afterTenantDelete.js';
|
|
9
|
+
import { enforceTenantMembership } from './hooks/enforceTenantMembership.js';
|
|
8
10
|
import { translations } from './translations/index.js';
|
|
9
11
|
import { addCollectionAccess } from './utilities/addCollectionAccess.js';
|
|
10
12
|
import { addFilterOptionsToFields } from './utilities/addFilterOptionsToFields.js';
|
|
11
13
|
import { combineFilters } from './utilities/combineFilters.js';
|
|
12
14
|
import { miniChalk } from './utilities/miniChalk.js';
|
|
13
|
-
export const multiTenantPlugin = (
|
|
15
|
+
export const multiTenantPlugin = definePlugin({
|
|
16
|
+
slug: '@payloadcms/plugin-multi-tenant',
|
|
17
|
+
plugin: ({ config: incomingConfig, options: pluginConfig })=>{
|
|
14
18
|
if (pluginConfig.enabled === false) {
|
|
15
19
|
return incomingConfig;
|
|
16
20
|
}
|
|
@@ -21,6 +25,7 @@ export const multiTenantPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
21
25
|
const tenantFieldName = pluginConfig?.tenantField?.name || defaults.tenantFieldName;
|
|
22
26
|
const tenantsArrayFieldName = pluginConfig?.tenantsArrayField?.arrayFieldName || defaults.tenantsArrayFieldName;
|
|
23
27
|
const tenantsArrayTenantFieldName = pluginConfig?.tenantsArrayField?.arrayTenantFieldName || defaults.tenantsArrayTenantFieldName;
|
|
28
|
+
const tenantAccessScopes = [];
|
|
24
29
|
/**
|
|
25
30
|
* Add defaults for admin properties
|
|
26
31
|
*/ if (!incomingConfig.admin) {
|
|
@@ -62,12 +67,17 @@ export const multiTenantPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
62
67
|
*/ if (pluginConfig?.tenantsArrayField?.includeDefaultField !== false) {
|
|
63
68
|
adminUsersCollection.fields.push(tenantsArrayField({
|
|
64
69
|
...pluginConfig?.tenantsArrayField || {},
|
|
70
|
+
arrayFieldAccess: {
|
|
71
|
+
create: ({ req })=>Boolean(req.user && userHasAccessToAllTenants(req.user)),
|
|
72
|
+
update: ({ req })=>Boolean(req.user && userHasAccessToAllTenants(req.user)),
|
|
73
|
+
...pluginConfig?.tenantsArrayField?.arrayFieldAccess || {}
|
|
74
|
+
},
|
|
65
75
|
tenantsArrayFieldName,
|
|
66
76
|
tenantsArrayTenantFieldName,
|
|
67
77
|
tenantsCollectionSlug
|
|
68
78
|
}));
|
|
69
79
|
}
|
|
70
|
-
|
|
80
|
+
tenantAccessScopes.push({
|
|
71
81
|
accessResultCallback: pluginConfig.usersAccessResultOverride,
|
|
72
82
|
adminUsersSlug: adminUsersCollection.slug,
|
|
73
83
|
collection: adminUsersCollection,
|
|
@@ -123,7 +133,7 @@ export const multiTenantPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
123
133
|
/**
|
|
124
134
|
* Add access control constraint to tenants collection
|
|
125
135
|
* - constrains access a users assigned tenants
|
|
126
|
-
*/
|
|
136
|
+
*/ tenantAccessScopes.push({
|
|
127
137
|
adminUsersSlug: adminUsersCollection.slug,
|
|
128
138
|
collection,
|
|
129
139
|
fieldName: 'id',
|
|
@@ -236,15 +246,26 @@ export const multiTenantPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
236
246
|
* Add tenant field to enabled collections
|
|
237
247
|
*/ collection.fields.unshift(tenantField({
|
|
238
248
|
name: tenantFieldName,
|
|
249
|
+
adminUsersSlug: adminUsersCollection.slug,
|
|
239
250
|
debug: pluginConfig.debug,
|
|
240
251
|
isAutosaveEnabled: hasAutosaveEnabled(collection),
|
|
241
252
|
overrides: pluginConfig.collections[collection.slug]?.tenantFieldOverrides ? pluginConfig.collections[collection.slug]?.tenantFieldOverrides : pluginConfig.tenantField || {},
|
|
242
253
|
tenantsArrayFieldName,
|
|
243
254
|
tenantsArrayTenantFieldName,
|
|
244
255
|
tenantsCollectionSlug,
|
|
245
|
-
unique: isGlobal
|
|
256
|
+
unique: isGlobal,
|
|
257
|
+
userHasAccessToAllTenants
|
|
246
258
|
}));
|
|
247
259
|
}
|
|
260
|
+
collection.hooks ??= {};
|
|
261
|
+
collection.hooks.beforeValidate ??= [];
|
|
262
|
+
collection.hooks.beforeValidate.push(enforceTenantMembership({
|
|
263
|
+
collectionSlug: collection.slug,
|
|
264
|
+
tenantFieldName,
|
|
265
|
+
tenantsArrayFieldName,
|
|
266
|
+
tenantsArrayTenantFieldName,
|
|
267
|
+
userHasAccessToAllTenants
|
|
268
|
+
}));
|
|
248
269
|
const { useBaseFilter, useBaseListFilter } = pluginConfig.collections[collection.slug] || {};
|
|
249
270
|
if (useBaseFilter ?? useBaseListFilter ?? true) {
|
|
250
271
|
/**
|
|
@@ -266,7 +287,7 @@ export const multiTenantPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
266
287
|
if (pluginConfig.collections[collection.slug]?.useTenantAccess !== false) {
|
|
267
288
|
/**
|
|
268
289
|
* Add access control constraint to tenant enabled collection
|
|
269
|
-
*/
|
|
290
|
+
*/ tenantAccessScopes.push({
|
|
270
291
|
accessResultCallback: pluginConfig.collections[collection.slug]?.accessResultOverride,
|
|
271
292
|
adminUsersSlug: adminUsersCollection.slug,
|
|
272
293
|
collection,
|
|
@@ -289,6 +310,10 @@ export const multiTenantPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
289
310
|
// eslint-disable-next-line no-console
|
|
290
311
|
console.error(miniChalk.yellowBold('WARNING (plugin-multi-tenant)'), 'missing collections', missingSlugs, 'try placing the multi-tenant plugin after other plugins.');
|
|
291
312
|
}
|
|
313
|
+
addCollectionAccess({
|
|
314
|
+
config: incomingConfig,
|
|
315
|
+
scopes: tenantAccessScopes
|
|
316
|
+
});
|
|
292
317
|
/**
|
|
293
318
|
* Add TenantSelectionProvider to admin providers
|
|
294
319
|
*/ incomingConfig.admin.components.providers.push({
|
|
@@ -355,6 +380,7 @@ export const multiTenantPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
355
380
|
};
|
|
356
381
|
});
|
|
357
382
|
return incomingConfig;
|
|
358
|
-
}
|
|
383
|
+
}
|
|
384
|
+
});
|
|
359
385
|
|
|
360
386
|
//# sourceMappingURL=index.js.map
|
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 } 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 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 * Modify collections\n */\n incomingConfig.collections.forEach((collection) => {\n /**\n * Modify tenants collection\n */\n if (collection.slug === tenantsCollectionSlug) {\n tenantCollection = collection\n\n if (pluginConfig.useTenantsCollectionAccess !== false) {\n /**\n * Add access control constraint to tenants collection\n * - constrains access a users assigned tenants\n */\n addCollectionAccess({\n adminUsersSlug: adminUsersCollection.slug,\n collection,\n fieldName: 'id',\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n })\n }\n\n if (pluginConfig.useTenantsListFilter !== false) {\n /**\n * Add list filter to tenants collection\n * - filter by selected tenant\n */\n if (!collection.admin) {\n collection.admin = {}\n }\n\n const baseFilter = collection.admin?.baseFilter ?? collection.admin?.baseListFilter\n collection.admin.baseFilter = combineFilters({\n baseFilter,\n customFilter: (args) =>\n filterDocumentsByTenants({\n filterFieldName: 'id',\n req: args.req,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n userHasAccessToAllTenants,\n }),\n })\n }\n\n if (pluginConfig.cleanupAfterTenantDelete !== false) {\n /**\n * Add cleanup logic when tenant is deleted\n * - delete documents related to tenant\n * - remove tenant from users\n */\n addTenantCleanup({\n collection,\n enabledSlugs: [...collectionSlugs, ...globalCollectionSlugs],\n tenantFieldName,\n tenantsCollectionSlug,\n usersSlug: adminUsersCollection.slug,\n usersTenantsArrayFieldName: tenantsArrayFieldName,\n usersTenantsArrayTenantFieldName: tenantsArrayTenantFieldName,\n })\n }\n\n /**\n * Add custom tenant field that watches and dispatches updates to the selector\n */\n collection.fields.push({\n name: '_watchTenant',\n type: 'ui',\n admin: {\n components: {\n Field: {\n path: '@payloadcms/plugin-multi-tenant/client#WatchTenantCollection',\n },\n },\n disabled: { bulkEdit: true, column: true },\n },\n })\n\n collection.endpoints = [\n ...(collection.endpoints || []),\n getTenantOptionsEndpoint({\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n useAsTitle: tenantCollection.admin?.useAsTitle || 'id',\n userHasAccessToAllTenants,\n }),\n ]\n } else if (pluginConfig.collections?.[collection.slug]) {\n if (collection.slug === adminUsersCollection.slug) {\n // eslint-disable-next-line no-console\n console.warn(\n `[plugin-multi-tenant] The admin users collection \"${collection.slug}\" should not be listed in pluginConfig.collections — it is already handled by the plugin. Skipping tenant-field processing for this collection to avoid double access control and validation errors.`,\n )\n return\n }\n multiTenantCollectionsFound.push(collection.slug)\n const isGlobal = Boolean(pluginConfig.collections[collection.slug]?.isGlobal)\n\n if (isGlobal) {\n collection.disableDuplicate = true\n }\n\n if (!pluginConfig.debug && !isGlobal) {\n collection.admin ??= {}\n collection.admin.components ??= {}\n collection.admin.components.edit ??= {}\n collection.admin.components.edit.editMenuItems ??= []\n collection.admin.components.edit.editMenuItems.push({\n path: '@payloadcms/plugin-multi-tenant/client#AssignTenantFieldTrigger',\n })\n }\n\n /**\n * Add filter options to all relationship fields\n */\n collection.fields = addFilterOptionsToFields({\n blockReferencesWithFilters,\n config: incomingConfig,\n fields: collection.fields,\n tenantEnabledCollectionSlugs: collectionSlugs,\n tenantEnabledGlobalSlugs: globalCollectionSlugs,\n tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n userHasAccessToAllTenants,\n })\n\n if (pluginConfig.collections[collection.slug]?.customTenantField !== true) {\n /**\n * Add tenant field to enabled collections\n */\n collection.fields.unshift(\n tenantField({\n name: tenantFieldName,\n debug: pluginConfig.debug,\n isAutosaveEnabled: hasAutosaveEnabled(collection),\n overrides: pluginConfig.collections[collection.slug]?.tenantFieldOverrides\n ? pluginConfig.collections[collection.slug]?.tenantFieldOverrides\n : pluginConfig.tenantField || {},\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n unique: isGlobal,\n }),\n )\n }\n\n const { useBaseFilter, useBaseListFilter } = pluginConfig.collections[collection.slug] || {}\n if (useBaseFilter ?? useBaseListFilter ?? true) {\n /**\n * Add list filter to enabled collections\n * - filters results by selected tenant\n */\n collection.admin = collection.admin || {}\n collection.admin.baseFilter = combineFilters({\n baseFilter: collection.admin?.baseFilter ?? collection.admin?.baseListFilter,\n customFilter: (args) =>\n filterDocumentsByTenants({\n filterFieldName: tenantFieldName,\n req: args.req,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n userHasAccessToAllTenants,\n }),\n })\n }\n\n if (pluginConfig.collections[collection.slug]?.useTenantAccess !== false) {\n /**\n * Add access control constraint to tenant enabled collection\n */\n addCollectionAccess({\n accessResultCallback: pluginConfig.collections[collection.slug]?.accessResultOverride,\n adminUsersSlug: adminUsersCollection.slug,\n collection,\n fieldName: tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n })\n }\n }\n })\n\n if (!tenantCollection) {\n throw new Error(`Tenants collection not found with slug: ${tenantsCollectionSlug}`)\n }\n\n if (\n multiTenantCollectionsFound.length !==\n collectionSlugs.length + globalCollectionSlugs.length\n ) {\n const missingSlugs = [...collectionSlugs, ...globalCollectionSlugs].filter(\n (slug) => !multiTenantCollectionsFound.includes(slug),\n )\n // eslint-disable-next-line no-console\n console.error(\n miniChalk.yellowBold('WARNING (plugin-multi-tenant)'),\n 'missing collections',\n missingSlugs,\n 'try placing the multi-tenant plugin after other plugins.',\n )\n }\n\n /**\n * Add TenantSelectionProvider to admin providers\n */\n incomingConfig.admin.components.providers.push({\n clientProps: {\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug: tenantCollection.slug,\n useAsTitle: tenantCollection.admin?.useAsTitle || 'id',\n userHasAccessToAllTenants,\n },\n path: '@payloadcms/plugin-multi-tenant/rsc#TenantSelectionProvider',\n })\n\n /**\n * Add global redirect action\n */\n if (globalCollectionSlugs.length) {\n incomingConfig.admin.components.actions.push({\n path: '@payloadcms/plugin-multi-tenant/rsc#GlobalViewRedirect',\n serverProps: {\n globalSlugs: globalCollectionSlugs,\n tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n useAsTitle: tenantCollection.admin?.useAsTitle || 'id',\n userHasAccessToAllTenants,\n },\n })\n }\n\n /**\n * Add tenant selector to admin UI\n */\n incomingConfig.admin.components.beforeNav.push({\n clientProps: {\n enabledSlugs: [\n ...collectionSlugs,\n ...globalCollectionSlugs,\n adminUsersCollection.slug,\n tenantCollection.slug,\n ],\n label: pluginConfig.tenantSelectorLabel || undefined,\n },\n path: '@payloadcms/plugin-multi-tenant/rsc#TenantSelector',\n })\n\n /**\n * Merge plugin translations\n */\n if (!incomingConfig.i18n) {\n incomingConfig.i18n = {}\n }\n Object.entries(translations).forEach(([locale, pluginI18nObject]) => {\n const typedLocale = locale as AcceptedLanguages\n if (!incomingConfig.i18n!.translations) {\n incomingConfig.i18n!.translations = {}\n }\n if (!(typedLocale in incomingConfig.i18n!.translations)) {\n incomingConfig.i18n!.translations[typedLocale] = {}\n }\n if (!('plugin-multi-tenant' in incomingConfig.i18n!.translations[typedLocale]!)) {\n ;(incomingConfig.i18n!.translations[typedLocale] as PluginDefaultTranslationsObject)[\n 'plugin-multi-tenant'\n ] = {} as PluginDefaultTranslationsObject['plugin-multi-tenant']\n }\n\n ;(incomingConfig.i18n!.translations[typedLocale] as PluginDefaultTranslationsObject)[\n 'plugin-multi-tenant'\n ] = {\n ...pluginI18nObject.translations['plugin-multi-tenant'],\n ...(pluginConfig.i18n?.translations?.[typedLocale] || {}),\n }\n })\n\n return incomingConfig\n }\n"],"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","accessResultCallback","usersAccessResultOverride","adminUsersSlug","collection","fieldName","useUsersTenantFilter","baseFilter","baseListFilter","customFilter","args","filterFieldName","req","tenantCollection","collectionSlugs","globalCollectionSlugs","Object","keys","reduce","acc","isGlobal","blockReferencesWithFilters","multiTenantCollectionsFound","forEach","useTenantsCollectionAccess","useTenantsListFilter","cleanupAfterTenantDelete","enabledSlugs","usersSlug","usersTenantsArrayFieldName","usersTenantsArrayTenantFieldName","type","Field","path","disabled","bulkEdit","column","endpoints","useAsTitle","console","warn","Boolean","disableDuplicate","debug","edit","editMenuItems","config","tenantEnabledCollectionSlugs","tenantEnabledGlobalSlugs","customTenantField","unshift","isAutosaveEnabled","overrides","tenantFieldOverrides","unique","useBaseFilter","useBaseListFilter","useTenantAccess","accessResultOverride","length","missingSlugs","filter","includes","error","yellowBold","clientProps","serverProps","globalSlugs","label","tenantSelectorLabel","undefined","i18n","entries","locale","pluginI18nObject","typedLocale"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { AcceptedLanguages } from '@payloadcms/translations'\nimport type { CollectionConfig } from 'payload'\n\nimport { definePlugin } from 'payload'\nimport { hasAutosaveEnabled } from 'payload/shared'\n\nimport type { PluginDefaultTranslationsObject } from './translations/types.js'\nimport type { MultiTenantPluginConfig } from './types.js'\n\nimport { defaults } from './defaults.js'\nimport { getTenantOptionsEndpoint } from './endpoints/getTenantOptionsEndpoint.js'\nimport { tenantField } from './fields/tenantField/index.js'\nimport { tenantsArrayField } from './fields/tenantsArrayField/index.js'\nimport { filterDocumentsByTenants } from './filters/filterDocumentsByTenants.js'\nimport { addTenantCleanup } from './hooks/afterTenantDelete.js'\nimport { enforceTenantMembership } from './hooks/enforceTenantMembership.js'\nimport { translations } from './translations/index.js'\nimport { addCollectionAccess, type TenantAccessConfig } from './utilities/addCollectionAccess.js'\nimport { addFilterOptionsToFields } from './utilities/addFilterOptionsToFields.js'\nimport { combineFilters } from './utilities/combineFilters.js'\nimport { miniChalk } from './utilities/miniChalk.js'\n\nexport const multiTenantPlugin = definePlugin<MultiTenantPluginConfig>({\n slug: '@payloadcms/plugin-multi-tenant',\n plugin: ({ config: incomingConfig, options: pluginConfig }) => {\n if (pluginConfig.enabled === false) {\n return incomingConfig\n }\n\n /**\n * Set defaults\n */\n const userHasAccessToAllTenants: Required<MultiTenantPluginConfig>['userHasAccessToAllTenants'] =\n typeof pluginConfig.userHasAccessToAllTenants === 'function'\n ? pluginConfig.userHasAccessToAllTenants\n : () => false\n const tenantsCollectionSlug = (pluginConfig.tenantsSlug =\n pluginConfig.tenantsSlug || defaults.tenantCollectionSlug)\n const tenantFieldName = pluginConfig?.tenantField?.name || defaults.tenantFieldName\n const tenantsArrayFieldName =\n pluginConfig?.tenantsArrayField?.arrayFieldName || defaults.tenantsArrayFieldName\n const tenantsArrayTenantFieldName =\n pluginConfig?.tenantsArrayField?.arrayTenantFieldName || defaults.tenantsArrayTenantFieldName\n const tenantAccessScopes: TenantAccessConfig[] = []\n\n /**\n * Add defaults for admin properties\n */\n if (!incomingConfig.admin) {\n incomingConfig.admin = {}\n }\n if (!incomingConfig.admin?.components) {\n incomingConfig.admin.components = {\n actions: [],\n beforeNav: [],\n providers: [],\n }\n }\n if (!incomingConfig.admin.components?.providers) {\n incomingConfig.admin.components.providers = []\n }\n if (!incomingConfig.admin.components?.actions) {\n incomingConfig.admin.components.actions = []\n }\n if (!incomingConfig.admin.components?.beforeNav) {\n incomingConfig.admin.components.beforeNav = []\n }\n if (!incomingConfig.collections) {\n incomingConfig.collections = []\n }\n\n /**\n * Add tenants array field to users collection\n */\n const adminUsersCollection = incomingConfig.collections.find(({ slug, auth }) => {\n if (incomingConfig.admin?.user) {\n return slug === incomingConfig.admin.user\n } else if (auth) {\n return true\n }\n })\n\n if (!adminUsersCollection) {\n throw Error('An auth enabled collection was not found')\n }\n\n /**\n * Add tenants array field to users collection\n */\n if (pluginConfig?.tenantsArrayField?.includeDefaultField !== false) {\n adminUsersCollection.fields.push(\n tenantsArrayField({\n ...(pluginConfig?.tenantsArrayField || {}),\n arrayFieldAccess: {\n create: ({ req }) => Boolean(req.user && userHasAccessToAllTenants(req.user)),\n update: ({ req }) => Boolean(req.user && userHasAccessToAllTenants(req.user)),\n ...(pluginConfig?.tenantsArrayField?.arrayFieldAccess || {}),\n },\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n }),\n )\n }\n\n tenantAccessScopes.push({\n accessResultCallback: pluginConfig.usersAccessResultOverride,\n adminUsersSlug: adminUsersCollection.slug,\n collection: adminUsersCollection,\n fieldName: `${tenantsArrayFieldName}.${tenantsArrayTenantFieldName}`,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n })\n\n if (pluginConfig.useUsersTenantFilter !== false) {\n if (!adminUsersCollection.admin) {\n adminUsersCollection.admin = {}\n }\n\n const baseFilter =\n adminUsersCollection.admin?.baseFilter ?? adminUsersCollection.admin?.baseListFilter\n adminUsersCollection.admin.baseFilter = combineFilters({\n baseFilter,\n customFilter: (args) =>\n filterDocumentsByTenants({\n filterFieldName: `${tenantsArrayFieldName}.${tenantsArrayTenantFieldName}`,\n req: args.req,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n userHasAccessToAllTenants,\n }),\n })\n }\n\n let tenantCollection: CollectionConfig | undefined\n\n const [collectionSlugs, globalCollectionSlugs] = Object.keys(pluginConfig.collections).reduce<\n [string[], string[]]\n >(\n (acc, slug) => {\n if (slug === adminUsersCollection.slug) {\n return acc\n }\n if (pluginConfig?.collections?.[slug]?.isGlobal) {\n acc[1].push(slug)\n } else {\n acc[0].push(slug)\n }\n\n return acc\n },\n [[], []],\n )\n\n // used to track and not duplicate filterOptions on referenced blocks\n const blockReferencesWithFilters: string[] = []\n\n // used to validate enabled collection slugs\n const multiTenantCollectionsFound: string[] = []\n\n /**\n * Modify collections\n */\n incomingConfig.collections.forEach((collection) => {\n /**\n * Modify tenants collection\n */\n if (collection.slug === tenantsCollectionSlug) {\n tenantCollection = collection\n\n if (pluginConfig.useTenantsCollectionAccess !== false) {\n /**\n * Add access control constraint to tenants collection\n * - constrains access a users assigned tenants\n */\n tenantAccessScopes.push({\n adminUsersSlug: adminUsersCollection.slug,\n collection,\n fieldName: 'id',\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\n })\n }\n\n if (pluginConfig.useTenantsListFilter !== false) {\n /**\n * Add list filter to tenants collection\n * - filter by selected tenant\n */\n if (!collection.admin) {\n collection.admin = {}\n }\n\n const baseFilter = collection.admin?.baseFilter ?? collection.admin?.baseListFilter\n collection.admin.baseFilter = combineFilters({\n baseFilter,\n customFilter: (args) =>\n filterDocumentsByTenants({\n filterFieldName: 'id',\n req: args.req,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n userHasAccessToAllTenants,\n }),\n })\n }\n\n if (pluginConfig.cleanupAfterTenantDelete !== false) {\n /**\n * Add cleanup logic when tenant is deleted\n * - delete documents related to tenant\n * - remove tenant from users\n */\n addTenantCleanup({\n collection,\n enabledSlugs: [...collectionSlugs, ...globalCollectionSlugs],\n tenantFieldName,\n tenantsCollectionSlug,\n usersSlug: adminUsersCollection.slug,\n usersTenantsArrayFieldName: tenantsArrayFieldName,\n usersTenantsArrayTenantFieldName: tenantsArrayTenantFieldName,\n })\n }\n\n /**\n * Add custom tenant field that watches and dispatches updates to the selector\n */\n collection.fields.push({\n name: '_watchTenant',\n type: 'ui',\n admin: {\n components: {\n Field: {\n path: '@payloadcms/plugin-multi-tenant/client#WatchTenantCollection',\n },\n },\n disabled: { bulkEdit: true, column: true },\n },\n })\n\n collection.endpoints = [\n ...(collection.endpoints || []),\n getTenantOptionsEndpoint({\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n useAsTitle: tenantCollection.admin?.useAsTitle || 'id',\n userHasAccessToAllTenants,\n }),\n ]\n } else if (pluginConfig.collections?.[collection.slug]) {\n if (collection.slug === adminUsersCollection.slug) {\n // eslint-disable-next-line no-console\n console.warn(\n `[plugin-multi-tenant] The admin users collection \"${collection.slug}\" should not be listed in pluginConfig.collections — it is already handled by the plugin. Skipping tenant-field processing for this collection to avoid double access control and validation errors.`,\n )\n return\n }\n multiTenantCollectionsFound.push(collection.slug)\n const isGlobal = Boolean(pluginConfig.collections[collection.slug]?.isGlobal)\n\n if (isGlobal) {\n collection.disableDuplicate = true\n }\n\n if (!pluginConfig.debug && !isGlobal) {\n collection.admin ??= {}\n collection.admin.components ??= {}\n collection.admin.components.edit ??= {}\n collection.admin.components.edit.editMenuItems ??= []\n collection.admin.components.edit.editMenuItems.push({\n path: '@payloadcms/plugin-multi-tenant/client#AssignTenantFieldTrigger',\n })\n }\n\n /**\n * Add filter options to all relationship fields\n */\n collection.fields = addFilterOptionsToFields({\n blockReferencesWithFilters,\n config: incomingConfig,\n fields: collection.fields,\n tenantEnabledCollectionSlugs: collectionSlugs,\n tenantEnabledGlobalSlugs: globalCollectionSlugs,\n tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n userHasAccessToAllTenants,\n })\n\n if (pluginConfig.collections[collection.slug]?.customTenantField !== true) {\n /**\n * Add tenant field to enabled collections\n */\n collection.fields.unshift(\n tenantField({\n name: tenantFieldName,\n 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 collection.hooks ??= {}\n collection.hooks.beforeValidate ??= []\n collection.hooks.beforeValidate.push(\n enforceTenantMembership({\n collectionSlug: collection.slug,\n tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n userHasAccessToAllTenants,\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 tenantAccessScopes.push({\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 addCollectionAccess({ config: incomingConfig, scopes: tenantAccessScopes })\n\n /**\n * Add TenantSelectionProvider to admin providers\n */\n incomingConfig.admin.components.providers.push({\n clientProps: {\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug: tenantCollection.slug,\n useAsTitle: tenantCollection.admin?.useAsTitle || 'id',\n userHasAccessToAllTenants,\n },\n path: '@payloadcms/plugin-multi-tenant/rsc#TenantSelectionProvider',\n })\n\n /**\n * Add global redirect action\n */\n if (globalCollectionSlugs.length) {\n incomingConfig.admin.components.actions.push({\n path: '@payloadcms/plugin-multi-tenant/rsc#GlobalViewRedirect',\n serverProps: {\n globalSlugs: globalCollectionSlugs,\n tenantFieldName,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n useAsTitle: tenantCollection.admin?.useAsTitle || 'id',\n userHasAccessToAllTenants,\n },\n })\n }\n\n /**\n * Add tenant selector to admin UI\n */\n incomingConfig.admin.components.beforeNav.push({\n clientProps: {\n enabledSlugs: [\n ...collectionSlugs,\n ...globalCollectionSlugs,\n adminUsersCollection.slug,\n tenantCollection.slug,\n ],\n label: pluginConfig.tenantSelectorLabel || undefined,\n },\n path: '@payloadcms/plugin-multi-tenant/rsc#TenantSelector',\n })\n\n /**\n * Merge plugin translations\n */\n if (!incomingConfig.i18n) {\n incomingConfig.i18n = {}\n }\n Object.entries(translations).forEach(([locale, pluginI18nObject]) => {\n const typedLocale = locale as AcceptedLanguages\n if (!incomingConfig.i18n!.translations) {\n incomingConfig.i18n!.translations = {}\n }\n if (!(typedLocale in incomingConfig.i18n!.translations)) {\n incomingConfig.i18n!.translations[typedLocale] = {}\n }\n if (!('plugin-multi-tenant' in incomingConfig.i18n!.translations[typedLocale]!)) {\n ;(incomingConfig.i18n!.translations[typedLocale] as PluginDefaultTranslationsObject)[\n 'plugin-multi-tenant'\n ] = {} as PluginDefaultTranslationsObject['plugin-multi-tenant']\n }\n\n ;(incomingConfig.i18n!.translations[typedLocale] as PluginDefaultTranslationsObject)[\n 'plugin-multi-tenant'\n ] = {\n ...pluginI18nObject.translations['plugin-multi-tenant'],\n ...(pluginConfig.i18n?.translations?.[typedLocale] || {}),\n }\n })\n\n return incomingConfig\n },\n})\n"],"names":["definePlugin","hasAutosaveEnabled","defaults","getTenantOptionsEndpoint","tenantField","tenantsArrayField","filterDocumentsByTenants","addTenantCleanup","enforceTenantMembership","translations","addCollectionAccess","addFilterOptionsToFields","combineFilters","miniChalk","multiTenantPlugin","slug","plugin","config","incomingConfig","options","pluginConfig","enabled","userHasAccessToAllTenants","tenantsCollectionSlug","tenantsSlug","tenantCollectionSlug","tenantFieldName","name","tenantsArrayFieldName","arrayFieldName","tenantsArrayTenantFieldName","arrayTenantFieldName","tenantAccessScopes","admin","components","actions","beforeNav","providers","collections","adminUsersCollection","find","auth","user","Error","includeDefaultField","fields","push","arrayFieldAccess","create","req","Boolean","update","accessResultCallback","usersAccessResultOverride","adminUsersSlug","collection","fieldName","useUsersTenantFilter","baseFilter","baseListFilter","customFilter","args","filterFieldName","tenantCollection","collectionSlugs","globalCollectionSlugs","Object","keys","reduce","acc","isGlobal","blockReferencesWithFilters","multiTenantCollectionsFound","forEach","useTenantsCollectionAccess","useTenantsListFilter","cleanupAfterTenantDelete","enabledSlugs","usersSlug","usersTenantsArrayFieldName","usersTenantsArrayTenantFieldName","type","Field","path","disabled","bulkEdit","column","endpoints","useAsTitle","console","warn","disableDuplicate","debug","edit","editMenuItems","tenantEnabledCollectionSlugs","tenantEnabledGlobalSlugs","customTenantField","unshift","isAutosaveEnabled","overrides","tenantFieldOverrides","unique","hooks","beforeValidate","collectionSlug","useBaseFilter","useBaseListFilter","useTenantAccess","accessResultOverride","length","missingSlugs","filter","includes","error","yellowBold","scopes","clientProps","serverProps","globalSlugs","label","tenantSelectorLabel","undefined","i18n","entries","locale","pluginI18nObject","typedLocale"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.client.d.ts","sourceRoot":"","sources":["../../../src/providers/TenantSelectionProvider/index.client.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAI3C,OAAO,KAAwB,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"index.client.d.ts","sourceRoot":"","sources":["../../../src/providers/TenantSelectionProvider/index.client.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAI3C,OAAO,KAAwB,MAAM,OAAO,CAAA;AAK5C,KAAK,WAAW,GAAG;IACjB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAA;IAClC;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;OAEG;IACH,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB;;OAEG;IACH,gBAAgB,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IAC7C;;OAEG;IACH,aAAa,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAA;IACtF;;OAEG;IACH,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAA;IAC1D;;;;;OAKG;IACH,SAAS,EAAE,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAA;IACjF;;OAEG;IACH,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAChC;;OAEG;IACH,aAAa,EAAE,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;CACtE,CAAA;AA+CD,eAAO,MAAM,6BAA6B,6EAKvC;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,oBAAoB,EAAE,YAAY,EAAE,CAAA;IACpC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC9B,qBAAqB,EAAE,MAAM,CAAA;CAC9B,sBAkOA,CAAA;AAED,eAAO,MAAM,kBAAkB,mBAA2B,CAAA"}
|
|
@@ -4,6 +4,7 @@ import { toast, useAuth, useConfig, useRouter } from '@payloadcms/ui';
|
|
|
4
4
|
import { formatAdminURL } from 'payload/shared';
|
|
5
5
|
import React, { createContext } from 'react';
|
|
6
6
|
import { generateCookie } from '../../utilities/generateCookie.js';
|
|
7
|
+
import { shouldRefreshTenantSelection } from '../../utilities/shouldRefreshTenantSelection.js';
|
|
7
8
|
const Context = /*#__PURE__*/ createContext({
|
|
8
9
|
entityType: undefined,
|
|
9
10
|
options: [],
|
|
@@ -176,17 +177,18 @@ export const TenantSelectionProviderClient = ({ children, initialTenantOptions,
|
|
|
176
177
|
initialTenantOptions
|
|
177
178
|
]);
|
|
178
179
|
React.useEffect(()=>{
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
180
|
+
const hasTenantSelectionMismatch = initialValue && String(initialValue) !== getTenantCookie();
|
|
181
|
+
if (userID && (userChanged || tenantOptions.length === 0 || hasTenantSelectionMismatch)) {
|
|
182
|
+
// Sync on login, and when the provider remounts after login without tenant options.
|
|
183
|
+
void syncTenants();
|
|
184
|
+
} else if (!userID && (userChanged || hasTenantSelectionMismatch)) {
|
|
185
|
+
// user logging out
|
|
186
|
+
setSelectedTenantID(undefined);
|
|
187
|
+
deleteTenantCookie();
|
|
188
|
+
setTenantOptions((prev)=>prev.length > 0 ? [] : prev);
|
|
189
|
+
router.refresh();
|
|
190
|
+
}
|
|
191
|
+
if (userChanged) {
|
|
190
192
|
prevUserID.current = userID;
|
|
191
193
|
}
|
|
192
194
|
}, [
|
|
@@ -194,24 +196,42 @@ export const TenantSelectionProviderClient = ({ children, initialTenantOptions,
|
|
|
194
196
|
userChanged,
|
|
195
197
|
syncTenants,
|
|
196
198
|
initialValue,
|
|
197
|
-
router
|
|
199
|
+
router,
|
|
200
|
+
tenantOptions.length
|
|
201
|
+
]);
|
|
202
|
+
/**
|
|
203
|
+
* Populate tenant options when the provider mounts already-authenticated but
|
|
204
|
+
* without server-provided options. This happens when a provider setup remounts
|
|
205
|
+
* this subtree on login (see `config.conditionalProvider`): the remounted
|
|
206
|
+
* instance initializes `prevUserID` to the current user, so `userChanged` above
|
|
207
|
+
* is `false` and never fires `syncTenants`, while the server still rendered the
|
|
208
|
+
* logged-out tree so `initialTenantOptions` is empty — leaving the selector
|
|
209
|
+
* unrendered. Unlike `router.refresh()`, `syncTenants()` is a plain client fetch
|
|
210
|
+
* that cannot trigger a remount loop, so this is safe on every framework adapter.
|
|
211
|
+
*/ const didInitialSync = React.useRef(false);
|
|
212
|
+
React.useEffect(()=>{
|
|
213
|
+
if (!didInitialSync.current && !userChanged && userID && tenantOptions.length === 0 && initialTenantOptions.length === 0) {
|
|
214
|
+
didInitialSync.current = true;
|
|
215
|
+
void syncTenants();
|
|
216
|
+
}
|
|
217
|
+
}, [
|
|
218
|
+
userChanged,
|
|
219
|
+
userID,
|
|
220
|
+
tenantOptions.length,
|
|
221
|
+
initialTenantOptions,
|
|
222
|
+
syncTenants
|
|
198
223
|
]);
|
|
199
224
|
/**
|
|
200
|
-
* If there is no initial value
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
* Only refresh when there is actually a stale cookie to clear: when no cookie
|
|
204
|
-
* is present the server already rendered tenant-less, so a refresh is
|
|
205
|
-
* redundant. This also avoids an infinite loop on framework adapters whose
|
|
206
|
-
* `router.refresh()` remounts this provider (e.g. TanStack Start) — an
|
|
207
|
-
* unconditional refresh would re-fire this mount effect and refresh again,
|
|
208
|
-
* whereas guarding on the (persistent) cookie self-terminates after the one
|
|
209
|
-
* refresh that clears it. The cookie is cleared either way via `setTenant`.
|
|
225
|
+
* If there is no initial value and a stale tenant cookie exists, clear the
|
|
226
|
+
* tenant and refresh the router.
|
|
210
227
|
*/ React.useEffect(()=>{
|
|
211
|
-
if (
|
|
228
|
+
if (shouldRefreshTenantSelection({
|
|
229
|
+
initialValue,
|
|
230
|
+
tenantCookie: getTenantCookie()
|
|
231
|
+
})) {
|
|
212
232
|
setTenant({
|
|
213
233
|
id: undefined,
|
|
214
|
-
refresh:
|
|
234
|
+
refresh: true
|
|
215
235
|
});
|
|
216
236
|
}
|
|
217
237
|
}, [
|