diff --git a/apps/remix/app/components/general/billing-plans.tsx b/apps/remix/app/components/general/billing-plans.tsx index 538471b49..1de96f1d0 100644 --- a/apps/remix/app/components/general/billing-plans.tsx +++ b/apps/remix/app/components/general/billing-plans.tsx @@ -54,7 +54,6 @@ export const BillingPlans = ({ plans }: BillingPlansProps) => { if (plan[interval] && plan[interval].isVisibleInApp) { prices.push({ ...plan[interval], - memberCount: plan.memberCount, claim: plan.id, }); } @@ -120,12 +119,7 @@ export const BillingPlans = ({ plans }: BillingPlansProps) => { Subscribe ) : ( - + )} @@ -136,16 +130,7 @@ export const BillingPlans = ({ plans }: BillingPlansProps) => { ); }; -const BillingDialog = ({ - priceId, - planName, - claim, -}: { - priceId: string; - planName: string; - memberCount: number; - claim: string; -}) => { +const BillingDialog = ({ priceId, planName, claim }: { priceId: string; planName: string; claim: string }) => { const [isOpen, setIsOpen] = useState(false); const { t } = useLingui(); diff --git a/packages/ee/server-only/stripe/webhook/on-subscription-created.ts b/packages/ee/server-only/stripe/webhook/on-subscription-created.ts index 242471481..655bdbbf8 100644 --- a/packages/ee/server-only/stripe/webhook/on-subscription-created.ts +++ b/packages/ee/server-only/stripe/webhook/on-subscription-created.ts @@ -3,10 +3,10 @@ import { createOrganisationClaimUpsertData, } from '@documenso/lib/server-only/organisation/create-organisation'; import type { Stripe } from '@documenso/lib/server-only/stripe'; -import type { InternalClaim, StripeOrganisationCreateMetadata } from '@documenso/lib/types/subscription'; +import type { StripeOrganisationCreateMetadata } from '@documenso/lib/types/subscription'; import { INTERNAL_CLAIM_ID, ZStripeOrganisationCreateMetadataSchema } from '@documenso/lib/types/subscription'; import { prisma } from '@documenso/prisma'; -import { OrganisationType, SubscriptionStatus } from '@prisma/client'; +import { OrganisationType, type SubscriptionClaim, SubscriptionStatus } from '@prisma/client'; import { match } from 'ts-pattern'; import { extractStripeClaim } from './on-subscription-updated'; @@ -108,7 +108,7 @@ export const onSubscriptionCreated = async ({ subscription }: OnSubscriptionCrea type HandleOrganisationCreateOptions = { customerId: string; - claim: InternalClaim; + claim: Omit; unknownCreateData: string; }; @@ -147,7 +147,7 @@ const handleOrganisationCreate = async ({ customerId, claim, unknownCreateData } type HandleOrganisationUpdateOptions = { customerId: string; - claim: InternalClaim; + claim: Omit; }; /** diff --git a/packages/lib/jobs/definitions/emails/send-document-cancelled-emails.handler.ts b/packages/lib/jobs/definitions/emails/send-document-cancelled-emails.handler.ts index 1a2f5539a..bca54f651 100644 --- a/packages/lib/jobs/definitions/emails/send-document-cancelled-emails.handler.ts +++ b/packages/lib/jobs/definitions/emails/send-document-cancelled-emails.handler.ts @@ -48,7 +48,7 @@ export const run = async ({ payload, io }: { payload: TSendDocumentCancelledEmai }, }); - const { branding, emailLanguage, senderEmail, replyToEmail, isOrganisationOwnerDisabled, organisationId, claims } = + const { branding, emailLanguage, senderEmail, replyToEmail, organisationId, claims, emailsDisabled } = await getEmailContext({ emailType: 'RECIPIENT', source: { @@ -60,8 +60,8 @@ export const run = async ({ payload, io }: { payload: TSendDocumentCancelledEmai const { documentMeta, user: documentOwner } = envelope; - // Don't send cancellation emails on behalf of a disabled (e.g. banned) account. - if (isOrganisationOwnerDisabled || documentOwner.disabled) { + // Don't send cancellation emails if the organisation has email sending disabled or the owner is disabled (e.g. banned). + if (emailsDisabled || documentOwner.disabled) { return; } diff --git a/packages/lib/jobs/definitions/emails/send-document-completed-emails.handler.ts b/packages/lib/jobs/definitions/emails/send-document-completed-emails.handler.ts index b0e5624ba..79c6d2707 100644 --- a/packages/lib/jobs/definitions/emails/send-document-completed-emails.handler.ts +++ b/packages/lib/jobs/definitions/emails/send-document-completed-emails.handler.ts @@ -67,7 +67,7 @@ export const run = async ({ payload, io }: { payload: TSendDocumentCompletedEmai throw new Error('Document has no recipients'); } - const { branding, emailLanguage, senderEmail, replyToEmail, isOrganisationOwnerDisabled, organisationId, claims } = + const { branding, emailLanguage, senderEmail, replyToEmail, organisationId, claims, emailsDisabled } = await getEmailContext({ emailType: 'RECIPIENT', source: { @@ -77,8 +77,8 @@ export const run = async ({ payload, io }: { payload: TSendDocumentCompletedEmai meta: envelope.documentMeta, }); - // Don't send completion emails on behalf of a disabled (e.g. banned) account. - if (envelope.user.disabled || isOrganisationOwnerDisabled) { + // Don't send completion emails if the organisation has email sending disabled or the owner is disabled (e.g. banned). + if (envelope.user.disabled || emailsDisabled) { return; } diff --git a/packages/lib/jobs/definitions/emails/send-owner-recipient-expired-email.handler.ts b/packages/lib/jobs/definitions/emails/send-owner-recipient-expired-email.handler.ts index 02bade62c..847278eb1 100644 --- a/packages/lib/jobs/definitions/emails/send-owner-recipient-expired-email.handler.ts +++ b/packages/lib/jobs/definitions/emails/send-owner-recipient-expired-email.handler.ts @@ -62,7 +62,7 @@ export const run = async ({ payload, io }: { payload: TSendOwnerRecipientExpired return; } - const { branding, emailLanguage, senderEmail } = await getEmailContext({ + const { branding, emailLanguage, senderEmail, emailsDisabled } = await getEmailContext({ emailType: 'RECIPIENT', source: { type: 'team', @@ -71,6 +71,11 @@ export const run = async ({ payload, io }: { payload: TSendOwnerRecipientExpired meta: documentMeta, }); + // Don't send any emails if the organisation has email sending disabled. + if (emailsDisabled) { + return; + } + const i18n = await getI18nInstance(emailLanguage); const documentLink = `${NEXT_PUBLIC_WEBAPP_URL()}${formatDocumentsPath(envelope.team.url)}/${envelope.id}`; diff --git a/packages/lib/jobs/definitions/emails/send-rejection-emails.handler.ts b/packages/lib/jobs/definitions/emails/send-rejection-emails.handler.ts index 93519fb91..ef3b1d5c1 100644 --- a/packages/lib/jobs/definitions/emails/send-rejection-emails.handler.ts +++ b/packages/lib/jobs/definitions/emails/send-rejection-emails.handler.ts @@ -64,7 +64,7 @@ export const run = async ({ payload, io }: { payload: TSendSigningRejectionEmail return; } - const { branding, emailLanguage, senderEmail, replyToEmail } = await getEmailContext({ + const { branding, emailLanguage, senderEmail, replyToEmail, emailsDisabled } = await getEmailContext({ emailType: 'RECIPIENT', source: { type: 'team', @@ -75,8 +75,10 @@ export const run = async ({ payload, io }: { payload: TSendSigningRejectionEmail const i18n = await getI18nInstance(emailLanguage); - // Send confirmation email to the recipient who rejected - if (isRecipientEmailValidForSending(recipient)) { + // Send confirmation email to the recipient who rejected. + // Skipped when the organisation has email sending disabled, since this is sent on its behalf. + // The owner notification below intentionally uses the internal Documenso email, so it still sends. + if (!emailsDisabled && isRecipientEmailValidForSending(recipient)) { await io.runTask('send-rejection-confirmation-email', async () => { const recipientTemplate = createElement(DocumentRejectionConfirmedEmail, { recipientName: recipient.name, diff --git a/packages/lib/jobs/definitions/emails/send-signing-email.handler.ts b/packages/lib/jobs/definitions/emails/send-signing-email.handler.ts index a3156b7d5..9cb34a9ca 100644 --- a/packages/lib/jobs/definitions/emails/send-signing-email.handler.ts +++ b/packages/lib/jobs/definitions/emails/send-signing-email.handler.ts @@ -99,7 +99,7 @@ export const run = async ({ payload, io }: { payload: TSendSigningEmailJobDefini replyToEmail, organisationId, claims, - isOrganisationOwnerDisabled, + emailsDisabled, } = await getEmailContext({ emailType: 'RECIPIENT', source: { @@ -109,8 +109,8 @@ export const run = async ({ payload, io }: { payload: TSendSigningEmailJobDefini meta: envelope.documentMeta, }); - // Don't send signing invitations on behalf of a disabled (e.g. banned) account. - if (envelope.user.disabled || isOrganisationOwnerDisabled) { + // Don't send signing invitations if the organisation has email sending disabled or the owner is disabled (e.g. banned). + if (envelope.user.disabled || emailsDisabled) { return; } diff --git a/packages/lib/jobs/definitions/internal/backport-subscription-claims.ts b/packages/lib/jobs/definitions/internal/backport-subscription-claims.ts index 8c504a1fc..cbf69c374 100644 --- a/packages/lib/jobs/definitions/internal/backport-subscription-claims.ts +++ b/packages/lib/jobs/definitions/internal/backport-subscription-claims.ts @@ -20,6 +20,7 @@ const BACKPORT_SUBSCRIPTION_CLAIM_JOB_DEFINITION_SCHEMA = z.object({ cfr21: z.literal(true).optional(), hipaa: z.literal(true).optional(), signingReminders: z.literal(true).optional(), + disableEmails: z.literal(true).optional(), // Todo: Envelopes - Do we need to check? // authenticationPortal & emailDomains missing here. }), diff --git a/packages/lib/jobs/definitions/internal/process-signing-reminder.handler.ts b/packages/lib/jobs/definitions/internal/process-signing-reminder.handler.ts index b755de015..0646c5c3b 100644 --- a/packages/lib/jobs/definitions/internal/process-signing-reminder.handler.ts +++ b/packages/lib/jobs/definitions/internal/process-signing-reminder.handler.ts @@ -108,9 +108,9 @@ export const run = async ({ payload, io }: { payload: TProcessSigningReminderJob organisationType, senderEmail, replyToEmail, - isOrganisationOwnerDisabled, organisationId, claims, + emailsDisabled, } = await getEmailContext({ emailType: 'RECIPIENT', source: { @@ -120,9 +120,10 @@ export const run = async ({ payload, io }: { payload: TProcessSigningReminderJob meta: envelope.documentMeta, }); - // Don't send reminders on behalf of a disabled (e.g. banned) account. - if (envelope.user.disabled || isOrganisationOwnerDisabled) { - io.logger.info(`Envelope ${envelope.id} owner is disabled, skipping reminder`); + // Don't send reminders if the owner is disabled (e.g. banned) or the organisation + // has email sending disabled. + if (envelope.user.disabled || emailsDisabled) { + io.logger.info(`Envelope ${envelope.id} skipping reminder: owner disabled or organisation emails disabled`); return; } diff --git a/packages/lib/server-only/document/delete-document.ts b/packages/lib/server-only/document/delete-document.ts index 8011408fe..8a344c774 100644 --- a/packages/lib/server-only/document/delete-document.ts +++ b/packages/lib/server-only/document/delete-document.ts @@ -126,7 +126,7 @@ const handleDocumentOwnerDelete = async ({ envelope, user, requestMetadata }: Ha return; } - const { branding, emailLanguage, senderEmail, replyToEmail } = await getEmailContext({ + const { branding, emailLanguage, senderEmail, replyToEmail, emailsDisabled } = await getEmailContext({ emailType: 'RECIPIENT', source: { type: 'team', @@ -187,7 +187,9 @@ const handleDocumentOwnerDelete = async ({ envelope, user, requestMetadata }: Ha const isEnvelopeDeleteEmailEnabled = extractDerivedDocumentEmailSettings(envelope.documentMeta).documentDeleted; - if (!isEnvelopeDeleteEmailEnabled) { + // Skip sending if the email is disabled for this document or the organisation + // has email sending disabled entirely. + if (!isEnvelopeDeleteEmailEnabled || emailsDisabled) { return deletedEnvelope; } diff --git a/packages/lib/server-only/document/resend-document.ts b/packages/lib/server-only/document/resend-document.ts index e0f119bcc..baa060408 100644 --- a/packages/lib/server-only/document/resend-document.ts +++ b/packages/lib/server-only/document/resend-document.ts @@ -151,15 +151,28 @@ export const resendDocument = async ({ id, userId, recipients, teamId, requestMe return envelope; } - const { branding, emailLanguage, organisationType, senderEmail, replyToEmail, organisationId, claims } = - await getEmailContext({ - emailType: 'RECIPIENT', - source: { - type: 'team', - teamId: envelope.teamId, - }, - meta: envelope.documentMeta, - }); + const { + branding, + emailLanguage, + organisationType, + senderEmail, + replyToEmail, + organisationId, + claims, + emailsDisabled, + } = await getEmailContext({ + emailType: 'RECIPIENT', + source: { + type: 'team', + teamId: envelope.teamId, + }, + meta: envelope.documentMeta, + }); + + // Don't resend any emails if the organisation has email sending disabled. + if (user.disabled || emailsDisabled) { + return envelope; + } // Assert that there is enough quota to send the emails. await assertOrganisationRatesAndLimits({ diff --git a/packages/lib/server-only/document/send-pending-email.ts b/packages/lib/server-only/document/send-pending-email.ts index bf42ffdd0..df8550186 100644 --- a/packages/lib/server-only/document/send-pending-email.ts +++ b/packages/lib/server-only/document/send-pending-email.ts @@ -47,7 +47,7 @@ export const sendPendingEmail = async ({ id, recipientId }: SendPendingEmailOpti throw new Error('Document has no recipients'); } - const { branding, emailLanguage, senderEmail, replyToEmail } = await getEmailContext({ + const { branding, emailLanguage, senderEmail, replyToEmail, emailsDisabled } = await getEmailContext({ emailType: 'RECIPIENT', source: { type: 'team', @@ -56,6 +56,11 @@ export const sendPendingEmail = async ({ id, recipientId }: SendPendingEmailOpti meta: envelope.documentMeta, }); + // Don't send any emails if the organisation has email sending disabled. + if (emailsDisabled) { + return; + } + const isDocumentPendingEmailEnabled = extractDerivedDocumentEmailSettings(envelope.documentMeta).documentPending; if (!isDocumentPendingEmailEnabled) { diff --git a/packages/lib/server-only/email/get-email-context.ts b/packages/lib/server-only/email/get-email-context.ts index 86e7ee2d7..7d2182b09 100644 --- a/packages/lib/server-only/email/get-email-context.ts +++ b/packages/lib/server-only/email/get-email-context.ts @@ -66,6 +66,12 @@ export type EmailContextResponse = { branding: BrandingSettings; settings: Omit; claims: OrganisationClaim; + /** + * Whether the organisation is prevented from sending emails. + * + * When true, ALL emails sent on behalf of this organisation must be skipped. + */ + emailsDisabled: boolean; organisationId: string; organisationType: OrganisationType; senderEmail: { @@ -74,7 +80,6 @@ export type EmailContextResponse = { }; replyToEmail: string | undefined; emailLanguage: string; - isOrganisationOwnerDisabled: boolean; }; export const getEmailContext = async (options: GetEmailContextOptions): Promise => { @@ -171,9 +176,9 @@ const handleOrganisationEmailContext = async (organisationId: string) => { ), settings: organisation.organisationGlobalSettings, claims, + emailsDisabled: organisation.owner.disabled || claims.flags.disableEmails === true, organisationId: organisation.id, organisationType: organisation.type, - isOrganisationOwnerDisabled: organisation.owner.disabled, }; }; @@ -223,9 +228,9 @@ const handleTeamEmailContext = async (teamId: number) => { branding: teamGlobalSettingsToBranding(teamSettings, teamId, claims.flags.hidePoweredBy ?? false), settings: teamSettings, claims, + emailsDisabled: organisation.owner.disabled || claims.flags.disableEmails === true, organisationId: organisation.id, organisationType: organisation.type, - isOrganisationOwnerDisabled: organisation.owner.disabled, }; }; diff --git a/packages/lib/server-only/organisation/create-organisation-member-invites.ts b/packages/lib/server-only/organisation/create-organisation-member-invites.ts index ebe0d859d..71e7cc73c 100644 --- a/packages/lib/server-only/organisation/create-organisation-member-invites.ts +++ b/packages/lib/server-only/organisation/create-organisation-member-invites.ts @@ -187,7 +187,7 @@ export const sendOrganisationMemberInviteEmail = async ({ organisationName: organisation.name, }); - const { branding, emailLanguage, senderEmail } = await getEmailContext({ + const { branding, emailLanguage, senderEmail, emailsDisabled } = await getEmailContext({ emailType: 'INTERNAL', source: { type: 'organisation', @@ -195,6 +195,12 @@ export const sendOrganisationMemberInviteEmail = async ({ }, }); + // Member invites can be sent to anyone, so block them when the organisation has email + // sending disabled. + if (emailsDisabled) { + return; + } + const [html, text] = await Promise.all([ renderEmailWithI18N(template, { lang: emailLanguage, diff --git a/packages/lib/server-only/organisation/create-organisation.ts b/packages/lib/server-only/organisation/create-organisation.ts index 04900814c..f77f3e376 100644 --- a/packages/lib/server-only/organisation/create-organisation.ts +++ b/packages/lib/server-only/organisation/create-organisation.ts @@ -6,7 +6,6 @@ import { OrganisationMemberRole, OrganisationType, Prisma, type SubscriptionClai import { IS_BILLING_ENABLED } from '../../constants/app'; import { ORGANISATION_INTERNAL_GROUPS } from '../../constants/organisations'; import { AppError, AppErrorCode } from '../../errors/app-error'; -import type { InternalClaim } from '../../types/subscription'; import { INTERNAL_CLAIM_ID } from '../../types/subscription'; import { generateDatabaseId, prefixedId } from '../../universal/id'; import { generateDefaultOrganisationSettings } from '../../utils/organisations'; @@ -18,7 +17,7 @@ type CreateOrganisationOptions = { type: OrganisationType; url?: string; customerId?: string; - claim: InternalClaim; + claim: Omit; }; export const createOrganisation = async ({ name, url, type, userId, customerId, claim }: CreateOrganisationOptions) => { diff --git a/packages/lib/server-only/recipient/delete-envelope-recipient.ts b/packages/lib/server-only/recipient/delete-envelope-recipient.ts index 0a50086e5..88aa411bc 100644 --- a/packages/lib/server-only/recipient/delete-envelope-recipient.ts +++ b/packages/lib/server-only/recipient/delete-envelope-recipient.ts @@ -152,14 +152,20 @@ export const deleteEnvelopeRecipient = async ({ assetBaseUrl, }); - const { branding, emailLanguage, senderEmail, replyToEmail, organisationId, claims } = await getEmailContext({ - emailType: 'RECIPIENT', - source: { - type: 'team', - teamId: envelope.teamId, - }, - meta: envelope.documentMeta, - }); + const { branding, emailLanguage, senderEmail, replyToEmail, organisationId, claims, emailsDisabled } = + await getEmailContext({ + emailType: 'RECIPIENT', + source: { + type: 'team', + teamId: envelope.teamId, + }, + meta: envelope.documentMeta, + }); + + // Don't send the removal email if the organisation has email sending disabled. + if (emailsDisabled) { + return deletedRecipient; + } // Meter the removal email against the organisation email quota/stats. // Add/remove churn can be used to blast unsolicited removal emails diff --git a/packages/lib/server-only/recipient/set-document-recipients.ts b/packages/lib/server-only/recipient/set-document-recipients.ts index c09827ef5..3f6d4143e 100644 --- a/packages/lib/server-only/recipient/set-document-recipients.ts +++ b/packages/lib/server-only/recipient/set-document-recipients.ts @@ -85,14 +85,15 @@ export const setDocumentRecipients = async ({ throw new Error('Document already complete'); } - const { branding, emailLanguage, senderEmail, replyToEmail, organisationId, claims } = await getEmailContext({ - emailType: 'RECIPIENT', - source: { - type: 'team', - teamId, - }, - meta: envelope.documentMeta, - }); + const { branding, emailLanguage, senderEmail, replyToEmail, organisationId, claims, emailsDisabled } = + await getEmailContext({ + emailType: 'RECIPIENT', + source: { + type: 'team', + teamId, + }, + meta: envelope.documentMeta, + }); const recipientsHaveActionAuth = recipients.some( (recipient) => recipient.actionAuth && recipient.actionAuth.length > 0, @@ -281,6 +282,7 @@ export const setDocumentRecipients = async ({ await Promise.all( removedRecipients.map(async (recipient) => { if ( + emailsDisabled || recipient.sendStatus !== SendStatus.SENT || recipient.role === RecipientRole.CC || !isRecipientRemovedEmailEnabled || diff --git a/packages/lib/server-only/subscription/get-subscription-claim.ts b/packages/lib/server-only/subscription/get-subscription-claim.ts index 694b7be84..a27e3a2f1 100644 --- a/packages/lib/server-only/subscription/get-subscription-claim.ts +++ b/packages/lib/server-only/subscription/get-subscription-claim.ts @@ -1,5 +1,3 @@ -import { INTERNAL_CLAIM_ID, internalClaims } from '@documenso/lib/types/subscription'; - import { prisma } from '@documenso/prisma'; import type { SubscriptionClaim } from '@prisma/client'; import { AppError, AppErrorCode } from '../../errors/app-error'; @@ -12,12 +10,6 @@ export const getSubscriptionClaim = async ( }); if (!subscriptionClaim) { - // Temporary fallback for free claim so we don't break self-hosters who somehow removed it - // from the database. - if (claimId === INTERNAL_CLAIM_ID.FREE) { - return internalClaims[INTERNAL_CLAIM_ID.FREE]; - } - throw new AppError(AppErrorCode.NOT_FOUND, { message: `Subscription claim ${claimId} not found`, }); diff --git a/packages/lib/types/subscription.ts b/packages/lib/types/subscription.ts index d7770fbb3..5cd3878ee 100644 --- a/packages/lib/types/subscription.ts +++ b/packages/lib/types/subscription.ts @@ -51,6 +51,13 @@ export const ZClaimFlagsSchema = z.object({ allowLegacyEnvelopes: z.boolean().optional(), signingReminders: z.boolean().optional(), + + /** + * Controls whether an organisation is prevented from sending emails. + * + * When this is enabled, ALL emails for the organisation are blocked. + */ + disableEmails: z.boolean().optional(), }); export type TClaimFlags = z.infer; @@ -122,6 +129,10 @@ export const SUBSCRIPTION_CLAIM_FEATURE_FLAGS: Record< key: 'signingReminders', label: 'Signing reminders', }, + disableEmails: { + key: 'disableEmails', + label: 'Disable emails', + }, }; export enum INTERNAL_CLAIM_ID { @@ -133,20 +144,12 @@ export enum INTERNAL_CLAIM_ID { ENTERPRISE = 'enterprise', } -export type InternalClaim = Omit; +export type InternalClaim = Pick; export type InternalClaims = { [key in INTERNAL_CLAIM_ID]: InternalClaim; }; -/** - * TODO: THIS NEEDS A REWORK - * - * Only the values within "free" claim (flags, etc) are directly used, the rest are taken - * from the actual SubscriptionClaim in the database. - * - * We need to remove all the content besides id/name and fetch free from the database. - */ export const internalClaims: InternalClaims = { /** * Free plan has no rates and quotas since this may break self-hosters. @@ -154,135 +157,26 @@ export const internalClaims: InternalClaims = { [INTERNAL_CLAIM_ID.FREE]: { id: INTERNAL_CLAIM_ID.FREE, name: 'Free', - teamCount: 1, - memberCount: 1, - envelopeItemCount: 5, - recipientCount: 0, - locked: true, - flags: {}, - documentRateLimits: [], - documentQuota: null, - emailRateLimits: [], - emailQuota: null, - apiRateLimits: [], - apiQuota: null, }, [INTERNAL_CLAIM_ID.INDIVIDUAL]: { id: INTERNAL_CLAIM_ID.INDIVIDUAL, name: 'Individual', - teamCount: 1, - memberCount: 1, - envelopeItemCount: 5, - recipientCount: 0, - locked: true, - flags: { - unlimitedDocuments: true, - signingReminders: true, - }, - documentRateLimits: [], - documentQuota: null, - emailRateLimits: [], - emailQuota: null, - apiRateLimits: [], - apiQuota: null, }, [INTERNAL_CLAIM_ID.TEAM]: { id: INTERNAL_CLAIM_ID.TEAM, name: 'Teams', - teamCount: 1, - memberCount: 5, - envelopeItemCount: 5, - recipientCount: 0, - locked: true, - flags: { - unlimitedDocuments: true, - allowCustomBranding: true, - embedSigning: true, - signingReminders: true, - }, - documentRateLimits: [], - documentQuota: null, - emailRateLimits: [], - emailQuota: null, - apiRateLimits: [], - apiQuota: null, }, [INTERNAL_CLAIM_ID.PLATFORM]: { id: INTERNAL_CLAIM_ID.PLATFORM, name: 'Platform', - teamCount: 1, - memberCount: 0, - envelopeItemCount: 10, - recipientCount: 0, - locked: true, - flags: { - unlimitedDocuments: true, - allowCustomBranding: true, - hidePoweredBy: true, - emailDomains: false, - embedAuthoring: false, - embedAuthoringWhiteLabel: true, - embedSigning: false, - embedSigningWhiteLabel: true, - signingReminders: true, - }, - documentRateLimits: [], - documentQuota: null, - emailRateLimits: [], - emailQuota: null, - apiRateLimits: [], - apiQuota: null, }, [INTERNAL_CLAIM_ID.ENTERPRISE]: { id: INTERNAL_CLAIM_ID.ENTERPRISE, name: 'Enterprise', - teamCount: 0, - memberCount: 0, - envelopeItemCount: 10, - recipientCount: 0, - locked: true, - flags: { - unlimitedDocuments: true, - allowCustomBranding: true, - hidePoweredBy: true, - emailDomains: true, - embedAuthoring: true, - embedAuthoringWhiteLabel: true, - embedSigning: true, - embedSigningWhiteLabel: true, - cfr21: true, - authenticationPortal: true, - signingReminders: true, - }, - documentRateLimits: [], - documentQuota: null, - emailRateLimits: [], - emailQuota: null, - apiRateLimits: [], - apiQuota: null, }, [INTERNAL_CLAIM_ID.EARLY_ADOPTER]: { id: INTERNAL_CLAIM_ID.EARLY_ADOPTER, name: 'Early Adopter', - teamCount: 0, - memberCount: 0, - envelopeItemCount: 5, - recipientCount: 0, - locked: true, - flags: { - unlimitedDocuments: true, - allowCustomBranding: true, - hidePoweredBy: true, - embedSigning: true, - embedSigningWhiteLabel: true, - signingReminders: true, - }, - documentRateLimits: [], - documentQuota: null, - emailRateLimits: [], - emailQuota: null, - apiRateLimits: [], - apiQuota: null, }, } as const;