feat(server): improve ci build (#15386)

#### PR Dependency Tree


* **PR #15386** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
  * Improved email rendering and formatting consistency.
* Preserved calendar synchronization windows while removing reliance on
date utility libraries.
* Enhanced cleanup of Prisma engine files, including deduplication and
space-saving reporting.

* **Tests**
  * Updated email snapshots to validate formatted HTML output.

* **Refactor**
* Streamlined email component usage and centralized email rendering
behavior.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-07-31 17:07:05 +08:00
committed by GitHub
parent 5c38f1376c
commit 758b2260f8
11 changed files with 194 additions and 304 deletions
@@ -1,3 +1,4 @@
import { pretty } from '@react-email/render';
import test from 'ava';
import { normalizeSMTPHeloHostname } from '../core/mail/utils';
@@ -8,7 +9,7 @@ test('should render emails', async t => {
for (const render of Object.values(Renderers)) {
// @ts-expect-error use [PreviewProps]
const content = await render();
t.snapshot(content.html, content.subject);
t.snapshot(await pretty(content.html), content.subject);
}
});
@@ -20,7 +21,7 @@ test('should render mention email with empty doc title', async t => {
title: '',
},
});
t.snapshot(content.html, content.subject);
t.snapshot(await pretty(content.html), content.subject);
});
test('should normalize valid SMTP HELO hostnames', t => {
@@ -1,5 +1,3 @@
import { format } from 'date-fns';
import { Bold } from './template';
export interface DateProps {
@@ -7,5 +5,9 @@ export interface DateProps {
}
export const IOSDate = (props: DateProps) => {
return <Bold>{format(props.value, 'yyyy-MM-dd')}</Bold>;
const year = String(props.value.getFullYear()).padStart(4, '0');
const month = String(props.value.getMonth() + 1).padStart(2, '0');
const day = String(props.value.getDate()).padStart(2, '0');
return <Bold>{`${year}-${month}-${day}`}</Bold>;
};
@@ -1,4 +1,4 @@
import { Link } from '@react-email/components';
import { Link } from '@react-email/link';
import { Bold } from './template';
@@ -1,4 +1,8 @@
import { Container, Img, Link, Row, Section } from '@react-email/components';
import { Container } from '@react-email/container';
import { Img } from '@react-email/img';
import { Link } from '@react-email/link';
import { Row } from '@react-email/row';
import { Section } from '@react-email/section';
import type { CSSProperties } from 'react';
import { BasicTextStyle } from './common';
@@ -1,15 +1,13 @@
import {
Body,
Button as EmailButton,
Container,
Head,
Html,
Img,
Link,
Row,
Section,
Text as EmailText,
} from '@react-email/components';
import { Body } from '@react-email/body';
import { Button as EmailButton } from '@react-email/button';
import { Container } from '@react-email/container';
import { Head } from '@react-email/head';
import { Html } from '@react-email/html';
import { Img } from '@react-email/img';
import { Link } from '@react-email/link';
import { Row } from '@react-email/row';
import { Section } from '@react-email/section';
import { Text as EmailText } from '@react-email/text';
import type { PropsWithChildren } from 'react';
import { BasicTextStyle } from './common';
+2 -6
View File
@@ -1,7 +1,7 @@
import { render as rawRender } from '@react-email/components';
import { type ComponentType, createElement, type ReactElement } from 'react';
import { type ComponentType, createElement } from 'react';
import { Comment, CommentMention, Mention } from './docs';
import { render } from './render';
import {
TeamBecomeAdmin,
TeamBecomeCollaborator,
@@ -41,10 +41,6 @@ type EmailContent = {
html: string;
};
function render(component: ReactElement) {
return rawRender(component, { pretty: env.testing });
}
type Props<T> = T extends ComponentType<infer P> ? P : never;
export type EmailRenderer<Props> = (props: Props) => Promise<EmailContent>;
@@ -0,0 +1,21 @@
import { createElement, type ReactElement, Suspense } from 'react';
import { renderToReadableStream } from 'react-dom/server';
const doctype =
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
export async function render(component: ReactElement) {
const stream = await renderToReadableStream(
createElement(Suspense, null, component),
{ progressiveChunkSize: Number.POSITIVE_INFINITY }
);
const decoder = new TextDecoder('utf-8');
let html = '';
for await (const chunk of stream) {
html += decoder.decode(chunk, { stream: true });
}
html += decoder.decode();
return `${doctype}${html.replace(/<!DOCTYPE.*?>/, '')}`;
}
@@ -3,7 +3,6 @@ import { randomUUID } from 'node:crypto';
import { Injectable, Logger } from '@nestjs/common';
import { Transactional } from '@nestjs-cls/transactional';
import type { CalendarAccount, Prisma } from '@prisma/client';
import { addDays, subDays } from 'date-fns';
import {
CalendarProviderRequestError,
@@ -819,9 +818,14 @@ export class CalendarService {
private getSyncWindow() {
const now = this.now();
const timeMin = new Date(now);
const timeMax = new Date(now);
timeMin.setDate(timeMin.getDate() - DEFAULT_PAST_DAYS);
timeMax.setDate(timeMax.getDate() + DEFAULT_FUTURE_DAYS);
return {
timeMin: subDays(now, DEFAULT_PAST_DAYS).toISOString(),
timeMax: addDays(now, DEFAULT_FUTURE_DAYS).toISOString(),
timeMin: timeMin.toISOString(),
timeMax: timeMax.toISOString(),
};
}