chore: format

This commit is contained in:
2025-10-10 16:43:21 +02:00
parent f0aabd63b6
commit 75c29e0ba4
551 changed files with 433948 additions and 94145 deletions

View File

@@ -1,22 +1,24 @@
import jwt from "jsonwebtoken"
import bcrypt from "bcryptjs"
import { env } from "../constants"
import jwt from "jsonwebtoken";
import bcrypt from "bcryptjs";
import { env } from "../constants";
export async function hashPassword(password: string) {
return bcrypt.hash(password, 10)
return bcrypt.hash(password, 10);
}
export async function comparePasswords(
password: string,
hashedPassword: string
password: string,
hashedPassword: string,
) {
return bcrypt.compare(password, hashedPassword)
return bcrypt.compare(password, hashedPassword);
}
export function generateToken(userId: string, version: number) {
return jwt.sign({ id: userId, version }, env.JWT_SECRET, { expiresIn: "30d" })
return jwt.sign({ id: userId, version }, env.JWT_SECRET, {
expiresIn: "30d",
});
}
export function verifyToken(token: string) {
return jwt.verify(token, env.JWT_SECRET)
return jwt.verify(token, env.JWT_SECRET);
}

View File

@@ -1,18 +1,18 @@
const formatLog = (messages: unknown[]) => {
return `[${new Date().toISOString()}] ${messages.join(" ")}`
}
return `[${new Date().toISOString()}] ${messages.join(" ")}`;
};
export const logger = {
log(...messages: unknown[]) {
console.log(formatLog(messages))
},
info(...messages: unknown[]) {
console.log(formatLog(messages))
},
error(...messages: unknown[]) {
console.error(formatLog(messages))
},
warn(...messages: unknown[]) {
console.warn(formatLog(messages))
},
}
log(...messages: unknown[]) {
console.log(formatLog(messages));
},
info(...messages: unknown[]) {
console.log(formatLog(messages));
},
error(...messages: unknown[]) {
console.error(formatLog(messages));
},
warn(...messages: unknown[]) {
console.warn(formatLog(messages));
},
};

View File

@@ -1,14 +1,14 @@
export async function resolveProps<T extends Record<string, Promise<any>>>(
promises: T
promises: T,
): Promise<{ [K in keyof T]: Awaited<T[K]> }> {
const keys = Object.keys(promises)
const values = await Promise.all(Object.values(promises))
const keys = Object.keys(promises);
const values = await Promise.all(Object.values(promises));
return keys.reduce(
(acc, key, index) => {
acc[key as keyof T] = values[index]
return acc
},
{} as { [K in keyof T]: Awaited<T[K]> }
)
return keys.reduce(
(acc, key, index) => {
acc[key as keyof T] = values[index];
return acc;
},
{} as { [K in keyof T]: Awaited<T[K]> },
);
}

View File

@@ -1,122 +1,125 @@
import { replacePlaceholders } from "./placeholder-parser"
import { describe, it, expect } from "vitest"
import { replacePlaceholders } from "./placeholder-parser";
import { describe, it, expect } from "vitest";
describe("replacePlaceholders", () => {
it("should replace a single placeholder", () => {
const template = "Hello {{subscriber.name}}!"
const data = { "subscriber.name": "John" }
expect(replacePlaceholders(template, data)).toBe("Hello John!")
})
it("should replace a single placeholder", () => {
const template = "Hello {{subscriber.name}}!";
const data = { "subscriber.name": "John" };
expect(replacePlaceholders(template, data)).toBe("Hello John!");
});
it("should replace multiple placeholders", () => {
const template = "Order for {{subscriber.name}} from {{organization.name}}."
const data = {
"subscriber.name": "Alice",
"organization.name": "Org Inc",
}
expect(replacePlaceholders(template, data)).toBe(
"Order for Alice from Org Inc."
)
})
it("should replace multiple placeholders", () => {
const template =
"Order for {{subscriber.name}} from {{organization.name}}.";
const data = {
"subscriber.name": "Alice",
"organization.name": "Org Inc",
};
expect(replacePlaceholders(template, data)).toBe(
"Order for Alice from Org Inc.",
);
});
it("should handle templates with no placeholders", () => {
const template = "This is a static string."
const data = { "subscriber.name": "Bob" }
expect(replacePlaceholders(template, data)).toBe("This is a static string.")
})
it("should handle templates with no placeholders", () => {
const template = "This is a static string.";
const data = { "subscriber.name": "Bob" };
expect(replacePlaceholders(template, data)).toBe(
"This is a static string.",
);
});
it("should handle empty data", () => {
const template = "Hello {{subscriber.name}}!"
const data = {}
expect(replacePlaceholders(template, data)).toBe(
"Hello {{subscriber.name}}!"
)
})
it("should handle empty data", () => {
const template = "Hello {{subscriber.name}}!";
const data = {};
expect(replacePlaceholders(template, data)).toBe(
"Hello {{subscriber.name}}!",
);
});
it("should handle empty template string", () => {
const template = ""
const data = { "subscriber.name": "Eve" }
expect(replacePlaceholders(template, data)).toBe("")
})
it("should handle empty template string", () => {
const template = "";
const data = { "subscriber.name": "Eve" };
expect(replacePlaceholders(template, data)).toBe("");
});
it("should handle placeholders with special characters in keys", () => {
const template = "Link: {{unsubscribe_link}}"
const data = { unsubscribe_link: "http://example.com/unsubscribe" }
expect(replacePlaceholders(template, data)).toBe(
"Link: http://example.com/unsubscribe"
)
})
it("should handle placeholders with special characters in keys", () => {
const template = "Link: {{unsubscribe_link}}";
const data = { unsubscribe_link: "http://example.com/unsubscribe" };
expect(replacePlaceholders(template, data)).toBe(
"Link: http://example.com/unsubscribe",
);
});
it("should replace all occurrences of a placeholder", () => {
const template = "Hi {{subscriber.name}}, welcome {{subscriber.name}}."
const data = { "subscriber.name": "Charlie" }
expect(replacePlaceholders(template, data)).toBe(
"Hi Charlie, welcome Charlie."
)
})
it("should replace all occurrences of a placeholder", () => {
const template = "Hi {{subscriber.name}}, welcome {{subscriber.name}}.";
const data = { "subscriber.name": "Charlie" };
expect(replacePlaceholders(template, data)).toBe(
"Hi Charlie, welcome Charlie.",
);
});
it("should not replace partial matches", () => {
const template = "Hello {{subscriber.name}} and {{subscriber.names}}"
const data = { "subscriber.name": "David" }
expect(replacePlaceholders(template, data)).toBe(
"Hello David and {{subscriber.names}}"
)
})
it("should not replace partial matches", () => {
const template = "Hello {{subscriber.name}} and {{subscriber.names}}";
const data = { "subscriber.name": "David" };
expect(replacePlaceholders(template, data)).toBe(
"Hello David and {{subscriber.names}}",
);
});
it("should correctly replace various types of placeholders", () => {
const template =
"Email: {{subscriber.email}}, Campaign: {{campaign.name}}, Org: {{organization.name}}, Unsub: {{unsubscribe_link}}, Date: {{current_date}}"
const data = {
"subscriber.email": "test@example.com",
"campaign.name": "Newsletter Q1",
"organization.name": "MyCompany",
unsubscribe_link: "domain.com/unsub",
current_date: "2024-01-01",
}
expect(replacePlaceholders(template, data)).toBe(
"Email: test@example.com, Campaign: Newsletter Q1, Org: MyCompany, Unsub: domain.com/unsub, Web: domain.com/web, Date: 2024-01-01"
)
})
it("should correctly replace various types of placeholders", () => {
const template =
"Email: {{subscriber.email}}, Campaign: {{campaign.name}}, Org: {{organization.name}}, Unsub: {{unsubscribe_link}}, Date: {{current_date}}";
const data = {
"subscriber.email": "test@example.com",
"campaign.name": "Newsletter Q1",
"organization.name": "MyCompany",
unsubscribe_link: "domain.com/unsub",
current_date: "2024-01-01",
};
expect(replacePlaceholders(template, data)).toBe(
"Email: test@example.com, Campaign: Newsletter Q1, Org: MyCompany, Unsub: domain.com/unsub, Web: domain.com/web, Date: 2024-01-01",
);
});
it("should handle data with undefined values gracefully", () => {
const template = "Hello {{subscriber.name}} and {{campaign.name}}!"
const data = {
"subscriber.name": "DefinedName",
"campaign.name": undefined,
} as { [key: string]: string | undefined } // Added type assertion for clarity
expect(replacePlaceholders(template, data)).toBe(
"Hello DefinedName and {{campaign.name}}!"
)
})
it("should handle data with undefined values gracefully", () => {
const template = "Hello {{subscriber.name}} and {{campaign.name}}!";
const data = {
"subscriber.name": "DefinedName",
"campaign.name": undefined,
} as { [key: string]: string | undefined }; // Added type assertion for clarity
expect(replacePlaceholders(template, data)).toBe(
"Hello DefinedName and {{campaign.name}}!",
);
});
it("should replace placeholders with leading spaces inside braces", () => {
const template = "Hello {{ subscriber.name }}!"
const data = { "subscriber.name": "SpacedJohn" }
expect(replacePlaceholders(template, data)).toBe("Hello SpacedJohn!")
})
it("should replace placeholders with leading spaces inside braces", () => {
const template = "Hello {{ subscriber.name }}!";
const data = { "subscriber.name": "SpacedJohn" };
expect(replacePlaceholders(template, data)).toBe("Hello SpacedJohn!");
});
it("should replace placeholders with trailing spaces inside braces", () => {
const template = "Hello {{subscriber.name }}!"
const data = { "subscriber.name": "SpacedAlice" }
expect(replacePlaceholders(template, data)).toBe("Hello SpacedAlice!")
})
it("should replace placeholders with trailing spaces inside braces", () => {
const template = "Hello {{subscriber.name }}!";
const data = { "subscriber.name": "SpacedAlice" };
expect(replacePlaceholders(template, data)).toBe("Hello SpacedAlice!");
});
it("should replace placeholders with leading and trailing spaces inside braces", () => {
const template = "Hello {{ subscriber.name }}!"
const data = { "subscriber.name": "SpacedBob" }
expect(replacePlaceholders(template, data)).toBe("Hello SpacedBob!")
})
it("should replace placeholders with leading and trailing spaces inside braces", () => {
const template = "Hello {{ subscriber.name }}!";
const data = { "subscriber.name": "SpacedBob" };
expect(replacePlaceholders(template, data)).toBe("Hello SpacedBob!");
});
it("should replace multiple placeholders with various spacing", () => {
const template =
"Hi {{subscriber.name}}, welcome {{ organization.name }}. Date: {{current_date}}."
const data = {
"subscriber.name": "SpacedEve",
"organization.name": "Org Spaced Inc.",
current_date: "2024-02-20",
}
expect(replacePlaceholders(template, data)).toBe(
"Hi SpacedEve, welcome Org Spaced Inc.. Date: 2024-02-20."
)
})
})
it("should replace multiple placeholders with various spacing", () => {
const template =
"Hi {{subscriber.name}}, welcome {{ organization.name }}. Date: {{current_date}}.";
const data = {
"subscriber.name": "SpacedEve",
"organization.name": "Org Spaced Inc.",
current_date: "2024-02-20",
};
expect(replacePlaceholders(template, data)).toBe(
"Hi SpacedEve, welcome Org Spaced Inc.. Date: 2024-02-20.",
);
});
});

View File

@@ -1,47 +1,47 @@
interface SubscriberPlaceholderData {
email: string
name?: string
email: string;
name?: string;
}
interface CampaignPlaceholderData {
name: string
subject?: string
name: string;
subject?: string;
}
interface OrganizationPlaceholderData {
name: string
name: string;
}
export interface PlaceholderData {
subscriber: SubscriberPlaceholderData
campaign: CampaignPlaceholderData
organization: OrganizationPlaceholderData
unsubscribe_link: string
current_date?: string
subscriber: SubscriberPlaceholderData;
campaign: CampaignPlaceholderData;
organization: OrganizationPlaceholderData;
unsubscribe_link: string;
current_date?: string;
}
export type PlaceholderDataKey =
| `subscriber.${keyof SubscriberPlaceholderData}`
| `campaign.${keyof CampaignPlaceholderData}`
| `organization.${keyof OrganizationPlaceholderData}`
| `unsubscribe_link`
| `current_date`
| `subscriber.metadata.${string}`
| `subscriber.${keyof SubscriberPlaceholderData}`
| `campaign.${keyof CampaignPlaceholderData}`
| `organization.${keyof OrganizationPlaceholderData}`
| `unsubscribe_link`
| `current_date`
| `subscriber.metadata.${string}`;
export function replacePlaceholders(
template: string,
data: Partial<Record<PlaceholderDataKey, string>>
template: string,
data: Partial<Record<PlaceholderDataKey, string>>,
): string {
let result = template
for (const key in data) {
const placeholderRegex = new RegExp(
`{{\\s*${key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*}}`,
"g"
)
const value = data[key as PlaceholderDataKey]
if (value !== undefined) {
result = result.replace(placeholderRegex, value)
}
}
return result
let result = template;
for (const key in data) {
const placeholderRegex = new RegExp(
`{{\\s*${key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*}}`,
"g",
);
const value = data[key as PlaceholderDataKey];
if (value !== undefined) {
result = result.replace(placeholderRegex, value);
}
}
return result;
}

View File

@@ -1,28 +1,28 @@
import { PrismaClient } from "../../prisma/client"
import { PrismaClient } from "../../prisma/client";
export const prisma = new PrismaClient({
omit: {
user: {
password: true,
pwdVersion: true,
},
apiKey: {
key: true,
},
},
omit: {
user: {
password: true,
pwdVersion: true,
},
apiKey: {
key: true,
},
},
}).$extends({
query: {
subscriber: {
$allOperations({ args, query }) {
if (
"data" in args &&
"email" in args.data &&
typeof args.data.email === "string"
) {
args.data.email = args.data.email.toLowerCase()
}
return query(args)
},
},
},
})
query: {
subscriber: {
$allOperations({ args, query }) {
if (
"data" in args &&
"email" in args.data &&
typeof args.data.email === "string"
) {
args.data.email = args.data.email.toLowerCase();
}
return query(args);
},
},
},
});

View File

@@ -1,9 +1,9 @@
import { z } from "zod"
import { z } from "zod";
export const paginationSchema = z.object({
page: z.number().min(1).default(1),
perPage: z.number().min(1).max(100).default(10),
search: z.string().optional(),
})
page: z.number().min(1).default(1),
perPage: z.number().min(1).max(100).default(10),
search: z.string().optional(),
});
export type PaginationSchema = z.infer<typeof paginationSchema>
export type PaginationSchema = z.infer<typeof paginationSchema>;

View File

@@ -1,10 +1,10 @@
import { z } from "zod"
import { z } from "zod";
export const tokenPayloadSchema = z.object({
id: z.string(),
version: z.number(),
iat: z.number(),
exp: z.number(),
})
id: z.string(),
version: z.number(),
iat: z.number(),
exp: z.number(),
});
export type TokenPayload = z.infer<typeof tokenPayloadSchema>
export type TokenPayload = z.infer<typeof tokenPayloadSchema>;