mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
feat(core,connector): update koaQuotaGuard to fit new pricing model (#5123)
This commit is contained in:
parent
e28822997f
commit
22e9580d68
8 changed files with 44 additions and 28 deletions
|
@ -49,6 +49,6 @@
|
|||
"access": "public"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@logto/cloud": "0.2.5-5a698db"
|
||||
"@logto/cloud": "0.2.5-5deb133"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@logto/cloud": "0.2.5-5a698db",
|
||||
"@logto/cloud": "0.2.5-5deb133",
|
||||
"@silverhand/eslint-config": "4.0.1",
|
||||
"@silverhand/ts-config": "4.0.0",
|
||||
"@types/debug": "^4.1.7",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { ConnectorType, DemoConnector } from '@logto/connector-kit';
|
||||
import { RoleType, ReservedPlanId } from '@logto/schemas';
|
||||
|
||||
import { EnvSet } from '#src/env-set/index.js';
|
||||
import RequestError from '#src/errors/RequestError/index.js';
|
||||
|
@ -44,7 +45,9 @@ export const createQuotaLibrary = (
|
|||
// Ignore the default management API resource
|
||||
return { count: count - 1 };
|
||||
},
|
||||
rolesLimit: async () => countRoles(),
|
||||
rolesLimit: async () => countRoles(undefined, { type: RoleType.User }),
|
||||
machineToMachineRolesLimit: async () =>
|
||||
countRoles(undefined, { type: RoleType.MachineToMachine }),
|
||||
scopesPerResourceLimit: async (queryKey) => {
|
||||
assertThat(queryKey, new TypeError('queryKey for scopesPerResourceLimit is required'));
|
||||
return countScopesByResourceId(queryKey);
|
||||
|
@ -61,13 +64,6 @@ export const createQuotaLibrary = (
|
|||
).length;
|
||||
return { count };
|
||||
},
|
||||
standardConnectorsLimit: async () => {
|
||||
const connectors = await getLogtoConnectors();
|
||||
const count = connectors.filter(
|
||||
({ metadata: { isStandard, id } }) => isStandard && id !== DemoConnector.Social
|
||||
).length;
|
||||
return { count };
|
||||
},
|
||||
customDomainEnabled: notNumber,
|
||||
mfaEnabled: notNumber,
|
||||
organizationsEnabled: notNumber,
|
||||
|
@ -96,8 +92,9 @@ export const createQuotaLibrary = (
|
|||
return;
|
||||
}
|
||||
|
||||
const plan = await getTenantSubscriptionPlan(cloudConnection);
|
||||
const limit = plan.quota[key];
|
||||
const { id: planId, quota } = await getTenantSubscriptionPlan(cloudConnection);
|
||||
// Only apply hard quota limit for free plan, o/w it's soft limit (use `null` to bypass quota check for soft limit cases).
|
||||
const limit = planId === ReservedPlanId.Free ? quota[key] : null;
|
||||
|
||||
if (limit === null) {
|
||||
return;
|
||||
|
|
|
@ -129,11 +129,11 @@ export default function applicationRoutes<T extends AuthedRouter>(
|
|||
async (ctx, next) => {
|
||||
const { oidcClientMetadata, ...rest } = ctx.guard.body;
|
||||
|
||||
await quota.guardKey(
|
||||
rest.type === ApplicationType.MachineToMachine
|
||||
? 'machineToMachineLimit'
|
||||
: 'applicationsLimit'
|
||||
);
|
||||
// When creating a m2m app, should check both m2m limit and application limit.
|
||||
if (rest.type === ApplicationType.MachineToMachine) {
|
||||
await quota.guardKey('machineToMachineLimit');
|
||||
}
|
||||
await quota.guardKey('applicationsLimit');
|
||||
|
||||
// Third party applications must be traditional type
|
||||
if (rest.isThirdParty) {
|
||||
|
|
|
@ -25,9 +25,6 @@ const guardConnectorsQuota = async (
|
|||
factory: ConnectorFactory<typeof router>,
|
||||
quota: QuotaLibrary
|
||||
) => {
|
||||
if (factory.metadata.isStandard) {
|
||||
await quota.guardKey('standardConnectorsLimit');
|
||||
}
|
||||
if (factory.type === ConnectorType.Social) {
|
||||
await quota.guardKey('socialConnectorsLimit');
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { RoleResponse } from '@logto/schemas';
|
||||
import { Roles, featuredApplicationGuard, featuredUserGuard } from '@logto/schemas';
|
||||
import { RoleType, Roles, featuredApplicationGuard, featuredUserGuard } from '@logto/schemas';
|
||||
import { generateStandardId } from '@logto/shared';
|
||||
import { pickState, tryThat } from '@silverhand/essentials';
|
||||
import { object, string, z, number } from 'zod';
|
||||
|
@ -7,7 +7,6 @@ import { object, string, z, number } from 'zod';
|
|||
import RequestError from '#src/errors/RequestError/index.js';
|
||||
import koaGuard from '#src/middleware/koa-guard.js';
|
||||
import koaPagination from '#src/middleware/koa-pagination.js';
|
||||
import koaQuotaGuard from '#src/middleware/koa-quota-guard.js';
|
||||
import koaRoleRlsErrorHandler from '#src/middleware/koa-role-rls-error-handler.js';
|
||||
import assertThat from '#src/utils/assert-that.js';
|
||||
import { parseSearchParamsForSearch } from '#src/utils/search.js';
|
||||
|
@ -133,7 +132,6 @@ export default function roleRoutes<T extends AuthedRouter>(...[router, tenant]:
|
|||
|
||||
router.post(
|
||||
'/roles',
|
||||
koaQuotaGuard({ key: 'rolesLimit', quota }),
|
||||
koaGuard({
|
||||
body: Roles.createGuard
|
||||
.omit({ id: true })
|
||||
|
@ -145,6 +143,13 @@ export default function roleRoutes<T extends AuthedRouter>(...[router, tenant]:
|
|||
const { body } = ctx.guard;
|
||||
const { scopeIds, ...roleBody } = body;
|
||||
|
||||
// `rolesLimit` is actually the limit of user roles, keep this name for backward compatibility.
|
||||
// We have optional `type` when creating a new role, if `type` is not provided, use `User` as default.
|
||||
// `machineToMachineRolesLimit` is the limit of machine to machine roles, and is independent to `rolesLimit`.
|
||||
await quota.guardKey(
|
||||
roleBody.type === RoleType.MachineToMachine ? 'machineToMachineRolesLimit' : 'rolesLimit'
|
||||
);
|
||||
|
||||
assertThat(
|
||||
!(await findRoleByRoleName(roleBody.name)),
|
||||
new RequestError({
|
||||
|
|
|
@ -9,7 +9,9 @@ type RouteResponseType<T extends { search?: unknown; body?: unknown; response?:
|
|||
|
||||
export type SubscriptionPlan = RouteResponseType<GetRoutes['/api/subscription-plans']>[number];
|
||||
|
||||
// Since `standardConnectorsLimit` will be removed in the upcoming pricing V2, no need to guard it.
|
||||
// `tokenLimit` is not guarded in backend.
|
||||
export type FeatureQuota = Omit<
|
||||
SubscriptionPlan['quota'],
|
||||
'tenantLimit' | 'mauLimit' | 'auditLogsRetentionDays'
|
||||
'tenantLimit' | 'mauLimit' | 'auditLogsRetentionDays' | 'standardConnectorsLimit' | 'tokenLimit'
|
||||
>;
|
||||
|
|
|
@ -1322,8 +1322,8 @@ importers:
|
|||
specifier: ^29.5.0
|
||||
version: 29.5.0
|
||||
'@logto/cloud':
|
||||
specifier: 0.2.5-5a698db
|
||||
version: 0.2.5-5a698db(zod@3.22.4)
|
||||
specifier: 0.2.5-5deb133
|
||||
version: 0.2.5-5deb133(zod@3.22.4)
|
||||
'@rollup/plugin-commonjs':
|
||||
specifier: ^25.0.0
|
||||
version: 25.0.7(rollup@4.1.4)
|
||||
|
@ -3324,8 +3324,8 @@ importers:
|
|||
version: 3.22.4
|
||||
devDependencies:
|
||||
'@logto/cloud':
|
||||
specifier: 0.2.5-5a698db
|
||||
version: 0.2.5-5a698db(zod@3.22.4)
|
||||
specifier: 0.2.5-5deb133
|
||||
version: 0.2.5-5deb133(zod@3.22.4)
|
||||
'@silverhand/eslint-config':
|
||||
specifier: 4.0.1
|
||||
version: 4.0.1(eslint@8.44.0)(prettier@3.0.0)(typescript@5.0.2)
|
||||
|
@ -7522,6 +7522,16 @@ packages:
|
|||
- zod
|
||||
dev: true
|
||||
|
||||
/@logto/cloud@0.2.5-5deb133(zod@3.22.4):
|
||||
resolution: {integrity: sha512-3itFraudBBc3bcS6qiBFHXQKoDYPFihxRu+L4HqDVEwTCBJfVVgGgD4F0fMpSpC+ouJY+VVdZGh7Yn9772B5fg==}
|
||||
engines: {node: ^18.12.0}
|
||||
dependencies:
|
||||
'@silverhand/essentials': 2.8.6
|
||||
'@withtyped/server': 0.12.9(zod@3.22.4)
|
||||
transitivePeerDependencies:
|
||||
- zod
|
||||
dev: true
|
||||
|
||||
/@logto/js@3.0.1:
|
||||
resolution: {integrity: sha512-vsU6mH5oiiW3k00pMyVA4V31K2Bd0rOT9qWch2l5e5o1yCQLJ3zUIOjGjChu3m2TRu1d920iiUpZU3Lzf6Pwdw==}
|
||||
dependencies:
|
||||
|
@ -9221,6 +9231,11 @@ packages:
|
|||
engines: {node: ^16.13.0 || ^18.12.0 || ^19.2.0, pnpm: ^8.0.0}
|
||||
dev: true
|
||||
|
||||
/@silverhand/essentials@2.8.6:
|
||||
resolution: {integrity: sha512-qNyc6CvZRngP66hTA8sbpXGsiu9j6Hu62jCy7LV3tJiytg/hmxJB5oM9k5tpaUa9kHwYJ2X9CManX7SYYNrzHg==}
|
||||
engines: {node: ^16.13.0 || ^18.12.0 || ^19.2.0, pnpm: ^8.0.0}
|
||||
dev: true
|
||||
|
||||
/@silverhand/ts-config-react@4.0.0(typescript@5.0.2):
|
||||
resolution: {integrity: sha512-IkZka1iuIBgw0AUbsknghw1vOIs4zOgUxR8jL38Kuk63hmSj687N4BWBb8KhVMhqaG4U/DYkbSEZuwsyHBe68g==}
|
||||
engines: {node: ^18.12.0}
|
||||
|
|
Loading…
Reference in a new issue