* fix(schemas): edit split MVT form chunks
* fix(uiRender): set height to 100% for styled text container
* fix(snapshots): set height to 100% for text elements in Designer and Preview snapshots
Adds inline markdown links, URI scheme allowlisting, basePdf URI link preservation, internal #schemaName PDF links, and planning notes for @pdfme/jsx/md2pdf.
* docs: add list schema implementation plan
* feat(schemas): add list schema
* fix(schemas): improve list form editing
* fix(schemas): localize list editing labels
* fix(schemas): align table control buttons
* fix(schemas): keep list designer editing during actions
* fix(tsconfig): resolve list schema subpath
* fix(schemas): keep list action clicks isolated
* fix(schemas): support empty list state
* fix(schemas): allow editing list items in designer
* fix(schemas): keep list designer editing on enter
* fix(schemas): ignore IME enter in list editor
* fix(schemas): make enter insert list item line breaks
* test(generator): add list plugin to playground snapshots
* refactor(schemas): render list items with text ui
* fix(schemas): adapt list prop panel fields by style
* fix(schemas): simplify list options and nested numbering
* Reorder import statements in generate-templates-thumbnail
* Reorder List plugin in getPlugins function
* fix(ui): reflow schemas after dynamic list resize
* chore: remove obsolete list plan
* fix(ui): reflow form list height changes
* fix(ui): keep designer height changes local
* fix(schemas): commit list item line breaks immediately
* fix(schemas): restore list focus after line break rerender
* fix(schemas): keep form list focused after enter
* test(generator): update dynamic list snapshots
* fix(schemas): store list content as json arrays
* fix(schemas): address list review cleanup
* test(ui): update designer snapshot
* chore: trim list pr noise
* fix(schemas): align list markers in ui
* fix: two unbounded-cache memory leaks in common and schemas
Two module-level Map caches that never evict and store multi-MB strings
as keys, silently leaking for the entire lifetime of any consumer.
1. packages/common/src/expression.ts — parseDataCache
parseData() was memoized via a module-level parseDataCache keyed by
JSON.stringify(data). replacePlaceholders() calls it with a merged
{ ...schemaNameDefaults, ...variables } object where values may be
arbitrary strings from the caller. Whenever inputs contain base64
(image schemas with embedded data URLs, embedded fonts, large text),
the cache key is a multi-MB JSON string that gets pinned permanently;
every unique inputs state adds its own key, never collected. Parsing
is O(fields) and cheap, so removing the cache is strictly a win.
Regression test: packages/common/__tests__/expression.test.ts
'replacePlaceholders memory safety > does not retain call inputs in
a module-level cache' — runs 30 replacePlaceholders() calls with
unique ~500 KB payloads, captures a V8 heap snapshot via
v8.writeHeapSnapshot, aggregates string nodes >= 200 KB and asserts
the total retained size is below 2 MB. Pre-fix: ~30 MB retained
(FAILS). Post-fix: 0 bytes retained (passes).
2. packages/schemas/src/graphics/image.ts — getCacheKey
getCacheKey(schema, input) returned `${schema.type}${input}`, using
the full base64 bytes of the image as part of the cache key. Every
unique image processed by the PDF render path added a permanent Map
entry whose key byte length matched the image itself.
Replaced with a short fingerprint that samples the total length plus
three 16-char regions (first, middle, last). The middle-region
sample is essential: base64 PNGs share a common header and IEND
trailer, so distinct images of the same size would collide if only
first/last regions were sampled. Middle bytes are pixel data and
differ between distinct images with overwhelming probability. Keys
stay under 80 chars regardless of input size.
Regression tests: packages/schemas/__tests__/image.test.ts
- 'does not pin the full base64 input as a cache key' — asserts
key length < 100 chars. Pre-fix: 139 chars for a minimal PNG and
proportionally more for realistic images (FAILS).
- 'distinguishes different images via the fingerprint' — guards
against future over-shortening of the fingerprint that could
reintroduce collisions between distinct images.
Both leaks were originally identified via a V8 heap-snapshot diff taken
across a UI workload (typing + field tabbing) against a consumer app
with image schemas carrying base64 content. Before the fix, the top two
growing allocations by retained size were multi-MB string entries — one
per module-level cache in this PR — together accounting for hundreds of
MB of retained JS heap in a single 3-iteration run. After the fix, both
string entries disappear from the top 25 growing allocations and
aggregate JS heap is net flat / slightly shrinking across iterations.
No public API change. No behavioral change for consumers. Both caches
were module-local implementation details.
* fix(schemas): harden image cache key with FNV-1a hash; fix stale test comments
Addresses Greptile review on #1426:
- Replace 3-region sampling fingerprint in getCacheKey with an FNV-1a
32-bit hash over the full input. The old first-16 slice was a
constant data-URI prefix for any image of the same MIME type,
contributing no entropy; hashing every byte removes that weakness
at the same O(n) cost without retaining any slice as a Map key.
Key format is now `${type}:${len}:${fnv1a-hex}` (~40 chars).
- Rewrite stale comments in image.test.ts that referred to a
padding/mutation scheme the test never performs, and update the
fingerprint-format comment to match the new hash-based key.
- Add trailing newline to expression.test.ts.
All pre-existing and new tests still pass.
* fix(ui): prevent focus loss on schema name input
Exclude name from the live handleWatch update path to prevent the sidebar from re-rendering on every keystroke. The name field will now only be updated on blur/Enter instead.
* fix(ui): add onBlur handler to persist schema name changes
Added onBlur handler to schema name field to persist changes when field loses focus, while keeping the exclusion of 'name' from handleWatch to prevent focus loss during typing.
* fix(ui): refactor form handling and update schema name validation logic
---------
Co-authored-by: bobo-xxx <111567133+bobo-xxx@users.noreply.github.com>