* feat: v2.1.0 — fal platform utilities (async fan-out, cost tools, recovery)
Six new nodes under FAL/Platform, built on fal's queue/request-id/pricing
primitives:
- Fal Submit + Fal Collect: queue jobs without blocking and collect
results later — N generations run in parallel inside one graph
- Fal Result by Request ID: re-fetch any past generation from fal's
queue without re-generating or re-billing
- Fal Cost Estimator: per-run cost report parsed from registry pricing
before anything is queued
- Fal Session Costs: in-memory ledger of every fal call this session
(endpoint, duration, request id, est. cost) with running total
- Fal Save Media from URL: persist expiring CDN results into the
ComfyUI output directory
Core: utils/pricing.py (pricing-text parser + registry lookup),
utils/ledger.py (thread-safe session ledger), api.py gains submit_only,
result_from_request_id, request-id capture via on_enqueue, and
automatic ledger recording; any_endpoint helpers extracted for reuse.
16 new tests (61 total).
* feat: v2.2.0 — persistent result cache, spend guard, URL passthrough
Three fal-platform features on top of the 2.1 platform pack:
- Persistent result cache (sqlite, [cache] config): identical fal calls
are served free from disk across ComfyUI restarts; uploads are
deduplicated by content hash so identical inputs upload once. Bypass
per node via force_rerun. Cache hits are never blocked by the spend
guard and never recorded as spend.
- Spend Guard + billing ([spend_guard] config): preflight refuses to
submit once the session's estimated spend reaches session_budget_usd
or the account balance (fal Billing API) falls below min_balance_usd.
New Fal Account Balance node; ledger reconciliation against the
aggregated usage API (fal exposes no per-request billed amounts).
- fal-CDN URL passthrough: every dynamic node's media inputs gain
optional *_direct_url twins (URL sent directly, no download/re-upload;
1,405 twins across 992 nodes) and image-kind nodes output image_urls
alongside IMAGE — fal→fal chains with zero local I/O.
Review fixes: path traversal blocked in FalSaveMediaURL (confined to the
output dir, atomic O_EXCL filename claim), FalAnyEndpoint force_rerun now
bypasses the cache, cache lookup ordered before spend-guard preflight,
result recovery no longer counts as new session spend.
14 new tests (76 total).
Auto-generated nodes for the entire live fal catalog (1,391 models →
1,482 total nodes) built at startup from a committed registry, plus a
full rewrite of the core layer. All 87 v1 node keys, inputs and outputs
are preserved — existing workflows load and run unchanged.
New:
- data/fal_registry.json + scripts/build_registry.py: distills fal's
catalog and per-endpoint OpenAPI schemas into a deterministic registry
- nodes/dynamic/: schema→node factory (typed widgets, tooltips, pricing
in node help, IMAGE/VIDEO/AUDIO auto-upload, native VIDEO/AUDIO
outputs, seed -1=random, force_rerun), plus a generic Fal Any Endpoint
node for arbitrary endpoints
- nodes/utils/: rewritten core — FalApiError surfacing fal's real error
payloads, queue progress logs, ComfyUI cancel support, retries and
timeouts everywhere, parallel uploads/downloads, structured logging
- tests/ (45 tests incl. a legacy-key snapshot lock), CI lint+test
workflow, weekly registry-refresh workflow that opens a PR on changes
- README regenerated from the registry (scripts/build_readme.py)
Fixed:
- GPTImage2 / GPTImage2Edit were defined but never registered
- Topaz video upscale sent a nonexistent API field (desired_increase)
- SeedVR video upscaler had its error handling commented out + wrong
model label; ProRes enum value mismatch translated at argument level
- 10x `is ""` comparisons, bare excepts, missing HTTP timeouts,
temp-file leaks, fps=0 crash in LoadVideoURL, duplicate enum entry
- opencv-python & friends missing from pyproject (Registry installs)
- API failures now raise visible errors instead of silently returning
blank images or "Error:" strings that downstream nodes tried to load
BREAKING (behavioral only): failed API calls raise instead of returning
blank/black images or error strings. Node signatures are unchanged.