Files
pitchfast/convex/domain.ts

176 lines
4.6 KiB
TypeScript

const SECRET_KEY_PATTERNS = [
/api[_-]?key/i,
/password/i,
/secret/i,
/token/i,
/credential/i,
/smtp/i,
/openrouter/i,
/google[_-]?(geocoding|places)?/i,
/pagespeed/i,
/rybbit/i,
];
export const CAMPAIGN_STATUSES = ["active", "paused"] as const;
export const LEAD_PRIORITIES = ["high", "medium", "low", "defer", "blocked"] as const;
export const LEAD_CONTACT_STATUSES = [
"new",
"missing_contact",
"audit_ready",
"outreach_ready",
"contacted",
"replied",
"do_not_contact",
] as const;
export const LEAD_DUPLICATE_STATUSES = [
"unchecked",
"unique",
"possible_duplicate",
"duplicate",
] as const;
export const LEAD_BLACKLIST_STATUSES = ["clear", "blocked"] as const;
export const AUDIT_STATUSES = [
"draft",
"approved",
"published",
"deactivated",
] as const;
export const OUTREACH_STRATEGIES = [
"call_first",
"email_first",
"defer",
"do_not_contact",
] as const;
export const OUTREACH_APPROVAL_STATUSES = [
"draft",
"approved",
"rejected",
] as const;
export const OUTREACH_SEND_STATUSES = [
"not_sent",
"queued",
"sent",
"failed",
] as const;
export const OUTREACH_RESPONSE_STATUSES = [
"none",
"manual_reply_recorded",
"no_interest",
"follow_up_needed",
] as const;
export const OUTREACH_SALES_STATUSES = [
"follow_up_planned",
"follow_up_sent",
"reply_received",
"not_interested",
"later",
"meeting_scheduled",
"proposal_requested",
"proposal_sent",
"won",
"lost",
"do_not_pursue",
] as const;
export const BLACKLIST_TYPES = [
"domain",
"email",
"phone",
"company",
"google_place_id",
] as const;
export const RUN_TYPES = [
"campaign",
"lead_discovery",
"audit",
"audit_generation",
"outreach",
"lifecycle",
"website_enrichment",
] as const;
export const RUN_STATUSES = [
"pending",
"running",
"succeeded",
"failed",
"canceled",
] as const;
export const AUDIT_GENERATION_STAGES = [
"classification",
"multimodalAudit",
"germanCopy",
"qualityReview",
] as const;
export const AUDIT_GENERATION_STATUSES = [
"pending",
"running",
"succeeded",
"failed",
"canceled",
] as const;
export const RUN_EVENT_LEVELS = ["info", "warning", "error"] as const;
export const SCREENSHOT_VIEWPORTS = ["desktop", "mobile"] as const;
export const PAGE_SPEED_STRATEGIES = ["mobile", "desktop"] as const;
export const PAGE_SPEED_RESULT_STATUSES = ["succeeded", "failed"] as const;
export const PAGE_SPEED_ERROR_TYPES = [
"quota",
"timeout",
"unavailable",
"invalid_url",
"api_error",
"unknown",
] as const;
export type CampaignStatus = (typeof CAMPAIGN_STATUSES)[number];
export type LeadPriority = (typeof LEAD_PRIORITIES)[number];
export type LeadContactStatus = (typeof LEAD_CONTACT_STATUSES)[number];
export type LeadDuplicateStatus = (typeof LEAD_DUPLICATE_STATUSES)[number];
export type LeadBlacklistStatus = (typeof LEAD_BLACKLIST_STATUSES)[number];
export type AuditStatus = (typeof AUDIT_STATUSES)[number];
export type OutreachStrategy = (typeof OUTREACH_STRATEGIES)[number];
export type OutreachApprovalStatus =
(typeof OUTREACH_APPROVAL_STATUSES)[number];
export type OutreachSendStatus = (typeof OUTREACH_SEND_STATUSES)[number];
export type OutreachResponseStatus =
(typeof OUTREACH_RESPONSE_STATUSES)[number];
export type OutreachSalesStatus = (typeof OUTREACH_SALES_STATUSES)[number];
export type BlacklistType = (typeof BLACKLIST_TYPES)[number];
export type RunType = (typeof RUN_TYPES)[number];
export type RunStatus = (typeof RUN_STATUSES)[number];
export type AuditGenerationStage = (typeof AUDIT_GENERATION_STAGES)[number];
export type AuditGenerationStatus = (typeof AUDIT_GENERATION_STATUSES)[number];
export type RunEventLevel = (typeof RUN_EVENT_LEVELS)[number];
export type ScreenshotViewport = (typeof SCREENSHOT_VIEWPORTS)[number];
export type PageSpeedStrategy = (typeof PAGE_SPEED_STRATEGIES)[number];
export type PageSpeedResultStatus = (typeof PAGE_SPEED_RESULT_STATUSES)[number];
export type PageSpeedErrorType = (typeof PAGE_SPEED_ERROR_TYPES)[number];
export type SettingsRow = {
key: string;
};
export function isSafeSettingsKey(key: string) {
const normalizedKey = key.trim();
if (normalizedKey.length === 0) {
return false;
}
return !SECRET_KEY_PATTERNS.some((pattern) => pattern.test(normalizedKey));
}
export function normalizeListLimit(limit: number | undefined) {
if (limit === undefined) {
return 50;
}
if (!Number.isFinite(limit)) {
return 50;
}
return Math.min(Math.max(Math.floor(limit), 1), 100);
}
export function filterSafeSettingsRows<T extends SettingsRow>(rows: T[]) {
return rows.filter((row) => isSafeSettingsKey(row.key));
}