feat: Python and Node bindings (v1: conversion)#24
Merged
Conversation
- README.md: leaner, ~265 lines (was ~615). Drops marketing comparison table and inline 32-row spec list; foregrounds operator console as the real differentiator vs Gotenberg; calls out deliberate gaps (TLS, RBAC) and empty placeholders explicitly. - comparison.md (new, root): in-depth audit vs Gotenberg in 16 sections — endpoint matrix, per-engine feature tables, what-we-did / didn't-do / shouldn't-do scorecards. - docs/markdown-plus.md (new): design proposal for an enhanced Markdown route (front-matter, math, mermaid, syntax highlighting, includes, themes). Sits alongside the basic markdown route, not a replacement. - docs/specs/ → docs/specs-archive-2026-05-01.zip. 32 legacy spec files archived; fresh contributor-facing specs will be re-introduced under docs/ in better-organised form. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v1 ships HTML/URL/Markdown/Office to PDF for Python (sync Folio + async AsyncFolio) and Node (async). Chrome auto-download lives in a new engine::chrome_fetch module so the CLI/server can opt in later. v2 (full parity: screenshots + PDF ops) is fully specified and deferred. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Plan covers chrome_fetch module, PyO3 sync+async Folio, napi-rs async Folio, maturin/napi-rs packaging, smoke + E2E tests, CI matrix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the chrome-fetch feature to the engine crate, wiring optional deps (reqwest, sha2, zip, flate2, tar, dirs) and a skeleton chrome_fetch module with stub submodules ready for Tasks 2-4 to implement. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements detect_system_chrome() with a testable detect_with() helper that accepts injectable env vars, path lookup, and exists functions. Adds minimal placeholders for cache.rs and download.rs (Tasks 3 & 4) and adds missing doc comments to EnsureOptions fields to satisfy the crate-level missing_docs deny lint. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the Task-4 placeholder with the real Chrome-for-Testing downloader: fetches the per-version manifest, streams the zip archive, extracts atomically via a .partial staging dir → rename, and chmod 755s chrome binaries on unix. walkdir added as optional dep gated behind the chrome-fetch feature. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements Task 5: PyO3 _native module with sync Folio class, error hierarchy mapped from EngineError, tokio runtime singleton, and JSON round-trip for engine option types via serde_json. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire up bindings/python/ as a maturin mixed project: pyproject.toml targets crates/py, folio/__init__.py re-exports all public symbols from _native, and tests/test_smoke.py verifies 3 structural checks (exports, error hierarchy, class methods) without launching Chrome. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implement AsyncFolio using pyo3-async-runtimes 0.22.0 (matched to PyO3 0.22 workspace dep). Engine futures are bridged to the caller's running event loop via `future_into_py`; the tokio runtime builder is registered in `_native` init. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements Task 8: napi-rs cdylib with async Folio class exposing html_to_pdf, url_to_pdf, markdown_to_pdf, office_to_pdf, and close. Error tagging convention ([Tag] prefix) wires into Task 9 JS loader. Also adds tokio_rt/serde-json features and napi-build to workspace deps. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds bindings/node with package.json (@folio/folio), a hand-written index.js that wraps the napi-rs native loader (_native.js) with typed error subclasses (FolioError hierarchy), TypeScript declarations, and 4 vitest smoke tests that all pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
af27fb9
into
spec/operator-console
11 of 17 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
folioPyPI) and Node.js (@folio/folionpm) bindings that drive Folio in-process — no HTTP server, no Docker.engine::chrome_fetchmodule detects system Chrome or downloads a pinned Chrome-for-Testing build into a platform cache on first use.Spec & plan
+ "docs/superpowers/specs/2026-05-01-bindings-design.md" ++ "docs/superpowers/plans/2026-05-01-bindings.md" +(12 TDD tasks)What changed
+ "engine::chrome_fetch" +(detect / cache / download)+ "crates/py" +(PyO3, sync+ "Folio" ++ async+ "AsyncFolio" +, abi3-py38)+ "bindings/python" +(maturin)+ "crates/js" +(napi-rs async+ "Folio" +)+ "bindings/node" +(npm)+ "FOLIO_E2E=1" +)+ "bindings/README.md" +Test plan
+ "pip install" +the wheel on a clean machine without Chrome →+ "Folio().html_to_pdf(...)" +produces a valid PDF (auto-download path)+ "npm install && Folio.create()" +then+ "htmlToPdf" ++ "bindings-python" +→+ "e2e" +job via workflow_dispatch and confirm pass+ "bindings-node" +→+ "e2e" +job via workflow_dispatch and confirm pass🤖 Generated with Claude Code