feat: add copilot feature type (#5465)

This commit is contained in:
DarkSky
2024-01-04 10:36:34 +00:00
parent df09dac389
commit f5b74ca8a9
13 changed files with 186 additions and 133 deletions
@@ -19,7 +19,20 @@ class FeatureConfig {
}
}
export class CopilotFeatureConfig extends FeatureConfig {
override config!: Feature & { feature: FeatureType.Copilot };
constructor(data: any) {
super(data);
if (this.config.feature !== FeatureType.Copilot) {
throw new Error('Invalid feature config: type is not Copilot');
}
}
}
export class EarlyAccessFeatureConfig extends FeatureConfig {
override config!: Feature & { feature: FeatureType.EarlyAccess };
constructor(data: any) {
super(data);
@@ -39,13 +52,15 @@ export class EarlyAccessFeatureConfig extends FeatureConfig {
}
const FeatureConfigMap = {
[FeatureType.Copilot]: CopilotFeatureConfig,
[FeatureType.EarlyAccess]: EarlyAccessFeatureConfig,
};
const FeatureCache = new Map<
number,
InstanceType<(typeof FeatureConfigMap)[FeatureType]>
>();
export type FeatureConfigType<F extends FeatureType> = InstanceType<
(typeof FeatureConfigMap)[F]
>;
const FeatureCache = new Map<number, FeatureConfigType<FeatureType>>();
export async function getFeature(prisma: PrismaService, featureId: number) {
const cachedQuota = FeatureCache.get(featureId);
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
import { PrismaService } from '../../prisma';
import { UserType } from '../users/types';
import { getFeature } from './feature';
import { FeatureConfigType, getFeature } from './feature';
import { FeatureKind, FeatureType } from './types';
@Injectable()
@@ -28,7 +28,9 @@ export class FeatureService {
);
}
async getFeature(feature: FeatureType) {
async getFeature<F extends FeatureType>(
feature: F
): Promise<FeatureConfigType<F> | undefined> {
const data = await this.prisma.features.findFirst({
where: {
feature,
@@ -40,7 +42,7 @@ export class FeatureService {
},
});
if (data) {
return getFeature(this.prisma, data.id);
return getFeature(this.prisma, data.id) as FeatureConfigType<F>;
}
return undefined;
}
@@ -0,0 +1,4 @@
export enum FeatureType {
Copilot = 'copilot',
EarlyAccess = 'early_access',
}
@@ -0,0 +1,8 @@
import { z } from 'zod';
import { FeatureType } from './common';
export const featureCopilot = z.object({
feature: z.literal(FeatureType.Copilot),
configs: z.object({}),
});
@@ -0,0 +1,24 @@
import { URL } from 'node:url';
import { z } from 'zod';
import { FeatureType } from './common';
function checkHostname(host: string) {
try {
return new URL(`https://${host}`).hostname === host;
} catch (_) {
return false;
}
}
export const featureEarlyAccess = z.object({
feature: z.literal(FeatureType.EarlyAccess),
configs: z.object({
whitelist: z
.string()
.startsWith('@')
.refine(domain => checkHostname(domain.slice(1)))
.array(),
}),
});
@@ -1,7 +1,9 @@
import { URL } from 'node:url';
import { z } from 'zod';
import { FeatureType } from './common';
import { featureCopilot } from './copilot';
import { featureEarlyAccess } from './early-access';
/// ======== common schema ========
export enum FeatureKind {
@@ -20,30 +22,13 @@ export type CommonFeature = z.infer<typeof commonFeatureSchema>;
/// ======== feature define ========
export enum FeatureType {
EarlyAccess = 'early_access',
}
function checkHostname(host: string) {
try {
return new URL(`https://${host}`).hostname === host;
} catch (_) {
return false;
}
}
const featureEarlyAccess = z.object({
feature: z.literal(FeatureType.EarlyAccess),
configs: z.object({
whitelist: z
.string()
.startsWith('@')
.refine(domain => checkHostname(domain.slice(1)))
.array(),
}),
});
export const Features: Feature[] = [
{
feature: FeatureType.Copilot,
type: FeatureKind.Feature,
version: 1,
configs: {},
},
{
feature: FeatureType.EarlyAccess,
type: FeatureKind.Feature,
@@ -60,6 +45,8 @@ export const FeatureSchema = commonFeatureSchema
.extend({
type: z.literal(FeatureKind.Feature),
})
.and(z.discriminatedUnion('feature', [featureEarlyAccess]));
.and(z.discriminatedUnion('feature', [featureCopilot, featureEarlyAccess]));
export type Feature = z.infer<typeof FeatureSchema>;
export { FeatureType };