1.0.9 rejects the Path2D objects pdfjs-dist 6.3.289 passes to fill/clip,
failing every raster test with "Value is none of these types `String`, `Path`".
Adding packages/pdf to CI turned it red on ubuntu-latest for two reasons,
neither of which is a real regression.
Rasterized pixels depend on the host font rasterizer. The chikorita, ditto
and all-template baselines differ on Linux in rasterSha256 alone: every page
count, item count and text coordinate is byte-identical to the macOS-authored
baseline. Compare the portable geometry on every host and the pixels only on
the platform the PNGs were generated on, so the characterization keeps
protecting layout without asserting another machine's antialiasing.
The picture-fit override case rasterizes twice and timed out at Vitest's 5s
default on a CI runner, with the date suite landing at 3.5-4.7s. Give the
package a 30s timeout rather than leaving every rendering test a runner
slowdown away from failing.
Verified on linux/amd64 in Docker: both files pass, 18/18.
The Lapras section marginTop added in c0c658c0 shifted every date marker in
that template down the page, but the date-layout characterization baseline
was not regenerated, so packages/pdf has been failing on main since. The
delta is geometry-only: same page count (2), same text item count (87), same
markers, x and width unchanged; 17 markers move on y and the raster hashes
follow.
Nothing caught it because the workflow ran test:ci for only server and
tooling, leaving 17 packages uncovered. Replace that filter list with the
full workspace run so a package cannot silently lose coverage again, and
move it after the migration and storage steps that the api suite needs.
Serial execution is deliberate. Running the packages in parallel oversubscribes
the runner and starves the PDF rasterization and API rate-limit suites past
their timeouts; 19/19 pass consistently at --concurrency=1.
Patch and minor bumps across the AI provider SDKs (@ai-sdk/*, ai),
@aws-sdk/client-s3, react-email/@react-email/ui, knip and jszip, with
pnpm-lock.yaml regenerated to match.
Also records the audit overrides and patched dependencies in the root
package.json alongside the existing pnpm-workspace.yaml entries.
- Fix Grid/Compact/List tab overlap on the resumes dashboard: the fixed
three-column grid forced cells narrower than their labels, so tab content
spilled into neighboring cells.
- Replace the "Resume styling" resume picker with a template picker in the
cover-letter create form and editor. The API accepts a `template` on create
and update, and refreshing style from a resume no longer overwrites it. The
resume control remains in the editor as "Sender details" since it is the
only source for the letter header.
- Remove the cover-letter library button from the builder sidebar and add an
"Import from library" option to the create-cover-letter dialog. Resume to
library copying stays in the library with its own resume picker.
- Remove the authored-pages/PDF-overflow note from the layout sidebar.
* fix(pdf): isolate character metadata for cached font glyphs
* test(pdf): verify glyph aliases do not grow cache
* test(pdf): assert glyph aliases are unique
* feat(editor): support whole-paragraph indentation
* fix(docx): retain indentation in quotes and RTL documents
* fix(exports): bound paragraph insets in narrow PDF columns
* fix(pdf): type bounded paragraph rendering consistently
* test(editor): use explicit list conversion commands
* fix(docx): preserve quote inset on list items
* feat(import): parse a PDF resume without an AI provider
Importing a PDF required a connected AI provider, so anyone without a
paid API key could only import the three JSON formats. Almost nobody
arrives with one of those files; they arrive with a PDF. The first thing
a new user tries to do was blocked behind bringing their own key.
Adds a deterministic parser that reads the text out of the PDF in the
browser and prefills the builder. It pulls the contact block, segments
the body on conventional headings, and maps entries to real items,
reusing the ATS period parser for dates so a date range is not mistaken
for a phone number.
Nothing is thrown away: header parts that do not map to a field go into
the description, and unrecognized headings become custom sections. The
imported sections are placed on the page so the result renders straight
away. Output is validated against the resume schema before it is
returned.
Text extraction groups items by baseline rather than trusting hasEOL,
and turns wide column gaps into a double space, which is what lets a
row split into company, position and location.
The AI path still runs when a provider is connected. Word import is
unchanged and still requires one.
Closes#3334
* fix(import): keep every section and entry the PDF actually contains
Review found three ways the parser lost or mangled content, all of them
reproducible.
A document whose first heading was not one of the known aliases never
started a section, because unknown-heading detection was gated on a
section already being open. Everything after it was swallowed as contact
header text. The header block is now bounded by where the contact
details stop, so a heading is recognized wherever it appears.
An entry spreading company, position and dates over three lines was
imported as two malformed items. A line that introduces an entry now
merges into the open entry instead of starting a second one.
An uppercase company such as ACME CORPORATION was read as a section
heading and fragmented the entry. A heading candidate followed by a date
line is now treated as an entry header, which is what it is.
Also escape single quotes, and construct the PDF worker inside the try
so the nested worker is terminated even if construction throws.
Title-case headings are deliberately still not treated as headings:
company and school names are title case too, and splitting on them would
fragment real entries. Such a section stays in the preceding one with its
text intact rather than risking loss.
* fix(import): look past a multi-line preamble before calling a line a heading
The previous guard only inspected the next line, so an uppercase company
followed by a separate role line and then the dates was still read as a
section heading. The experience or education entry was moved into a
custom section and lost.
Heading detection now scans a two-line window for the date that marks an
entry, and stops early at a bullet so a genuine heading whose section
opens with bullet points is still recognized.
The window can suppress a real heading whose first entry puts a bare date
two lines below it. That is the deliberate direction to fail in: a missed
heading leaves the text in the preceding section, while a misread entry
fragments structured content.
* fix(import): collect an entry preamble until its dates appear
An entry that spread company, role, location and dates over four lines
was imported as two broken items: the company with no dates, and the
location carrying the period.
The cause was in entry grouping rather than heading detection. Lines
before a date were only folded into the entry header when the date sat
on the very next line; anything earlier fell through to the description.
Preamble lines are now collected into the entry header until the dates
turn up, bounded by the same lookahead and stopping at a bullet, so an
undated section cannot swallow itself.
The heading lookahead widens to four lines to match, which is the
realistic maximum for company, role, location and dates.
* fix(import): harden local PDF resume parsing
* chore(import): document audited HTML construction
---------
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
* feat(skills): add inline layout option for skill items
* fix: restore default skills layout (regressed by inline feature)
- Restore metrics rowGap style for default layout
- Only render LevelDisplay inside the row for inline layout, not default
* refactor(pdf): Extract inline skills style logic from JSX to reusable function
* test(pdf): add test coverage for inline skills item layout
- Add test suite SkillsSectionInlineFormat to verify isInlineSkillsItem and getSkillsItemStyle behavior
* test(pdf): add comprehensive test coverage for inline skills item style logic
- Test combinations of proficiency, level, and keywords fields (0, 1, 3 fields)
* test(schema): add test coverage for column equals 1 when layout is inline
* test(web): add component-level tests for inline and columns layouts
* test(import): add v4 parser-level test for missing skills layout
* docs: regenerate skills layout references
* test(docx): include skills layout in section fixtures
---------
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
* fix(pdf): keep list markers with their first text fragment
* fix(pdf): preserve page breaks while rewinding list companions
* fix(pdf): consume oversized list marker presence hints
* test(pdf): allow cold startup for pagination process guard
* fix(pdf): key list presence spacer