0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-03-17 22:31:28 -05:00

feat(core): add customJwt paywall guard to core API (#5708)

add customJwt paywall guard to core API
This commit is contained in:
simeng-li 2024-04-16 12:02:08 +08:00 committed by GitHub
parent 49b60af093
commit 43430afddb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
54 changed files with 332 additions and 38 deletions

View file

@ -28,7 +28,7 @@
"@fontsource/roboto-mono": "^5.0.0",
"@jest/types": "^29.5.0",
"@logto/app-insights": "workspace:^1.4.0",
"@logto/cloud": "0.2.5-ab8a489",
"@logto/cloud": "0.2.5-94f7bcc",
"@logto/connector-kit": "workspace:^3.0.0",
"@logto/core-kit": "workspace:^2.4.0",
"@logto/language-kit": "workspace:^1.1.0",

View file

@ -27,6 +27,7 @@ export const quotaItemPhrasesMap: Record<
organizationsEnabled: 'organizations_enabled.name',
ssoEnabled: 'sso_enabled.name',
tenantMembersLimit: 'tenant_members_limit.name',
customJwtEnabled: 'custom_jwt_enabled.name',
};
export const quotaItemUnlimitedPhrasesMap: Record<
@ -54,6 +55,7 @@ export const quotaItemUnlimitedPhrasesMap: Record<
organizationsEnabled: 'organizations_enabled.unlimited',
ssoEnabled: 'sso_enabled.unlimited',
tenantMembersLimit: 'tenant_members_limit.unlimited',
customJwtEnabled: 'custom_jwt_enabled.unlimited',
};
export const quotaItemLimitedPhrasesMap: Record<
@ -81,6 +83,7 @@ export const quotaItemLimitedPhrasesMap: Record<
organizationsEnabled: 'organizations_enabled.limited',
ssoEnabled: 'sso_enabled.limited',
tenantMembersLimit: 'tenant_members_limit.limited',
customJwtEnabled: 'custom_jwt_enabled.limited',
};
export const quotaItemNotEligiblePhrasesMap: Record<
@ -108,4 +111,5 @@ export const quotaItemNotEligiblePhrasesMap: Record<
organizationsEnabled: 'organizations_enabled.not_eligible',
ssoEnabled: 'sso_enabled.not_eligible',
tenantMembersLimit: 'tenant_members_limit.not_eligible',
customJwtEnabled: 'custom_jwt_enabled.not_eligible',
};

View file

@ -1,4 +1,4 @@
import { TenantTag, ReservedPlanId, defaultManagementApi } from '@logto/schemas';
import { ReservedPlanId, TenantTag, defaultManagementApi } from '@logto/schemas';
import dayjs from 'dayjs';
import { type TenantResponse } from '@/cloud/types/router';
@ -67,6 +67,7 @@ export const defaultSubscriptionPlan: SubscriptionPlan = {
ticketSupportResponseTime: 48,
thirdPartyApplicationsLimit: null,
tenantMembersLimit: null,
customJwtEnabled: true,
},
};

View file

@ -1,9 +1,9 @@
import type { Nullable } from '@silverhand/essentials';
import { noop } from '@silverhand/essentials';
import { useState, useRef, useMemo, createContext, useCallback, useEffect } from 'react';
import { createContext, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import ConfirmModal from '@/ds-components/ConfirmModal';
import type { ConfirmModalProps } from '@/ds-components/ConfirmModal';
import ConfirmModal from '@/ds-components/ConfirmModal';
type ModalContentRenderProps = {
confirm: (data?: unknown) => void;
@ -108,13 +108,7 @@ function AppConfirmModalProvider({ children }: Props) {
{children}
<ConfirmModal
{...restProps}
onConfirm={
type === 'confirm'
? () => {
handleConfirm();
}
: undefined
}
onConfirm={type === 'confirm' ? handleConfirm : undefined}
onCancel={() => {
handleCancel();
}}

View file

@ -1,6 +1,11 @@
import { type LogtoJwtTokenKeyType } from '@logto/schemas';
import { useCallback, useContext } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import ContactUsPhraseLink from '@/components/ContactUsPhraseLink';
import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider';
import Button from '@/ds-components/Button';
import { useConfirmModal } from '@/hooks/use-confirm-modal';
import useTenantPathname from '@/hooks/use-tenant-pathname';
import { getPagePath } from '@/pages/CustomizeJwt/utils/path';
@ -11,14 +16,47 @@ type Props = {
function CreateButton({ tokenType }: Props) {
const link = getPagePath(tokenType, 'create');
const { navigate } = useTenantPathname();
const { show } = useConfirmModal();
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const { currentPlan } = useContext(SubscriptionDataContext);
const {
quota: { customJwtEnabled },
} = currentPlan;
const onCreateButtonClick = useCallback(async () => {
if (customJwtEnabled) {
navigate(link);
return;
}
const [confirm] = await show({
title: 'upsell.paywall.custom_jwt.title',
ModalContent: () => (
<Trans
components={{
a: <ContactUsPhraseLink />,
}}
>
{t('upsell.paywall.custom_jwt.description')}
</Trans>
),
confirmButtonText: 'upsell.upgrade_plan',
confirmButtonType: 'primary',
isCancelButtonVisible: false,
});
if (confirm) {
// Navigate to subscription page by default
navigate('/tenant-settings/subscription');
}
}, [customJwtEnabled, link, navigate, show, t]);
return (
<Button
type="primary"
title="jwt_claims.custom_jwt_create_button"
onClick={() => {
navigate(link);
}}
onClick={onCreateButtonClick}
/>
);
}

View file

@ -92,7 +92,7 @@
"zod": "^3.22.4"
},
"devDependencies": {
"@logto/cloud": "0.2.5-749cae5",
"@logto/cloud": "0.2.5-94f7bcc",
"@silverhand/eslint-config": "5.0.0",
"@silverhand/ts-config": "5.0.0",
"@types/debug": "^4.1.7",

View file

@ -1,5 +1,5 @@
import { ConnectorType, DemoConnector } from '@logto/connector-kit';
import { RoleType, ReservedPlanId } from '@logto/schemas';
import { ReservedPlanId, RoleType } from '@logto/schemas';
import { EnvSet } from '#src/env-set/index.js';
import RequestError from '#src/errors/RequestError/index.js';
@ -72,6 +72,7 @@ export const createQuotaLibrary = (
ssoEnabled: notNumber,
omniSignInEnabled: notNumber, // No limit for now
builtInEmailConnectorEnabled: notNumber, // No limit for now
customJwtEnabled: notNumber, // No limit for now
};
const getTenantUsage = async (key: keyof FeatureQuota, queryKey?: string): Promise<number> => {

View file

@ -14,6 +14,7 @@ import { ZodError, z } from 'zod';
import { EnvSet } from '#src/env-set/index.js';
import RequestError, { formatZodError } from '#src/errors/RequestError/index.js';
import koaGuard, { parse } from '#src/middleware/koa-guard.js';
import koaQuotaGuard from '#src/middleware/koa-quota-guard.js';
import type { AuthedRouter, RouterInitArgs } from '../types.js';
@ -31,7 +32,10 @@ const getJwtTokenKeyAndBody = (tokenPath: LogtoJwtTokenKeyType, body: unknown) =
};
export default function logtoConfigJwtCustomizerRoutes<T extends AuthedRouter>(
...[router, { id: tenantId, queries, logtoConfigs, cloudConnection }]: RouterInitArgs<T>
...[
router,
{ id: tenantId, queries, logtoConfigs, cloudConnection, libraries },
]: RouterInitArgs<T>
) {
const { getRowsByKeys, deleteJwtCustomizer } = queries.logtoConfigs;
const {
@ -60,6 +64,7 @@ export default function logtoConfigJwtCustomizerRoutes<T extends AuthedRouter>(
response: accessTokenJwtCustomizerGuard.or(clientCredentialsJwtCustomizerGuard),
status: [200, 201, 400, 403],
}),
koaQuotaGuard({ key: 'customJwtEnabled', quota: libraries.quota }),
async (ctx, next) => {
const { isCloud, isIntegrationTest } = EnvSet.values;
if (tenantId === adminTenantId && isCloud && !isIntegrationTest) {
@ -109,6 +114,7 @@ export default function logtoConfigJwtCustomizerRoutes<T extends AuthedRouter>(
response: accessTokenJwtCustomizerGuard.or(clientCredentialsJwtCustomizerGuard),
status: [200, 400, 404],
}),
koaQuotaGuard({ key: 'customJwtEnabled', quota: libraries.quota }),
async (ctx, next) => {
const { isIntegrationTest } = EnvSet.values;
@ -211,6 +217,7 @@ export default function logtoConfigJwtCustomizerRoutes<T extends AuthedRouter>(
response: jsonObjectGuard,
status: [200, 400, 403, 422],
}),
koaQuotaGuard({ key: 'customJwtEnabled', quota: libraries.quota }),
async (ctx, next) => {
const { body } = ctx.guard;

View file

@ -163,6 +163,16 @@ const quota_item = {
/** UNTRANSLATED */
not_eligible: 'Remove your tenant members',
},
custom_jwt_enabled: {
/** UNTRANSLATED */
name: 'Custom JWT',
/** UNTRANSLATED */
limited: 'Custom JWT',
/** UNTRANSLATED */
unlimited: 'Custom JWT',
/** UNTRANSLATED */
not_eligible: 'Remove your JWT claims customizer',
},
};
export default Object.freeze(quota_item);

View file

@ -15,7 +15,7 @@ const tabs = {
tenant_settings: 'Einstellungen',
mfa: 'Multi-Faktor-Authentifizierung',
/** UNTRANSLATED */
customize_jwt: 'JWT Claims',
customize_jwt: 'Custom JWT',
signing_keys: 'Signierschlüssel',
organization_template: 'Organisationstemplate',
};

View file

@ -64,6 +64,13 @@ const paywall = {
/** UNTRANSLATED */
tenant_members_dev_plan:
"You've reached your {{limit}}-member limit. Release a member or revoke a pending invitation to add someone new. Need more seats? Feel free to contact us.",
custom_jwt: {
/** UNTRANSLATED */
title: 'Add custom claims',
/** UNTRANSLATED */
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
};
export default Object.freeze(paywall);

View file

@ -153,6 +153,12 @@ const quota_item = {
unlimited: 'Unlimited tenant members',
not_eligible: 'Remove your tenant members',
},
custom_jwt_enabled: {
name: 'Custom JWT',
limited: 'Custom JWT',
unlimited: 'Custom JWT',
not_eligible: 'Remove your JWT claims customizer',
},
};
export default Object.freeze(quota_item);

View file

@ -14,7 +14,7 @@ const tabs = {
docs: 'Docs',
tenant_settings: 'Settings',
mfa: 'Multi-factor auth',
customize_jwt: 'JWT Claims',
customize_jwt: 'Custom JWT',
signing_keys: 'Signing keys',
organization_template: 'Organization template',
};

View file

@ -60,6 +60,11 @@ const paywall = {
'Unlock collaboration feature by upgrading to a paid plan. For any assistance, feel free to <a>contact us</a>.',
tenant_members_dev_plan:
"You've reached your {{limit}}-member limit. Release a member or revoke a pending invitation to add someone new. Need more seats? Feel free to contact us.",
custom_jwt: {
title: 'Add custom claims',
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
};
export default Object.freeze(paywall);

View file

@ -163,6 +163,16 @@ const quota_item = {
/** UNTRANSLATED */
not_eligible: 'Remove your tenant members',
},
custom_jwt_enabled: {
/** UNTRANSLATED */
name: 'Custom JWT',
/** UNTRANSLATED */
limited: 'Custom JWT',
/** UNTRANSLATED */
unlimited: 'Custom JWT',
/** UNTRANSLATED */
not_eligible: 'Remove your JWT claims customizer',
},
};
export default Object.freeze(quota_item);

View file

@ -15,7 +15,7 @@ const tabs = {
tenant_settings: 'Configuraciones del inquilino',
mfa: 'Autenticación multifactor',
/** UNTRANSLATED */
customize_jwt: 'JWT Claims',
customize_jwt: 'Custom JWT',
signing_keys: 'Claves de firma',
organization_template: 'Plantilla de organización',
};

View file

@ -64,6 +64,13 @@ const paywall = {
/** UNTRANSLATED */
tenant_members_dev_plan:
"You've reached your {{limit}}-member limit. Release a member or revoke a pending invitation to add someone new. Need more seats? Feel free to contact us.",
custom_jwt: {
/** UNTRANSLATED */
title: 'Add custom claims',
/** UNTRANSLATED */
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
};
export default Object.freeze(paywall);

View file

@ -163,6 +163,16 @@ const quota_item = {
/** UNTRANSLATED */
not_eligible: 'Remove your tenant members',
},
custom_jwt_enabled: {
/** UNTRANSLATED */
name: 'Custom JWT',
/** UNTRANSLATED */
limited: 'Custom JWT',
/** UNTRANSLATED */
unlimited: 'Custom JWT',
/** UNTRANSLATED */
not_eligible: 'Remove your JWT claims customizer',
},
};
export default Object.freeze(quota_item);

View file

@ -15,7 +15,7 @@ const tabs = {
tenant_settings: 'Paramètres du locataire',
mfa: 'Authentification multi-facteur',
/** UNTRANSLATED */
customize_jwt: 'JWT Claims',
customize_jwt: 'Custom JWT',
signing_keys: 'Clés de signature',
organization_template: "Modèle d'organisation",
};

View file

@ -64,6 +64,13 @@ const paywall = {
/** UNTRANSLATED */
tenant_members_dev_plan:
"You've reached your {{limit}}-member limit. Release a member or revoke a pending invitation to add someone new. Need more seats? Feel free to contact us.",
custom_jwt: {
/** UNTRANSLATED */
title: 'Add custom claims',
/** UNTRANSLATED */
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
};
export default Object.freeze(paywall);

View file

@ -163,6 +163,16 @@ const quota_item = {
/** UNTRANSLATED */
not_eligible: 'Remove your tenant members',
},
custom_jwt_enabled: {
/** UNTRANSLATED */
name: 'Custom JWT',
/** UNTRANSLATED */
limited: 'Custom JWT',
/** UNTRANSLATED */
unlimited: 'Custom JWT',
/** UNTRANSLATED */
not_eligible: 'Remove your JWT claims customizer',
},
};
export default Object.freeze(quota_item);

View file

@ -15,7 +15,7 @@ const tabs = {
tenant_settings: 'Impostazioni',
mfa: 'Autenticazione multi-fattore',
/** UNTRANSLATED */
customize_jwt: 'JWT Claims',
customize_jwt: 'Custom JWT',
signing_keys: 'Chiavi di firma',
organization_template: 'Modello di organizzazione',
};

View file

@ -64,6 +64,13 @@ const paywall = {
/** UNTRANSLATED */
tenant_members_dev_plan:
"You've reached your {{limit}}-member limit. Release a member or revoke a pending invitation to add someone new. Need more seats? Feel free to contact us.",
custom_jwt: {
/** UNTRANSLATED */
title: 'Add custom claims',
/** UNTRANSLATED */
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
};
export default Object.freeze(paywall);

View file

@ -163,6 +163,16 @@ const quota_item = {
/** UNTRANSLATED */
not_eligible: 'Remove your tenant members',
},
custom_jwt_enabled: {
/** UNTRANSLATED */
name: 'Custom JWT',
/** UNTRANSLATED */
limited: 'Custom JWT',
/** UNTRANSLATED */
unlimited: 'Custom JWT',
/** UNTRANSLATED */
not_eligible: 'Remove your JWT claims customizer',
},
};
export default Object.freeze(quota_item);

View file

@ -15,7 +15,7 @@ const tabs = {
tenant_settings: '設定',
mfa: 'Multi-factor auth',
/** UNTRANSLATED */
customize_jwt: 'JWT Claims',
customize_jwt: 'Custom JWT',
signing_keys: '署名キー',
organization_template: '組織テンプレート',
};

View file

@ -64,6 +64,13 @@ const paywall = {
/** UNTRANSLATED */
tenant_members_dev_plan:
"You've reached your {{limit}}-member limit. Release a member or revoke a pending invitation to add someone new. Need more seats? Feel free to contact us.",
custom_jwt: {
/** UNTRANSLATED */
title: 'Add custom claims',
/** UNTRANSLATED */
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
};
export default Object.freeze(paywall);

View file

@ -163,6 +163,16 @@ const quota_item = {
/** UNTRANSLATED */
not_eligible: 'Remove your tenant members',
},
custom_jwt_enabled: {
/** UNTRANSLATED */
name: 'Custom JWT',
/** UNTRANSLATED */
limited: 'Custom JWT',
/** UNTRANSLATED */
unlimited: 'Custom JWT',
/** UNTRANSLATED */
not_eligible: 'Remove your JWT claims customizer',
},
};
export default Object.freeze(quota_item);

View file

@ -15,7 +15,7 @@ const tabs = {
tenant_settings: '테넌트 설정',
mfa: '다중 요소 인증',
/** UNTRANSLATED */
customize_jwt: 'JWT Claims',
customize_jwt: 'Custom JWT',
signing_keys: '서명 키',
organization_template: '조직 템플릿',
};

View file

@ -64,6 +64,13 @@ const paywall = {
/** UNTRANSLATED */
tenant_members_dev_plan:
"You've reached your {{limit}}-member limit. Release a member or revoke a pending invitation to add someone new. Need more seats? Feel free to contact us.",
custom_jwt: {
/** UNTRANSLATED */
title: 'Add custom claims',
/** UNTRANSLATED */
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
};
export default Object.freeze(paywall);

View file

@ -163,6 +163,16 @@ const quota_item = {
/** UNTRANSLATED */
not_eligible: 'Remove your tenant members',
},
custom_jwt_enabled: {
/** UNTRANSLATED */
name: 'Custom JWT',
/** UNTRANSLATED */
limited: 'Custom JWT',
/** UNTRANSLATED */
unlimited: 'Custom JWT',
/** UNTRANSLATED */
not_eligible: 'Remove your JWT claims customizer',
},
};
export default Object.freeze(quota_item);

View file

@ -15,7 +15,7 @@ const tabs = {
tenant_settings: 'Ustawienia',
mfa: 'Multi-factor auth',
/** UNTRANSLATED */
customize_jwt: 'JWT Claims',
customize_jwt: 'Custom JWT',
signing_keys: 'Klucze do podpisu',
organization_template: 'Szablon organizacji',
};

View file

@ -64,6 +64,13 @@ const paywall = {
/** UNTRANSLATED */
tenant_members_dev_plan:
"You've reached your {{limit}}-member limit. Release a member or revoke a pending invitation to add someone new. Need more seats? Feel free to contact us.",
custom_jwt: {
/** UNTRANSLATED */
title: 'Add custom claims',
/** UNTRANSLATED */
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
};
export default Object.freeze(paywall);

View file

@ -163,6 +163,16 @@ const quota_item = {
/** UNTRANSLATED */
not_eligible: 'Remove your tenant members',
},
custom_jwt_enabled: {
/** UNTRANSLATED */
name: 'Custom JWT',
/** UNTRANSLATED */
limited: 'Custom JWT',
/** UNTRANSLATED */
unlimited: 'Custom JWT',
/** UNTRANSLATED */
not_eligible: 'Remove your JWT claims customizer',
},
};
export default Object.freeze(quota_item);

View file

@ -15,7 +15,7 @@ const tabs = {
tenant_settings: 'Configurações',
mfa: 'Autenticação de multi-fator',
/** UNTRANSLATED */
customize_jwt: 'JWT Claims',
customize_jwt: 'Custom JWT',
signing_keys: 'Chaves de assinatura',
organization_template: 'Modelo de organização',
};

View file

@ -64,6 +64,13 @@ const paywall = {
/** UNTRANSLATED */
tenant_members_dev_plan:
"You've reached your {{limit}}-member limit. Release a member or revoke a pending invitation to add someone new. Need more seats? Feel free to contact us.",
custom_jwt: {
/** UNTRANSLATED */
title: 'Add custom claims',
/** UNTRANSLATED */
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
};
export default Object.freeze(paywall);

View file

@ -163,6 +163,16 @@ const quota_item = {
/** UNTRANSLATED */
not_eligible: 'Remove your tenant members',
},
custom_jwt_enabled: {
/** UNTRANSLATED */
name: 'Custom JWT',
/** UNTRANSLATED */
limited: 'Custom JWT',
/** UNTRANSLATED */
unlimited: 'Custom JWT',
/** UNTRANSLATED */
not_eligible: 'Remove your JWT claims customizer',
},
};
export default Object.freeze(quota_item);

View file

@ -15,7 +15,7 @@ const tabs = {
tenant_settings: 'Definições do inquilino',
mfa: 'Autenticação multi-fator',
/** UNTRANSLATED */
customize_jwt: 'JWT Claims',
customize_jwt: 'Custom JWT',
signing_keys: 'Chaves de assinatura',
organization_template: 'Modelo de organização',
};

View file

@ -64,6 +64,13 @@ const paywall = {
/** UNTRANSLATED */
tenant_members_dev_plan:
"You've reached your {{limit}}-member limit. Release a member or revoke a pending invitation to add someone new. Need more seats? Feel free to contact us.",
custom_jwt: {
/** UNTRANSLATED */
title: 'Add custom claims',
/** UNTRANSLATED */
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
};
export default Object.freeze(paywall);

View file

@ -163,6 +163,16 @@ const quota_item = {
/** UNTRANSLATED */
not_eligible: 'Remove your tenant members',
},
custom_jwt_enabled: {
/** UNTRANSLATED */
name: 'Custom JWT',
/** UNTRANSLATED */
limited: 'Custom JWT',
/** UNTRANSLATED */
unlimited: 'Custom JWT',
/** UNTRANSLATED */
not_eligible: 'Remove your JWT claims customizer',
},
};
export default Object.freeze(quota_item);

View file

@ -15,7 +15,7 @@ const tabs = {
tenant_settings: 'Настройки',
mfa: 'Multi-factor auth',
/** UNTRANSLATED */
customize_jwt: 'JWT Claims',
customize_jwt: 'Custom JWT',
signing_keys: 'Ключи подписи',
organization_template: 'Шаблон организации',
};

View file

@ -64,6 +64,13 @@ const paywall = {
/** UNTRANSLATED */
tenant_members_dev_plan:
"You've reached your {{limit}}-member limit. Release a member or revoke a pending invitation to add someone new. Need more seats? Feel free to contact us.",
custom_jwt: {
/** UNTRANSLATED */
title: 'Add custom claims',
/** UNTRANSLATED */
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
};
export default Object.freeze(paywall);

View file

@ -163,6 +163,16 @@ const quota_item = {
/** UNTRANSLATED */
not_eligible: 'Remove your tenant members',
},
custom_jwt_enabled: {
/** UNTRANSLATED */
name: 'Custom JWT',
/** UNTRANSLATED */
limited: 'Custom JWT',
/** UNTRANSLATED */
unlimited: 'Custom JWT',
/** UNTRANSLATED */
not_eligible: 'Remove your JWT claims customizer',
},
};
export default Object.freeze(quota_item);

View file

@ -15,7 +15,7 @@ const tabs = {
tenant_settings: 'Ayarlar',
mfa: 'Çoklu faktörlü kimlik doğrulama',
/** UNTRANSLATED */
customize_jwt: 'JWT Claims',
customize_jwt: 'Custom JWT',
signing_keys: 'İmza anahtarları',
organization_template: 'Kuruluş şablonu',
};

View file

@ -64,6 +64,13 @@ const paywall = {
/** UNTRANSLATED */
tenant_members_dev_plan:
"You've reached your {{limit}}-member limit. Release a member or revoke a pending invitation to add someone new. Need more seats? Feel free to contact us.",
custom_jwt: {
/** UNTRANSLATED */
title: 'Add custom claims',
/** UNTRANSLATED */
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
};
export default Object.freeze(paywall);

View file

@ -163,6 +163,16 @@ const quota_item = {
/** UNTRANSLATED */
not_eligible: 'Remove your tenant members',
},
custom_jwt_enabled: {
/** UNTRANSLATED */
name: 'Custom JWT',
/** UNTRANSLATED */
limited: 'Custom JWT',
/** UNTRANSLATED */
unlimited: 'Custom JWT',
/** UNTRANSLATED */
not_eligible: 'Remove your JWT claims customizer',
},
};
export default Object.freeze(quota_item);

View file

@ -15,7 +15,7 @@ const tabs = {
tenant_settings: '租户设置',
mfa: '多因素认证',
/** UNTRANSLATED */
customize_jwt: 'JWT Claims',
customize_jwt: 'Custom JWT',
signing_keys: '签名密钥',
organization_template: '组织模板',
};

View file

@ -63,6 +63,13 @@ const paywall = {
/** UNTRANSLATED */
tenant_members_dev_plan:
"You've reached your {{limit}}-member limit. Release a member or revoke a pending invitation to add someone new. Need more seats? Feel free to contact us.",
custom_jwt: {
/** UNTRANSLATED */
title: 'Add custom claims',
/** UNTRANSLATED */
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
};
export default Object.freeze(paywall);

View file

@ -163,6 +163,16 @@ const quota_item = {
/** UNTRANSLATED */
not_eligible: 'Remove your tenant members',
},
custom_jwt_enabled: {
/** UNTRANSLATED */
name: 'Custom JWT',
/** UNTRANSLATED */
limited: 'Custom JWT',
/** UNTRANSLATED */
unlimited: 'Custom JWT',
/** UNTRANSLATED */
not_eligible: 'Remove your JWT claims customizer',
},
};
export default Object.freeze(quota_item);

View file

@ -15,7 +15,7 @@ const tabs = {
tenant_settings: '租戶設置',
mfa: '多重認證',
/** UNTRANSLATED */
customize_jwt: 'JWT Claims',
customize_jwt: 'Custom JWT',
signing_keys: '簽署密鑰',
organization_template: '組織模板',
};

View file

@ -63,6 +63,13 @@ const paywall = {
/** UNTRANSLATED */
tenant_members_dev_plan:
"You've reached your {{limit}}-member limit. Release a member or revoke a pending invitation to add someone new. Need more seats? Feel free to contact us.",
custom_jwt: {
/** UNTRANSLATED */
title: 'Add custom claims',
/** UNTRANSLATED */
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
};
export default Object.freeze(paywall);

View file

@ -163,6 +163,16 @@ const quota_item = {
/** UNTRANSLATED */
not_eligible: 'Remove your tenant members',
},
custom_jwt_enabled: {
/** UNTRANSLATED */
name: 'Custom JWT',
/** UNTRANSLATED */
limited: 'Custom JWT',
/** UNTRANSLATED */
unlimited: 'Custom JWT',
/** UNTRANSLATED */
not_eligible: 'Remove your JWT claims customizer',
},
};
export default Object.freeze(quota_item);

View file

@ -15,7 +15,7 @@ const tabs = {
tenant_settings: '租戶設定',
mfa: '多重認證',
/** UNTRANSLATED */
customize_jwt: 'JWT Claims',
customize_jwt: 'Custom JWT',
signing_keys: '簽署密鑰',
organization_template: '組織模板',
};

View file

@ -63,6 +63,13 @@ const paywall = {
/** UNTRANSLATED */
tenant_members_dev_plan:
"You've reached your {{limit}}-member limit. Release a member or revoke a pending invitation to add someone new. Need more seats? Feel free to contact us.",
custom_jwt: {
/** UNTRANSLATED */
title: 'Add custom claims',
/** UNTRANSLATED */
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
};
export default Object.freeze(paywall);

12
pnpm-lock.yaml generated
View file

@ -2715,8 +2715,8 @@ importers:
specifier: workspace:^1.4.0
version: link:../app-insights
'@logto/cloud':
specifier: 0.2.5-ab8a489
version: 0.2.5-ab8a489(zod@3.22.4)
specifier: 0.2.5-94f7bcc
version: 0.2.5-94f7bcc(zod@3.22.4)
'@logto/connector-kit':
specifier: workspace:^3.0.0
version: link:../toolkit/connector-kit
@ -3205,8 +3205,8 @@ importers:
version: 3.22.4
devDependencies:
'@logto/cloud':
specifier: 0.2.5-749cae5
version: 0.2.5-749cae5(zod@3.22.4)
specifier: 0.2.5-94f7bcc
version: 0.2.5-94f7bcc(zod@3.22.4)
'@silverhand/eslint-config':
specifier: 5.0.0
version: 5.0.0(eslint@8.44.0)(prettier@3.0.0)(typescript@5.3.3)
@ -7647,8 +7647,8 @@ packages:
jose: 5.2.2
dev: true
/@logto/cloud@0.2.5-749cae5(zod@3.22.4):
resolution: {integrity: sha512-QzebHRSBShQwOsKAvYlVd7QF43RlrHOt/nmwrlRNW4F9U0DUEFaeLZujYS56oxjQ49GRdsOPKSQCE97wRB7NNQ==}
/@logto/cloud@0.2.5-94f7bcc(zod@3.22.4):
resolution: {integrity: sha512-1nY3o1/gXgEIqgvjel2no0X3rR+BGnfozB7Vev+FY2qTkDyQIWRtHAnx+kkv4iEIIFcZW86LRNlvfjDUqR2yIg==}
engines: {node: ^20.9.0}
dependencies:
'@silverhand/essentials': 2.9.0