Files
TX/artifacts/api-server/package.json
T
Riyadh 7c5a9748a2 Rebuild PDF generation: HTML <table> + Playwright replaces PDFKit manual drawing
Task #372: Replaced the manual PDFKit coordinate-based PDF renderer with an
HTML table-based approach using Playwright's headless Chromium.

Key changes:
- Created `pdf-html-renderer.ts` with `buildScheduleHtml()` (generates full
  HTML with embedded base64 fonts, proper `<table>`, RTL/LTR support, row
  colors, merged cells, attendees formatting) and `htmlToPdfBuffer()` (renders
  HTML to PDF via Playwright Chromium).
- Updated `pdf-renderer.ts`: `renderSchedulePdf()` now delegates to the new
  HTML renderer via dynamic import. Legacy PDFKit code preserved as
  `renderSchedulePdf_LEGACY()` for fallback reference.
- Added `playwright-core` dependency and configured esbuild externals.
- Chromium binary discovery: searches `.cache/ms-playwright/` directories with
  env var override (`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH`). Browser instance
  is cached as singleton with launch mutex to prevent concurrent double-launch.
- Process shutdown hook closes browser on exit.

Requirements met:
- Each meeting in exactly one `<tr>` with 4 `<td>` cells
- No text outside table, attendees ~3 per line inline
- Time always in its column, `page-break-inside: avoid`, `table-layout: fixed`
- Matches reference design (blue header, centered text, DIN Next LT Arabic)
2026-05-04 10:24:08 +00:00

57 lines
1.6 KiB
JSON

{
"name": "@workspace/api-server",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "export NODE_ENV=development && pnpm run build && pnpm run start",
"build": "node ./build.mjs",
"start": "node --enable-source-maps ./dist/index.mjs",
"typecheck": "tsc -p tsconfig.json --noEmit",
"test:wait": "node ./scripts/wait-for-server.mjs",
"test": "node --test 'tests/**/*.test.mjs'"
},
"dependencies": {
"@google-cloud/storage": "^7.19.0",
"@swc/helpers": "^0.5.21",
"@workspace/api-zod": "workspace:*",
"@workspace/db": "workspace:*",
"arabic-persian-reshaper": "1.0.1",
"bcryptjs": "^3.0.3",
"bidi-js": "^1.0.3",
"connect-pg-simple": "^10.0.0",
"cookie-parser": "^1.4.7",
"cors": "^2",
"drizzle-orm": "catalog:",
"express": "^5",
"express-session": "^1.19.0",
"google-auth-library": "^10.6.2",
"nodemailer": "^8.0.7",
"pdfkit": "^0.18.0",
"pino": "^9",
"pino-http": "^10",
"playwright-core": "^1.59.1",
"sanitize-html": "^2.17.3",
"socket.io": "^4.8.3",
"zod": "catalog:"
},
"devDependencies": {
"@types/bcryptjs": "^3.0.0",
"@types/connect-pg-simple": "^7.0.3",
"@types/cookie-parser": "^1.4.10",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.6",
"@types/express-session": "^1.19.0",
"@types/node": "catalog:",
"@types/nodemailer": "^8.0.0",
"@types/pdfkit": "^0.17.6",
"@types/sanitize-html": "^2.16.1",
"esbuild": "^0.27.3",
"esbuild-plugin-pino": "^2.3.3",
"pg": "^8.20.0",
"pino-pretty": "^13",
"socket.io-client": "^4.8.3",
"thread-stream": "3.1.0"
}
}