Skip to content

Conversation

@Robdel12
Copy link
Contributor

@Robdel12 Robdel12 commented Jan 7, 2026

Summary

  • Client SDK now sends type field ('base64' or 'file-path') with screenshot requests
  • Server uses explicit type when provided, skipping O(n) detection entirely
  • Fallback detection optimized with length check (strings > 2KB cannot be file paths)
  • Fixed looksLikeFilePath to not false-positive on JPEG base64 (which starts with /9j/)

Problem

For large full-page screenshots (multi-megabyte base64 strings), the detectImageInputType function was running expensive O(n) regex validation on every screenshot. This caused noticeable slowdowns, especially for content-heavy pages like blog indexes and changelogs.

Solution

  1. Explicit type from SDK (zero cost): The SDK already knows whether it's sending base64 or a file path, so it now tells the server explicitly
  2. Optimized fallback: For backwards compatibility with old clients, detection now bails early on large strings (file paths are always < 2KB)

Test plan

  • All existing tests pass
  • Verified detection still works correctly for file paths and base64
  • Backwards compatible - old clients without type field still work

- Client SDK now sends 'type' field ('base64' or 'file-path')
- Server uses explicit type, skipping O(n) detection entirely
- Fallback detection optimized with length check (> 2KB = not a path)
- Fixed looksLikeFilePath to not false-positive on JPEG base64 (/9j/...)

This eliminates expensive regex validation on multi-megabyte screenshots.
@Robdel12 Robdel12 force-pushed the perf/explicit-image-type branch from 760d73a to 6b640f2 Compare January 7, 2026 01:50
@claude
Copy link

claude bot commented Jan 7, 2026

Pull Request Review

Overview

This PR introduces a smart performance optimization by having the client SDK explicitly declare the image type ('base64' or 'file-path'), eliminating expensive O(n) regex validation on large screenshot buffers. The optimization is well-designed with proper fallback for backwards compatibility.


✅ Strengths

1. Performance Optimization

  • The fast-path approach (explicit type from SDK) completely eliminates detection overhead
  • Length-based early bailout (2KB threshold in looksLikeFilePath, 1KB threshold in detectImageInputType) is smart and makes detection O(1) for large base64 strings
  • The performance gains will be most noticeable for large full-page screenshots (multi-megabyte base64)

2. Backwards Compatibility

  • Fallback detection ensures old clients without type field continue working
  • The optimized detection still handles edge cases properly

3. Code Quality

  • Clear comments explaining the optimization strategy
  • JPEG base64 false-positive bug fix (/9j/ pattern) is a valuable improvement
  • Logical ordering of checks (data URI → file patterns → length check → full validation)

⚠️ Issues & Concerns

1. Critical: Missing Test Coverage for New Functionality

The new type parameter is added to the client SDK and flows through the entire stack, but there are no tests verifying:

  • Client SDK sends the correct type value for file paths vs base64
  • Server handlers respect the explicit type parameter
  • Backwards compatibility when type is undefined/null

Test files to update:

  • tests/server/routers/screenshot.test.js (line 129-142): Add test cases with explicit type: 'base64' and type: 'file-path'
  • tests/server/handlers/tdd-handler.test.js: Verify handler uses explicit type when provided
  • tests/server/handlers/api-handler.test.js: Same verification needed
  • tests/utils/image-input-detector.test.js: Add tests for large strings (>1000 chars) to verify the length optimization works

2. Inconsistent Length Thresholds

The codebase uses different thresholds without clear justification:

  • looksLikeFilePath: str.length > 2000 → returns false
  • detectImageInputType: str.length > 1000 → assumes base64

Why this matters: A string of 1500 characters would:

  1. Pass through looksLikeFilePath early bailout (1500 < 2000)
  2. Not trigger the length optimization in detectImageInputType (1500 > 1000)
  3. Still run expensive isBase64 validation

Recommendation: Use consistent threshold (1000 for both) or add a comment explaining why they differ.

3. Potential Edge Case: Malformed type Parameter

The code uses: const inputType = type || detectImageInputType(image);

This means type: 'invalid-value' would pass through to file reading logic without validation.

Recommendation: Validate the type parameter or document that invalid types are intentionally handled downstream.


🔒 Security Considerations

No new security concerns - The changes don't introduce vulnerabilities:

  • File path validation remains in place
  • No new user input parsing beyond the type parameter
  • Explicit type actually reduces attack surface by skipping regex validation

📊 Performance Considerations

Excellent performance improvement:

  • Large screenshots (>1KB): O(n) → O(1) when type is explicit
  • Large screenshots (>1KB): O(n) → O(1) even with fallback detection (length check)
  • Small strings (<1KB): Minimal change, still runs full validation

Real-world impact:

  • Multi-megabyte screenshots: Could save 10-100ms per screenshot
  • High-frequency test suites: Savings multiply across hundreds of screenshots

🎯 Recommendations Summary

Must fix before merge:

  1. Add test coverage for the new type parameter throughout the stack
  2. Add tests for the length optimization (large strings)
  3. Add test for JPEG base64 false-positive fix

Should fix before merge:
4. Align length thresholds (1000 vs 2000) or document reasoning
5. Add input validation for the type parameter

Nice to have:
6. Add JSDoc documentation for the new parameter
7. Add a benchmark test demonstrating the performance improvement


🏁 Conclusion

This is a high-quality optimization that addresses a real performance bottleneck with minimal code changes. The implementation is sound and backwards-compatible. However, the lack of test coverage for the core feature is a significant gap that must be addressed before merging.

With the recommended test additions and minor tweaks, this PR will be ready to ship.

Suggested next steps:

  1. Add the missing test cases
  2. Address the threshold inconsistency
  3. Run the full test suite to ensure no regressions
  4. Merge with confidence ✨

- Add tests for type parameter in router, tdd-handler, api-handler
- Add tests for length optimization and JPEG base64 edge case
- Align length thresholds to 1000 (was inconsistent 1000 vs 2000)
- Add validation for type parameter (invalid values fall back to detection)
@Robdel12 Robdel12 enabled auto-merge (squash) January 7, 2026 02:13
@Robdel12 Robdel12 merged commit 235dd65 into main Jan 7, 2026
36 of 41 checks passed
@Robdel12 Robdel12 deleted the perf/explicit-image-type branch January 7, 2026 02:14
Robdel12 added a commit that referenced this pull request Jan 7, 2026
## Summary

Adds the `type` field to all SDK clients that send screenshot image
data. This completes the performance optimization from #174 by ensuring
all clients benefit from O(1) type detection on the server.

## Changes

| SDK | File | Type Sent |
|-----|------|-----------|
| Full SDK | `src/sdk/index.js` | `type: 'base64'` |
| Vitest | `clients/vitest/src/setup.js` | `type: 'file-path'` |
| Ruby | `clients/ruby/lib/vizzly.rb` | `type: 'base64'` |
| Swift | `clients/swift/.../VizzlyClient.swift` | `type: 'base64'` |

**No changes needed:**
- **Core client** (`src/client/index.js`) - Already updated in #174
- **Static-site** - Uses core client SDK
- **Storybook** - Uses core client SDK
- **Ember** - Different architecture (sends selector, server takes
screenshot)

## Packages to Release

After merging, the following packages need new releases:

| Package | Registry | Notes |
|---------|----------|-------|
| `@vizzly-testing/cli` | npm | Main CLI package |
| `@vizzly-testing/vitest` | npm | Vitest plugin |
| `vizzly` | RubyGems | Ruby gem |
| `Vizzly` | Swift Package Manager | Swift package |

## Test Plan

- [x] All 1751 tests pass
- [x] Backwards compatible (server falls back to detection if `type`
missing)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants