FRE-4510: Implement feature flag checks for spam classification
- Add runtime flag evaluation from FLAG_<KEY> environment variables - Add enableCallAnalysis flag check to analyzeCall() and interceptCall() - Add enableFeedbackLoop flag check to recordFeedback() - Add 19 tests for feature flag behavior (checkFeatureFlag, getters, service integration) - Add vitest config and test script to spamshield package
This commit is contained in:
@@ -4,7 +4,7 @@ export const spamRateLimits = {
|
||||
PREMIUM: 2000,
|
||||
} as const;
|
||||
|
||||
export const spamFeatureFlags = {
|
||||
export const spamFeatureFlagDefaults = {
|
||||
enableHiyaIntegration: true,
|
||||
enableTruecallerIntegration: true,
|
||||
enableSMSClassification: true,
|
||||
@@ -12,11 +12,42 @@ export const spamFeatureFlags = {
|
||||
enableFeedbackLoop: true,
|
||||
} as const;
|
||||
|
||||
type FeatureFlagKey = keyof typeof spamFeatureFlagDefaults;
|
||||
|
||||
export function checkFeatureFlag(flag: FeatureFlagKey): boolean {
|
||||
const envKey = `FLAG_${flag.toUpperCase()}`;
|
||||
const envValue = process.env[envKey];
|
||||
|
||||
if (envValue !== undefined) {
|
||||
return envValue === 'true' || envValue === '1';
|
||||
}
|
||||
|
||||
return spamFeatureFlagDefaults[flag];
|
||||
}
|
||||
|
||||
export const spamFeatureFlags = {
|
||||
get enableHiyaIntegration() {
|
||||
return checkFeatureFlag('enableHiyaIntegration');
|
||||
},
|
||||
get enableTruecallerIntegration() {
|
||||
return checkFeatureFlag('enableTruecallerIntegration');
|
||||
},
|
||||
get enableSMSClassification() {
|
||||
return checkFeatureFlag('enableSMSClassification');
|
||||
},
|
||||
get enableCallAnalysis() {
|
||||
return checkFeatureFlag('enableCallAnalysis');
|
||||
},
|
||||
get enableFeedbackLoop() {
|
||||
return checkFeatureFlag('enableFeedbackLoop');
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const spamConfig = {
|
||||
maxPhoneNumberLength: 20,
|
||||
minPhoneNumberLength: 10,
|
||||
defaultConfidenceThreshold: 0.7,
|
||||
maxMetadataSize: 1024 * 10, // 10KB
|
||||
maxMetadataSize: 1024 * 10,
|
||||
circuitBreakerThreshold: 5,
|
||||
circuitBreakerTimeout: 60000,
|
||||
} as const;
|
||||
|
||||
@@ -197,6 +197,10 @@ export class SpamShieldService {
|
||||
confidence: number;
|
||||
ruleMatches: string[];
|
||||
}> {
|
||||
if (!spamFeatureFlags.enableCallAnalysis) {
|
||||
throw new Error('Call analysis disabled via feature flag');
|
||||
}
|
||||
|
||||
const validated = this.validatePhoneNumber(phoneNumber);
|
||||
const rules = await this.getActiveRules();
|
||||
|
||||
@@ -244,6 +248,10 @@ export class SpamShieldService {
|
||||
isSpam: boolean,
|
||||
label?: string
|
||||
): Promise<void> {
|
||||
if (!spamFeatureFlags.enableFeedbackLoop) {
|
||||
throw new Error('Feedback loop disabled via feature flag');
|
||||
}
|
||||
|
||||
const validated = this.validatePhoneNumber(phoneNumber);
|
||||
const encrypted = FieldEncryptionService.encrypt(validated);
|
||||
const hash = FieldEncryptionService.hashPhoneNumber(validated);
|
||||
@@ -391,6 +399,10 @@ export class SpamShieldService {
|
||||
|
||||
// Combined interception methods
|
||||
async interceptCall(call: IncomingCall): Promise<DecisionResult> {
|
||||
if (!spamFeatureFlags.enableCallAnalysis) {
|
||||
throw new Error('Call analysis disabled via feature flag');
|
||||
}
|
||||
|
||||
const requestId = call.requestId ?? generateRequestId();
|
||||
const decision = await this.makeRealTimeDecision(call.phoneNumber, {
|
||||
callMetadata: {
|
||||
|
||||
Reference in New Issue
Block a user