@payloadcms/plugin-multi-tenant 4.0.0-internal.293e026 → 4.0.0-internal.2f0d313
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 -3
- package/dist/components/AssignTenantFieldModal/index.client.d.ts.map +1 -1
- package/dist/components/AssignTenantFieldModal/index.client.js +26 -81
- 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 +1 -1
- package/dist/components/TenantField/index.client.d.ts.map +1 -1
- package/dist/components/TenantField/index.client.js +85 -75
- package/dist/components/TenantField/index.client.js.map +1 -1
- package/dist/components/TenantField/index.css +44 -0
- package/dist/components/TenantSelector/index.client.d.ts +2 -2
- package/dist/components/TenantSelector/index.client.d.ts.map +1 -1
- package/dist/components/TenantSelector/index.client.js +4 -2
- package/dist/components/TenantSelector/index.client.js.map +1 -1
- package/dist/components/TenantSelector/index.css +13 -0
- 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.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/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -5
- package/dist/index.js.map +1 -1
- package/dist/index.spec.js +70 -0
- package/dist/index.spec.js.map +1 -0
- package/dist/providers/TenantSelectionProvider/index.client.d.ts.map +1 -1
- package/dist/providers/TenantSelectionProvider/index.client.js +31 -1
- 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/addCollectionAccess.spec.js +134 -0
- package/dist/utilities/addCollectionAccess.spec.js.map +1 -0
- 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/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 +2 -1
- package/dist/utilities/getUserTenantIDs.js.map +1 -1
- package/dist/utilities/miniChalk.d.ts.map +1 -1
- package/package.json +6 -7
- package/dist/@types/assets.d.js +0 -2
- package/dist/@types/assets.d.js.map +0 -1
- package/dist/components/AssignTenantFieldModal/index.scss +0 -78
- package/dist/components/TenantField/index.scss +0 -52
- package/dist/components/TenantSelector/index.scss +0 -4
- 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,"sources":["../../../src/components/TenantSelector/index.client.tsx"],"sourcesContent":["'use client'\nimport type { ReactSelectOption } from '@payloadcms/ui'\nimport type { ViewTypes } from 'payload'\n\nimport { getTranslation } from '@payloadcms/translations'\nimport { ConfirmationModal, SelectInput, useModal, useTranslation } from '@payloadcms/ui'\nimport React from 'react'\n\nimport type {\n PluginMultiTenantTranslationKeys,\n PluginMultiTenantTranslations,\n} from '../../translations/index.js'\nimport type { MultiTenantPluginConfig } from '../../types.js'\n\nimport { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js'\nimport './index.
|
|
1
|
+
{"version":3,"sources":["../../../src/components/TenantSelector/index.client.tsx"],"sourcesContent":["'use client'\nimport type { ReactSelectOption } from '@payloadcms/ui'\nimport type { ViewTypes } from 'payload'\n\nimport { getTranslation } from '@payloadcms/translations'\nimport { ConfirmationModal, SelectInput, useModal, useTranslation } from '@payloadcms/ui'\nimport React from 'react'\n\nimport type {\n PluginMultiTenantTranslationKeys,\n PluginMultiTenantTranslations,\n} from '../../translations/index.js'\nimport type { MultiTenantPluginConfig } from '../../types.js'\n\nimport { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js'\nimport './index.css'\n\nconst confirmLeaveWithoutSavingSlug = 'confirm-leave-without-saving'\n\nconst baseClass = 'tenant-selector'\n\nexport const TenantSelectorClient = ({\n disabled: disabledFromProps,\n label,\n viewType,\n}: {\n disabled?: boolean\n label?: MultiTenantPluginConfig['tenantSelectorLabel']\n viewType?: ViewTypes\n}) => {\n const { entityType, modified, options, selectedTenantID, setTenant } = useTenantSelection()\n const { closeModal, openModal } = useModal()\n const { i18n, t } = useTranslation<\n PluginMultiTenantTranslations,\n PluginMultiTenantTranslationKeys\n >()\n const [tenantSelection, setTenantSelection] = React.useState<\n ReactSelectOption | ReactSelectOption[]\n >()\n\n const switchTenant = React.useCallback(\n (option: ReactSelectOption | ReactSelectOption[] | undefined) => {\n if (option && 'value' in option) {\n setTenant({ id: option.value as string, refresh: true })\n } else {\n setTenant({ id: undefined, refresh: true })\n }\n },\n [setTenant],\n )\n\n const onChange = React.useCallback(\n (option: ReactSelectOption | ReactSelectOption[]) => {\n if (option && 'value' in option && option.value === selectedTenantID) {\n // If the selected option is the same as the current tenant, do nothing\n return\n }\n\n if (entityType === 'global' && modified) {\n // If the entityType is 'global' and there are unsaved changes, prompt for confirmation\n setTenantSelection(option)\n openModal(confirmLeaveWithoutSavingSlug)\n } else {\n // If the entityType is not 'document', switch tenant without confirmation\n switchTenant(option)\n }\n },\n [selectedTenantID, entityType, modified, switchTenant, openModal],\n )\n\n if (options.length <= 1) {\n return null\n }\n\n return (\n <div className={baseClass}>\n <SelectInput\n className={`${baseClass}__select`}\n isClearable={['dashboard', 'list'].includes(viewType ?? '')}\n label={\n label ? getTranslation(label, i18n) : t('plugin-multi-tenant:nav-tenantSelector-label')\n }\n name=\"setTenant\"\n onChange={onChange}\n options={options}\n path=\"setTenant\"\n readOnly={\n disabledFromProps ||\n (entityType !== 'global' &&\n viewType &&\n (['document', 'version'] satisfies ViewTypes[] as ViewTypes[]).includes(viewType))\n }\n value={selectedTenantID as string | undefined}\n />\n\n <ConfirmationModal\n body={t('general:changesNotSaved')}\n cancelLabel={t('general:stayOnThisPage')}\n confirmLabel={t('general:leaveAnyway')}\n heading={t('general:leaveWithoutSaving')}\n modalSlug={confirmLeaveWithoutSavingSlug}\n onCancel={() => {\n closeModal(confirmLeaveWithoutSavingSlug)\n }}\n onConfirm={() => {\n switchTenant(tenantSelection)\n }}\n />\n </div>\n )\n}\n"],"names":["getTranslation","ConfirmationModal","SelectInput","useModal","useTranslation","React","useTenantSelection","confirmLeaveWithoutSavingSlug","baseClass","TenantSelectorClient","disabled","disabledFromProps","label","viewType","entityType","modified","options","selectedTenantID","setTenant","closeModal","openModal","i18n","t","tenantSelection","setTenantSelection","useState","switchTenant","useCallback","option","id","value","refresh","undefined","onChange","length","div","className","isClearable","includes","name","path","readOnly","body","cancelLabel","confirmLabel","heading","modalSlug","onCancel","onConfirm"],"mappings":"AAAA;;AAIA,SAASA,cAAc,QAAQ,2BAA0B;AACzD,SAASC,iBAAiB,EAAEC,WAAW,EAAEC,QAAQ,EAAEC,cAAc,QAAQ,iBAAgB;AACzF,OAAOC,WAAW,QAAO;AAQzB,SAASC,kBAAkB,QAAQ,0DAAyD;AAC5F,OAAO,cAAa;AAEpB,MAAMC,gCAAgC;AAEtC,MAAMC,YAAY;AAElB,OAAO,MAAMC,uBAAuB,CAAC,EACnCC,UAAUC,iBAAiB,EAC3BC,KAAK,EACLC,QAAQ,EAKT;IACC,MAAM,EAAEC,UAAU,EAAEC,QAAQ,EAAEC,OAAO,EAAEC,gBAAgB,EAAEC,SAAS,EAAE,GAAGZ;IACvE,MAAM,EAAEa,UAAU,EAAEC,SAAS,EAAE,GAAGjB;IAClC,MAAM,EAAEkB,IAAI,EAAEC,CAAC,EAAE,GAAGlB;IAIpB,MAAM,CAACmB,iBAAiBC,mBAAmB,GAAGnB,MAAMoB,QAAQ;IAI5D,MAAMC,eAAerB,MAAMsB,WAAW,CACpC,CAACC;QACC,IAAIA,UAAU,WAAWA,QAAQ;YAC/BV,UAAU;gBAAEW,IAAID,OAAOE,KAAK;gBAAYC,SAAS;YAAK;QACxD,OAAO;YACLb,UAAU;gBAAEW,IAAIG;gBAAWD,SAAS;YAAK;QAC3C;IACF,GACA;QAACb;KAAU;IAGb,MAAMe,WAAW5B,MAAMsB,WAAW,CAChC,CAACC;QACC,IAAIA,UAAU,WAAWA,UAAUA,OAAOE,KAAK,KAAKb,kBAAkB;YACpE,uEAAuE;YACvE;QACF;QAEA,IAAIH,eAAe,YAAYC,UAAU;YACvC,uFAAuF;YACvFS,mBAAmBI;YACnBR,UAAUb;QACZ,OAAO;YACL,0EAA0E;YAC1EmB,aAAaE;QACf;IACF,GACA;QAACX;QAAkBH;QAAYC;QAAUW;QAAcN;KAAU;IAGnE,IAAIJ,QAAQkB,MAAM,IAAI,GAAG;QACvB,OAAO;IACT;IAEA,qBACE,MAACC;QAAIC,WAAW5B;;0BACd,KAACN;gBACCkC,WAAW,GAAG5B,UAAU,QAAQ,CAAC;gBACjC6B,aAAa;oBAAC;oBAAa;iBAAO,CAACC,QAAQ,CAACzB,YAAY;gBACxDD,OACEA,QAAQZ,eAAeY,OAAOS,QAAQC,EAAE;gBAE1CiB,MAAK;gBACLN,UAAUA;gBACVjB,SAASA;gBACTwB,MAAK;gBACLC,UACE9B,qBACCG,eAAe,YACdD,YACA,AAAC;oBAAC;oBAAY;iBAAU,CAAuCyB,QAAQ,CAACzB;gBAE5EiB,OAAOb;;0BAGT,KAAChB;gBACCyC,MAAMpB,EAAE;gBACRqB,aAAarB,EAAE;gBACfsB,cAActB,EAAE;gBAChBuB,SAASvB,EAAE;gBACXwB,WAAWvC;gBACXwC,UAAU;oBACR5B,WAAWZ;gBACb;gBACAyC,WAAW;oBACTtB,aAAaH;gBACf;;;;AAIR,EAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
@layer payload-default {
|
|
2
|
+
.tenant-selector {
|
|
3
|
+
border-bottom: var(--stroke-width-small) solid var(--color-border);
|
|
4
|
+
width: calc(100% + var(--nav-padding-block-start) * 2);
|
|
5
|
+
margin-inline-start: calc(-1 * var(--nav-padding-inline-start));
|
|
6
|
+
margin-block-end: var(--spacer-4);
|
|
7
|
+
padding-block-end: var(--spacer-4);
|
|
8
|
+
|
|
9
|
+
.tenant-selector__select {
|
|
10
|
+
margin-inline: var(--nav-padding-inline-start);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/TenantSelector/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAE1C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAI7D,KAAK,KAAK,GAAG;IACX,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,KAAK,EAAE,uBAAuB,CAAC,qBAAqB,CAAC,CAAA;CACtD,GAAG,WAAW,CAAA;AACf,eAAO,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/TenantSelector/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAE1C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAI7D,KAAK,KAAK,GAAG;IACX,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,KAAK,EAAE,uBAAuB,CAAC,qBAAqB,CAAC,CAAA;CACtD,GAAG,WAAW,CAAA;AACf,eAAO,MAAM,cAAc,UAAW,KAAK,gCAI1C,CAAA"}
|
package/dist/defaults.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ;IACnB,oBAAoB;IACpB,eAAe;IACf,qBAAqB;IACrB,2BAA2B;IAC3B,mBAAmB;CACpB,CAAA"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Endpoint } from 'payload';
|
|
2
2
|
import type { MultiTenantPluginConfig } from '../types.js';
|
|
3
|
-
export declare const getTenantOptionsEndpoint:
|
|
3
|
+
export declare const getTenantOptionsEndpoint: ({ tenantsArrayFieldName, tenantsArrayTenantFieldName, tenantsCollectionSlug, useAsTitle, userHasAccessToAllTenants, }: {
|
|
4
4
|
tenantsArrayFieldName: string;
|
|
5
5
|
tenantsArrayTenantFieldName: string;
|
|
6
6
|
tenantsCollectionSlug: string;
|
|
7
7
|
useAsTitle: string;
|
|
8
|
-
userHasAccessToAllTenants: Required<MultiTenantPluginConfig
|
|
8
|
+
userHasAccessToAllTenants: Required<MultiTenantPluginConfig>['userHasAccessToAllTenants'];
|
|
9
9
|
}) => Endpoint;
|
|
10
10
|
//# sourceMappingURL=getTenantOptionsEndpoint.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getTenantOptionsEndpoint.d.ts","sourceRoot":"","sources":["../../src/endpoints/getTenantOptionsEndpoint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAIvC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAI1D,eAAO,MAAM,wBAAwB,
|
|
1
|
+
{"version":3,"file":"getTenantOptionsEndpoint.d.ts","sourceRoot":"","sources":["../../src/endpoints/getTenantOptionsEndpoint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAIvC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAI1D,eAAO,MAAM,wBAAwB,0HAMlC;IACD,qBAAqB,EAAE,MAAM,CAAA;IAC7B,2BAA2B,EAAE,MAAM,CAAA;IACnC,qBAAqB,EAAE,MAAM,CAAA;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,yBAAyB,EAAE,QAAQ,CAAC,uBAAuB,CAAC,CAAC,2BAA2B,CAAC,CAAA;CAC1F,KAAG,QAsBF,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/endpoints/getTenantOptionsEndpoint.ts"],"sourcesContent":["import type { Endpoint } from 'payload'\n\nimport { APIError } from 'payload'\n\nimport type { MultiTenantPluginConfig } from '../types.js'\n\nimport { getTenantOptions } from '../utilities/getTenantOptions.js'\n\nexport const getTenantOptionsEndpoint =
|
|
1
|
+
{"version":3,"sources":["../../src/endpoints/getTenantOptionsEndpoint.ts"],"sourcesContent":["import type { Endpoint } from 'payload'\n\nimport { APIError } from 'payload'\n\nimport type { MultiTenantPluginConfig } from '../types.js'\n\nimport { getTenantOptions } from '../utilities/getTenantOptions.js'\n\nexport const getTenantOptionsEndpoint = ({\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n useAsTitle,\n userHasAccessToAllTenants,\n}: {\n tenantsArrayFieldName: string\n tenantsArrayTenantFieldName: string\n tenantsCollectionSlug: string\n useAsTitle: string\n userHasAccessToAllTenants: Required<MultiTenantPluginConfig>['userHasAccessToAllTenants']\n}): Endpoint => ({\n handler: async (req) => {\n const { payload, user } = req\n\n if (!user) {\n throw new APIError('Unauthorized', 401)\n }\n\n const tenantOptions = await getTenantOptions({\n payload,\n tenantsArrayFieldName,\n tenantsArrayTenantFieldName,\n tenantsCollectionSlug,\n useAsTitle,\n user,\n userHasAccessToAllTenants,\n })\n\n return new Response(JSON.stringify({ tenantOptions }))\n },\n method: 'get',\n path: '/populate-tenant-options',\n})\n"],"names":["APIError","getTenantOptions","getTenantOptionsEndpoint","tenantsArrayFieldName","tenantsArrayTenantFieldName","tenantsCollectionSlug","useAsTitle","userHasAccessToAllTenants","handler","req","payload","user","tenantOptions","Response","JSON","stringify","method","path"],"mappings":"AAEA,SAASA,QAAQ,QAAQ,UAAS;AAIlC,SAASC,gBAAgB,QAAQ,mCAAkC;AAEnE,OAAO,MAAMC,2BAA2B,CAAC,EACvCC,qBAAqB,EACrBC,2BAA2B,EAC3BC,qBAAqB,EACrBC,UAAU,EACVC,yBAAyB,EAO1B,GAAgB,CAAA;QACfC,SAAS,OAAOC;YACd,MAAM,EAAEC,OAAO,EAAEC,IAAI,EAAE,GAAGF;YAE1B,IAAI,CAACE,MAAM;gBACT,MAAM,IAAIX,SAAS,gBAAgB;YACrC;YAEA,MAAMY,gBAAgB,MAAMX,iBAAiB;gBAC3CS;gBACAP;gBACAC;gBACAC;gBACAC;gBACAK;gBACAJ;YACF;YAEA,OAAO,IAAIM,SAASC,KAAKC,SAAS,CAAC;gBAAEH;YAAc;QACrD;QACAI,QAAQ;QACRC,MAAM;IACR,CAAA,EAAE"}
|
|
@@ -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,
|
|
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,uBAiGT,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/fields/tenantsArrayField/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAI5D,KAAK,IAAI,GAAG;IACV;;OAEG;IACH,gBAAgB,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;IACvC;;OAEG;IACH,SAAS,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;IAChC;;OAEG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAA;IAC/C;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAA;IAC1C;;;;OAIG;IACH,2BAA2B,CAAC,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAA;IACvD;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAC/B,CAAA;AACD,eAAO,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/fields/tenantsArrayField/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAI5D,KAAK,IAAI,GAAG;IACV;;OAEG;IACH,gBAAgB,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;IACvC;;OAEG;IACH,SAAS,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;IAChC;;OAEG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAA;IAC/C;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAA;IAC1C;;;;OAIG;IACH,2BAA2B,CAAC,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAA;IACvD;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAC/B,CAAA;AACD,eAAO,MAAM,iBAAiB,mIAO3B,IAAI,KAAG,UAiBR,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { PayloadRequest, Where } from 'payload';
|
|
2
2
|
import type { MultiTenantPluginConfig } from '../types.js';
|
|
3
|
-
type Args
|
|
3
|
+
type Args = {
|
|
4
4
|
/**
|
|
5
5
|
* If the document this filter is run belongs to a tenant, the tenant ID should be passed here.
|
|
6
6
|
* If set, this will be used instead of the tenant cookie
|
|
@@ -12,8 +12,8 @@ type Args<ConfigType = unknown> = {
|
|
|
12
12
|
tenantsArrayFieldName?: string;
|
|
13
13
|
tenantsArrayTenantFieldName?: string;
|
|
14
14
|
tenantsCollectionSlug: string;
|
|
15
|
-
userHasAccessToAllTenants: Required<MultiTenantPluginConfig
|
|
15
|
+
userHasAccessToAllTenants: Required<MultiTenantPluginConfig>['userHasAccessToAllTenants'];
|
|
16
16
|
};
|
|
17
|
-
export declare const filterDocumentsByTenants:
|
|
17
|
+
export declare const filterDocumentsByTenants: ({ docTenantID, filterFieldName, req, tenantsArrayFieldName, tenantsArrayTenantFieldName, tenantsCollectionSlug, userHasAccessToAllTenants, }: Args) => null | Where;
|
|
18
18
|
export {};
|
|
19
19
|
//# sourceMappingURL=filterDocumentsByTenants.d.ts.map
|
|
@@ -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"}
|
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;AAczD,eAAO,MAAM,iBAAiB,gEA+a5B,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';
|
|
@@ -10,7 +11,9 @@ import { addCollectionAccess } from './utilities/addCollectionAccess.js';
|
|
|
10
11
|
import { addFilterOptionsToFields } from './utilities/addFilterOptionsToFields.js';
|
|
11
12
|
import { combineFilters } from './utilities/combineFilters.js';
|
|
12
13
|
import { miniChalk } from './utilities/miniChalk.js';
|
|
13
|
-
export const multiTenantPlugin = (
|
|
14
|
+
export const multiTenantPlugin = definePlugin({
|
|
15
|
+
slug: '@payloadcms/plugin-multi-tenant',
|
|
16
|
+
plugin: ({ config: incomingConfig, options: pluginConfig })=>{
|
|
14
17
|
if (pluginConfig.enabled === false) {
|
|
15
18
|
return incomingConfig;
|
|
16
19
|
}
|
|
@@ -21,6 +24,7 @@ export const multiTenantPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
21
24
|
const tenantFieldName = pluginConfig?.tenantField?.name || defaults.tenantFieldName;
|
|
22
25
|
const tenantsArrayFieldName = pluginConfig?.tenantsArrayField?.arrayFieldName || defaults.tenantsArrayFieldName;
|
|
23
26
|
const tenantsArrayTenantFieldName = pluginConfig?.tenantsArrayField?.arrayTenantFieldName || defaults.tenantsArrayTenantFieldName;
|
|
27
|
+
const tenantAccessScopes = [];
|
|
24
28
|
/**
|
|
25
29
|
* Add defaults for admin properties
|
|
26
30
|
*/ if (!incomingConfig.admin) {
|
|
@@ -62,12 +66,17 @@ export const multiTenantPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
62
66
|
*/ if (pluginConfig?.tenantsArrayField?.includeDefaultField !== false) {
|
|
63
67
|
adminUsersCollection.fields.push(tenantsArrayField({
|
|
64
68
|
...pluginConfig?.tenantsArrayField || {},
|
|
69
|
+
arrayFieldAccess: {
|
|
70
|
+
create: ({ req })=>Boolean(req.user && userHasAccessToAllTenants(req.user)),
|
|
71
|
+
update: ({ req })=>Boolean(req.user && userHasAccessToAllTenants(req.user)),
|
|
72
|
+
...pluginConfig?.tenantsArrayField?.arrayFieldAccess || {}
|
|
73
|
+
},
|
|
65
74
|
tenantsArrayFieldName,
|
|
66
75
|
tenantsArrayTenantFieldName,
|
|
67
76
|
tenantsCollectionSlug
|
|
68
77
|
}));
|
|
69
78
|
}
|
|
70
|
-
|
|
79
|
+
tenantAccessScopes.push({
|
|
71
80
|
accessResultCallback: pluginConfig.usersAccessResultOverride,
|
|
72
81
|
adminUsersSlug: adminUsersCollection.slug,
|
|
73
82
|
collection: adminUsersCollection,
|
|
@@ -123,7 +132,7 @@ export const multiTenantPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
123
132
|
/**
|
|
124
133
|
* Add access control constraint to tenants collection
|
|
125
134
|
* - constrains access a users assigned tenants
|
|
126
|
-
*/
|
|
135
|
+
*/ tenantAccessScopes.push({
|
|
127
136
|
adminUsersSlug: adminUsersCollection.slug,
|
|
128
137
|
collection,
|
|
129
138
|
fieldName: 'id',
|
|
@@ -266,7 +275,7 @@ export const multiTenantPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
266
275
|
if (pluginConfig.collections[collection.slug]?.useTenantAccess !== false) {
|
|
267
276
|
/**
|
|
268
277
|
* Add access control constraint to tenant enabled collection
|
|
269
|
-
*/
|
|
278
|
+
*/ tenantAccessScopes.push({
|
|
270
279
|
accessResultCallback: pluginConfig.collections[collection.slug]?.accessResultOverride,
|
|
271
280
|
adminUsersSlug: adminUsersCollection.slug,
|
|
272
281
|
collection,
|
|
@@ -289,6 +298,10 @@ export const multiTenantPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
289
298
|
// eslint-disable-next-line no-console
|
|
290
299
|
console.error(miniChalk.yellowBold('WARNING (plugin-multi-tenant)'), 'missing collections', missingSlugs, 'try placing the multi-tenant plugin after other plugins.');
|
|
291
300
|
}
|
|
301
|
+
addCollectionAccess({
|
|
302
|
+
config: incomingConfig,
|
|
303
|
+
scopes: tenantAccessScopes
|
|
304
|
+
});
|
|
292
305
|
/**
|
|
293
306
|
* Add TenantSelectionProvider to admin providers
|
|
294
307
|
*/ incomingConfig.admin.components.providers.push({
|
|
@@ -355,6 +368,7 @@ export const multiTenantPlugin = (pluginConfig)=>(incomingConfig)=>{
|
|
|
355
368
|
};
|
|
356
369
|
});
|
|
357
370
|
return incomingConfig;
|
|
358
|
-
}
|
|
371
|
+
}
|
|
372
|
+
});
|
|
359
373
|
|
|
360
374
|
//# 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 { 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 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 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","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","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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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { multiTenantPlugin } from './index.js';
|
|
3
|
+
describe('multiTenantPlugin', ()=>{
|
|
4
|
+
it('applies tenant assignment access defaults', async ()=>{
|
|
5
|
+
let hasAllTenantAccess = false;
|
|
6
|
+
const plugin = multiTenantPlugin({
|
|
7
|
+
collections: {},
|
|
8
|
+
userHasAccessToAllTenants: ()=>hasAllTenantAccess
|
|
9
|
+
});
|
|
10
|
+
const config = await plugin({
|
|
11
|
+
collections: [
|
|
12
|
+
{
|
|
13
|
+
slug: 'users',
|
|
14
|
+
auth: true,
|
|
15
|
+
fields: []
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
slug: 'tenants',
|
|
19
|
+
fields: []
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
});
|
|
23
|
+
const usersCollection = config.collections?.find(({ slug })=>slug === 'users');
|
|
24
|
+
const tenantsField = usersCollection?.fields.find((field)=>'name' in field && field.name === 'tenants');
|
|
25
|
+
const accessArgs = {
|
|
26
|
+
req: {
|
|
27
|
+
user: {
|
|
28
|
+
id: 'test-user'
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
expect(await tenantsField?.access?.create?.(accessArgs)).toBe(false);
|
|
33
|
+
expect(await tenantsField?.access?.update?.(accessArgs)).toBe(false);
|
|
34
|
+
hasAllTenantAccess = true;
|
|
35
|
+
expect(await tenantsField?.access?.create?.(accessArgs)).toBe(true);
|
|
36
|
+
expect(await tenantsField?.access?.update?.(accessArgs)).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
it('retains configured tenant assignment access callbacks', async ()=>{
|
|
39
|
+
const createAccess = ()=>false;
|
|
40
|
+
const updateAccess = ()=>true;
|
|
41
|
+
const plugin = multiTenantPlugin({
|
|
42
|
+
collections: {},
|
|
43
|
+
tenantsArrayField: {
|
|
44
|
+
arrayFieldAccess: {
|
|
45
|
+
create: createAccess,
|
|
46
|
+
update: updateAccess
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
const config = await plugin({
|
|
51
|
+
collections: [
|
|
52
|
+
{
|
|
53
|
+
slug: 'users',
|
|
54
|
+
auth: true,
|
|
55
|
+
fields: []
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
slug: 'tenants',
|
|
59
|
+
fields: []
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
});
|
|
63
|
+
const usersCollection = config.collections?.find(({ slug })=>slug === 'users');
|
|
64
|
+
const tenantsField = usersCollection?.fields.find((field)=>'name' in field && field.name === 'tenants');
|
|
65
|
+
expect(tenantsField?.access?.create).toBe(createAccess);
|
|
66
|
+
expect(tenantsField?.access?.update).toBe(updateAccess);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
//# sourceMappingURL=index.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.spec.ts"],"sourcesContent":["import type { ArrayField, Config } from 'payload'\n\nimport { describe, expect, it } from 'vitest'\n\nimport { multiTenantPlugin } from './index.js'\n\ndescribe('multiTenantPlugin', () => {\n it('applies tenant assignment access defaults', async () => {\n let hasAllTenantAccess = false\n const plugin = multiTenantPlugin({\n collections: {},\n userHasAccessToAllTenants: () => hasAllTenantAccess,\n })\n const config = await plugin({\n collections: [\n { slug: 'users', auth: true, fields: [] },\n { slug: 'tenants', fields: [] },\n ],\n } as Config)\n const usersCollection = config.collections?.find(({ slug }) => slug === 'users')\n const tenantsField = usersCollection?.fields.find(\n (field): field is ArrayField => 'name' in field && field.name === 'tenants',\n )\n const accessArgs = { req: { user: { id: 'test-user' } } } as never\n\n expect(await tenantsField?.access?.create?.(accessArgs)).toBe(false)\n expect(await tenantsField?.access?.update?.(accessArgs)).toBe(false)\n\n hasAllTenantAccess = true\n\n expect(await tenantsField?.access?.create?.(accessArgs)).toBe(true)\n expect(await tenantsField?.access?.update?.(accessArgs)).toBe(true)\n })\n\n it('retains configured tenant assignment access callbacks', async () => {\n const createAccess = () => false\n const updateAccess = () => true\n const plugin = multiTenantPlugin({\n collections: {},\n tenantsArrayField: {\n arrayFieldAccess: {\n create: createAccess,\n update: updateAccess,\n },\n },\n })\n const config = await plugin({\n collections: [\n { slug: 'users', auth: true, fields: [] },\n { slug: 'tenants', fields: [] },\n ],\n } as Config)\n const usersCollection = config.collections?.find(({ slug }) => slug === 'users')\n const tenantsField = usersCollection?.fields.find(\n (field): field is ArrayField => 'name' in field && field.name === 'tenants',\n )\n\n expect(tenantsField?.access?.create).toBe(createAccess)\n expect(tenantsField?.access?.update).toBe(updateAccess)\n })\n})\n"],"names":["describe","expect","it","multiTenantPlugin","hasAllTenantAccess","plugin","collections","userHasAccessToAllTenants","config","slug","auth","fields","usersCollection","find","tenantsField","field","name","accessArgs","req","user","id","access","create","toBe","update","createAccess","updateAccess","tenantsArrayField","arrayFieldAccess"],"mappings":"AAEA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAE7C,SAASC,iBAAiB,QAAQ,aAAY;AAE9CH,SAAS,qBAAqB;IAC5BE,GAAG,6CAA6C;QAC9C,IAAIE,qBAAqB;QACzB,MAAMC,SAASF,kBAAkB;YAC/BG,aAAa,CAAC;YACdC,2BAA2B,IAAMH;QACnC;QACA,MAAMI,SAAS,MAAMH,OAAO;YAC1BC,aAAa;gBACX;oBAAEG,MAAM;oBAASC,MAAM;oBAAMC,QAAQ,EAAE;gBAAC;gBACxC;oBAAEF,MAAM;oBAAWE,QAAQ,EAAE;gBAAC;aAC/B;QACH;QACA,MAAMC,kBAAkBJ,OAAOF,WAAW,EAAEO,KAAK,CAAC,EAAEJ,IAAI,EAAE,GAAKA,SAAS;QACxE,MAAMK,eAAeF,iBAAiBD,OAAOE,KAC3C,CAACE,QAA+B,UAAUA,SAASA,MAAMC,IAAI,KAAK;QAEpE,MAAMC,aAAa;YAAEC,KAAK;gBAAEC,MAAM;oBAAEC,IAAI;gBAAY;YAAE;QAAE;QAExDnB,OAAO,MAAMa,cAAcO,QAAQC,SAASL,aAAaM,IAAI,CAAC;QAC9DtB,OAAO,MAAMa,cAAcO,QAAQG,SAASP,aAAaM,IAAI,CAAC;QAE9DnB,qBAAqB;QAErBH,OAAO,MAAMa,cAAcO,QAAQC,SAASL,aAAaM,IAAI,CAAC;QAC9DtB,OAAO,MAAMa,cAAcO,QAAQG,SAASP,aAAaM,IAAI,CAAC;IAChE;IAEArB,GAAG,yDAAyD;QAC1D,MAAMuB,eAAe,IAAM;QAC3B,MAAMC,eAAe,IAAM;QAC3B,MAAMrB,SAASF,kBAAkB;YAC/BG,aAAa,CAAC;YACdqB,mBAAmB;gBACjBC,kBAAkB;oBAChBN,QAAQG;oBACRD,QAAQE;gBACV;YACF;QACF;QACA,MAAMlB,SAAS,MAAMH,OAAO;YAC1BC,aAAa;gBACX;oBAAEG,MAAM;oBAASC,MAAM;oBAAMC,QAAQ,EAAE;gBAAC;gBACxC;oBAAEF,MAAM;oBAAWE,QAAQ,EAAE;gBAAC;aAC/B;QACH;QACA,MAAMC,kBAAkBJ,OAAOF,WAAW,EAAEO,KAAK,CAAC,EAAEJ,IAAI,EAAE,GAAKA,SAAS;QACxE,MAAMK,eAAeF,iBAAiBD,OAAOE,KAC3C,CAACE,QAA+B,UAAUA,SAASA,MAAMC,IAAI,KAAK;QAGpEf,OAAOa,cAAcO,QAAQC,QAAQC,IAAI,CAACE;QAC1CxB,OAAOa,cAAcO,QAAQG,QAAQD,IAAI,CAACG;IAC5C;AACF"}
|
|
@@ -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;AAI5C,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,
|
|
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;AAI5C,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,sBAiOA,CAAA;AAED,eAAO,MAAM,kBAAkB,mBAA2B,CAAA"}
|
|
@@ -197,13 +197,43 @@ export const TenantSelectionProviderClient = ({ children, initialTenantOptions,
|
|
|
197
197
|
router
|
|
198
198
|
]);
|
|
199
199
|
/**
|
|
200
|
+
* Populate tenant options when the provider mounts already-authenticated but
|
|
201
|
+
* without server-provided options. This happens when a provider setup remounts
|
|
202
|
+
* this subtree on login (see `config.conditionalProvider`): the remounted
|
|
203
|
+
* instance initializes `prevUserID` to the current user, so `userChanged` above
|
|
204
|
+
* is `false` and never fires `syncTenants`, while the server still rendered the
|
|
205
|
+
* logged-out tree so `initialTenantOptions` is empty — leaving the selector
|
|
206
|
+
* unrendered. Unlike `router.refresh()`, `syncTenants()` is a plain client fetch
|
|
207
|
+
* that cannot trigger a remount loop, so this is safe on every framework adapter.
|
|
208
|
+
*/ const didInitialSync = React.useRef(false);
|
|
209
|
+
React.useEffect(()=>{
|
|
210
|
+
if (!didInitialSync.current && !userChanged && userID && tenantOptions.length === 0 && initialTenantOptions.length === 0) {
|
|
211
|
+
didInitialSync.current = true;
|
|
212
|
+
void syncTenants();
|
|
213
|
+
}
|
|
214
|
+
}, [
|
|
215
|
+
userChanged,
|
|
216
|
+
userID,
|
|
217
|
+
tenantOptions.length,
|
|
218
|
+
initialTenantOptions,
|
|
219
|
+
syncTenants
|
|
220
|
+
]);
|
|
221
|
+
/**
|
|
200
222
|
* If there is no initial value, clear the tenant and refresh the router.
|
|
201
223
|
* Needed for stale tenantIDs set as a cookie.
|
|
224
|
+
*
|
|
225
|
+
* Only refresh when there is actually a stale cookie to clear: when no cookie
|
|
226
|
+
* is present the server already rendered tenant-less, so a refresh is
|
|
227
|
+
* redundant. This also avoids an infinite loop on framework adapters whose
|
|
228
|
+
* `router.refresh()` remounts this provider (e.g. TanStack Start) — an
|
|
229
|
+
* unconditional refresh would re-fire this mount effect and refresh again,
|
|
230
|
+
* whereas guarding on the (persistent) cookie self-terminates after the one
|
|
231
|
+
* refresh that clears it. The cookie is cleared either way via `setTenant`.
|
|
202
232
|
*/ React.useEffect(()=>{
|
|
203
233
|
if (!initialValue) {
|
|
204
234
|
setTenant({
|
|
205
235
|
id: undefined,
|
|
206
|
-
refresh:
|
|
236
|
+
refresh: Boolean(getTenantCookie())
|
|
207
237
|
});
|
|
208
238
|
}
|
|
209
239
|
}, [
|