Finding 1: Replace hand-rolled MONTH_NAMES[12] array with Intl.DateTimeFormat("en-US", {month:"long"}).
Finding 2: Drop @uiw/color-convert fallback — parseColorString already rejects the same inputs, return "#000000" instead. Remove dep from utils and server package.json.
Finding 3: Replace 56 z.literal calls in z.union with z.enum([...]); identical parse behavior and inferred type.
Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa
Templates import no React (react-email convention); tsx resolves each
file's nearest tsconfig, so jsx:preserve made esbuild emit classic
React.createElement and background email rendering threw
'React is not defined'.
Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa
Removes fs, path, env, getLocalDataDirectory imports from statistics service.
A module-level Map<string, {value, cachedAt}> gives the same TTL semantics
without touching disk. Adds clearStatisticsCache() for test isolation and
updates the test to call it in afterEach instead of relying on unique
LOCAL_STORAGE_PATH temp dirs (finding 5).
Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa
Replace 12 near-identical try/catch blocks in threads/actions/attachments/messages
handlers with a single AnyMiddleware that maps the AGENT_ENVIRONMENT_UNAVAILABLE
sentinel to PRECONDITION_FAILED ORPCError.
Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa
Move 14 identical style slots (text/heading/div/inline/link/small/bold/
richParagraph/richListItemRow/richListItemMarker/richListItemContent/
splitRow/alignEnd/picture) from all 15 template Page.tsx files into a
single createBaseTemplateStyles factory in templates/shared. Each template
now spreads …base and keeps only its real overrides. Resolved StyleSheet
values are identical to before. Update rtl-fixture and rich-text-template-
styles tests to guard the factory file rather than each template directly.
Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa
Add three shared contact-item components to packages/pdf/src/templates/shared/
contact-item.tsx alongside the existing WebsiteContactItem and CustomFieldContactItem.
Replace ~18 lines of inline email/phone/location JSX in all 15 template headers
with the shared components (EmailContactItem accepts an optional iconName prop
for ditgar's "at" variant; rhyhorn's array-push pattern also updated).
Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa
Two match chains in sections.tsx are replaced with plain lookup maps typed
via `satisfies Record<CustomSectionType, ...>` which preserves compile-time
exhaustiveness without the ts-pattern dependency. Remove ts-pattern from
packages/pdf/package.json.
Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa
Export parseFiniteNumber and parsePxValue from icon-size.ts (already the
canonical home of these helpers). Remove the three private copies in
rich-text-spacing.ts and import the shared ones instead.
Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa
- Delete templates.test.ts: re-tests z.enum semantics with a hardcoded
fixture that duplicates the template list in templates.ts.
- default.ts: add 2-line section(icon) helper; 12 repeated 7-field blocks
collapse to one-liners. Output is byte-identical.
- data.ts: add 2-line itemSection<T> factory; 12 baseSectionSchema.extend()
blocks collapse to one-liners. Inferred types unchanged.
- data.ts: replace 15-field hand-listed styleRuleSlotsSchema with
z.partialRecord(styleSlotSchema, styleIntentSchema); parse behaviour and
TypeScript type are equivalent (unknown keys still rejected).
Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa
AuthProvider was the only zod usage in the package — a z.enum solely to
infer a type. Replace with a plain union type and remove zod from
packages/auth/package.json dependencies.
Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa
- Replace pdf-parser-system.md + docx-parser-system.md with a single
parser-system.md template; prompts.ts substitutes 6 placeholders per
source type. Produced strings are byte-identical to the former files.
- Remove makeEmptyItem recursive walker (all SECTION_ITEM_SHAPES leaves are
already zero-valued) and call structuredClone(shape) instead.
Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa
- Add getBaseRun() next to getHtmlStyle() and replace 8 inline baseRun spreads (~27 lines).
- Hoist one mainConfig object in buildDocument; sidebar call spreads only the two
differing color keys (~17 lines).
- Remove BUILT_IN_SECTIONS Set; derive membership via `sectionId in data.sections` (~14 lines).
- Delete unreachable ordered-list numbering machinery in html-to-docx.ts: numberingRef is
always undefined through all call paths, so isOrdered && numberingRef is always false (~15 lines).
Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa
- Extract one TOOL_META record (title/description/inputSchema/annotations per
tool) consumed by both registerTools and buildMcpServerCard, eliminating the
~200-line duplication in the server card.
- Collapse TOOL_ANNOTATIONS from 14 × 4-line inline objects to 5 named
annotation-preset consts (READ_IDEMPOTENT, WRITE_NON_IDEMPOTENT, etc.),
saving ~55 lines.
Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa
Some providers (OpenAI Responses API, others) reject system-role messages in
the messages array with AI_InvalidPromptError. Move the analyze/parse system
prompts to the generateText system option, matching the chat handler.
A Postgres connection can drop at any time — e.g. a serverless Postgres such as
Neon terminating the connection (error code 57P01). node-postgres surfaces this as
an 'error' event; without a listener node re-throws it as an unhandled 'error' and
crashes the process. Idle clients emit on the pool, but a client that is connecting
or checked out emits on the client itself, so we listen on both the pool and each
client. The pool then discards the dead client and opens a fresh one on the next
query, so the server survives transient/idle disconnects.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
overflow: hidden on Text elements in @react-pdf/renderer v4.x clips
content at its initial computed height, hiding any text after a line
break. minWidth/maxWidth/flexShrink already handle horizontal
containment so nothing else breaks.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: use language-specific Noto fonts for CJK PDF fallback
* feat: extend fallback to Arabic/Hebrew/Thai
---------
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
* fix: use non-empty placeholder for redacted resume name
* fix: update stale test title to match new placeholder behavior
---------
Co-authored-by: Albano <alumno26.fazzito.albano@ipm.edu.ar>
Some providers (notably Anthropic via proxies) wrap JSON output in
markdown code fences (```json ... ```), causing Output.object to
throw NoObjectGeneratedError / JSONParseError.
Replace Output.object with manual JSON boundary extraction that works
regardless of fencing. Also propagate the original AISDKError as cause
in throwAiProviderGatewayError for better diagnostics.
* feat(editor): add multicolor highlight with auto-contrast text
Enable the Tiptap Highlight extension in multicolor mode, replacing the
single-color yellow toggle with a full color picker (16 presets + custom).
When the chosen highlight color is perceptually dark, text inside the mark
automatically renders white for readability.
Changes span the full pipeline:
- Editor: ColorPicker UI, extended renderHTML for contrast detection
- PDF: normalizeMarkElements preserves data-color as inline style
- DOCX: mergeStyle reads actual background-color from <mark>
- Utils: new isDarkColor() luminance helper
Backward-compatible: legacy <mark> without data-color still renders yellow.
Resolves#3109
* fix: handle multicolor highlight edge cases
---------
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
* feat: add section heading icons to PDF templates
Add customizable Phosphor icons before section titles in PDF output.
Users can toggle visibility globally via a new "Hide section heading icons"
switch (independent of item-level icons) and customize individual section
icons through the builder sidebar icon picker.
- Add `icon` field to `baseSectionSchema` and `summarySchema`
- Add `hideSectionIcons` to `pageSchema` (defaults to true for backward compat)
- Implement `SectionHeadingIcon` component with heading font-size scaling
- Support "none" sentinel for per-section icon hiding
- Fallback to sensible defaults (briefcase, graduation-cap, etc.) for legacy data
- Add icon picker to builder sidebar sections and custom section dialogs
Closes#2632
* test: add unit tests for section heading icons
- Add tests for getResumeSectionIcon() covering built-in sections,
summary, custom sections, "none" sentinel, and default fallbacks
- Add schema tests for baseSectionSchema icon field, summarySchema icon,
and pageSchema hideSectionIcons default behavior
* refactor: minor updates to icon display
* Update apps/web/locales/es-ES.po
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---------
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>