- Add ws WebSocket server (port 3001) with JWT auth and user-socket mapping - Add WebSocket client with exponential backoff reconnection and heartbeat - Add useRealtimeAlerts hook with toast notifications and unread badge - Add alert.publisher service (WS → push → email fallback) - Integrate publisher into DarkWatch, VoicePrint, HomeTitle, SpamShield, RemoveBrokers - Update Navbar with connection status indicator and unread count - Add comprehensive tests (14 passing) for server, client, and publisher
77 lines
2.1 KiB
TypeScript
77 lines
2.1 KiB
TypeScript
import { wrap } from "@typeschema/valibot";
|
|
import { createTRPCRouter, publicProcedure, protectedProcedure } from "../utils";
|
|
import {
|
|
CheckNumberSchema,
|
|
ClassifySMSSchema,
|
|
ClassifyCallSchema,
|
|
CreateRuleSchema,
|
|
DeleteRuleSchema,
|
|
FeedbackSchema,
|
|
StatsFilterSchema,
|
|
} from "../schemas/spamshield";
|
|
import * as spamshieldService from "~/server/services/spamshield.service";
|
|
|
|
export const spamshieldRouter = createTRPCRouter({
|
|
checkNumber: publicProcedure
|
|
.input(wrap(CheckNumberSchema))
|
|
.query(async ({ input }) => {
|
|
return spamshieldService.checkNumberReputation(input.phoneNumber);
|
|
}),
|
|
|
|
classifySMS: publicProcedure
|
|
.input(wrap(ClassifySMSSchema))
|
|
.query(async ({ input, ctx }) => {
|
|
return spamshieldService.classifySMS(input.text, ctx.user?.id);
|
|
}),
|
|
|
|
classifyCall: publicProcedure
|
|
.input(wrap(ClassifyCallSchema))
|
|
.query(async ({ input, ctx }) => {
|
|
return spamshieldService.classifyCall(
|
|
input.callerNumber,
|
|
input.duration,
|
|
input.timeOfDay,
|
|
ctx.user?.id,
|
|
);
|
|
}),
|
|
|
|
getRules: protectedProcedure.query(async ({ ctx }) => {
|
|
return spamshieldService.getRules(ctx.user.id);
|
|
}),
|
|
|
|
createRule: protectedProcedure
|
|
.input(wrap(CreateRuleSchema))
|
|
.mutation(async ({ ctx, input }) => {
|
|
return spamshieldService.createRule(
|
|
ctx.user.id,
|
|
input.ruleType,
|
|
input.pattern,
|
|
input.action,
|
|
input.priority,
|
|
);
|
|
}),
|
|
|
|
deleteRule: protectedProcedure
|
|
.input(wrap(DeleteRuleSchema))
|
|
.mutation(async ({ ctx, input }) => {
|
|
return spamshieldService.deleteRule(ctx.user.id, input.ruleId);
|
|
}),
|
|
|
|
submitFeedback: protectedProcedure
|
|
.input(wrap(FeedbackSchema))
|
|
.mutation(async ({ ctx, input }) => {
|
|
return spamshieldService.submitFeedback(
|
|
ctx.user.id,
|
|
input.phoneNumber,
|
|
input.isSpam,
|
|
input.feedbackType,
|
|
);
|
|
}),
|
|
|
|
getStats: protectedProcedure
|
|
.input(wrap(StatsFilterSchema))
|
|
.query(async ({ ctx, input }) => {
|
|
return spamshieldService.getStats(ctx.user.id, input.period);
|
|
}),
|
|
});
|