feat(server): improve subscription sync stability (#14703)

This commit is contained in:
DarkSky
2026-03-23 21:13:00 +08:00
committed by GitHub
parent dcf041a3f2
commit 5d124ee55b
31 changed files with 1538 additions and 66 deletions
@@ -53,6 +53,7 @@ export enum Feature {
// workspace
UnlimitedWorkspace = 'unlimited_workspace',
TeamPlan = 'team_plan_v1',
QuotaExceededReadonlyWorkspace = 'quota_exceeded_readonly_workspace_v1',
}
// TODO(@forehalo): may merge `FeatureShapes` and `FeatureConfigs`?
@@ -66,6 +67,7 @@ export const FeaturesShapes = {
pro_plan_v1: UserPlanQuotaConfig,
lifetime_pro_plan_v1: UserPlanQuotaConfig,
team_plan_v1: WorkspaceQuotaConfig,
quota_exceeded_readonly_workspace_v1: EMPTY_CONFIG,
} satisfies Record<Feature, z.ZodObject<any>>;
export type UserFeatureName = keyof Pick<
@@ -80,7 +82,9 @@ export type UserFeatureName = keyof Pick<
>;
export type WorkspaceFeatureName = keyof Pick<
typeof FeaturesShapes,
'unlimited_workspace' | 'team_plan_v1'
| 'unlimited_workspace'
| 'team_plan_v1'
| 'quota_exceeded_readonly_workspace_v1'
>;
export type FeatureName = UserFeatureName | WorkspaceFeatureName;
@@ -162,6 +166,7 @@ export const FeatureConfigs: {
team_plan_v1: TeamFeature,
early_access: WhitelistFeature,
unlimited_workspace: EmptyFeature,
quota_exceeded_readonly_workspace_v1: EmptyFeature,
unlimited_copilot: EmptyFeature,
ai_early_access: EmptyFeature,
administrator: EmptyFeature,
@@ -36,7 +36,8 @@ export class WorkspaceUserModel extends BaseModel {
/**
* Set or update the [Owner] of a workspace.
* The old [Owner] will be changed to [Admin] if there is already an [Owner].
* The old [Owner] will be changed to [Admin] for team workspace and
* [Collaborator] for owned workspace if there is already an [Owner].
*/
@Transactional()
async setOwner(workspaceId: string, userId: string) {
@@ -63,12 +64,18 @@ export class WorkspaceUserModel extends BaseModel {
throw new NewOwnerIsNotActiveMember();
}
const fallbackRole = (await this.models.workspace.isTeamWorkspace(
workspaceId
))
? WorkspaceRole.Admin
: WorkspaceRole.Collaborator;
await this.db.workspaceUserRole.update({
where: {
id: oldOwner.id,
},
data: {
type: WorkspaceRole.Admin,
type: fallbackRole,
},
});
await this.db.workspaceUserRole.update({
@@ -201,6 +208,25 @@ export class WorkspaceUserModel extends BaseModel {
});
}
async deleteNonAccepted(workspaceId: string) {
return await this.db.workspaceUserRole.deleteMany({
where: { workspaceId, status: { not: WorkspaceMemberStatus.Accepted } },
});
}
async demoteAcceptedAdmins(workspaceId: string) {
return await this.db.workspaceUserRole.updateMany({
where: {
workspaceId,
status: WorkspaceMemberStatus.Accepted,
type: WorkspaceRole.Admin,
},
data: {
type: WorkspaceRole.Collaborator,
},
});
}
async get(workspaceId: string, userId: string) {
return await this.db.workspaceUserRole.findUnique({
where: {