Releases: Smoren/transferum-ts
Releases · Smoren/transferum-ts
Release list
Sequence Guard, ordered execution, ConditionTransfer cleanup
Sequence Guard for AsyncConvertTransfer and AsyncConditionTransfer
- Bug fix (issue #7): Race condition on
_state.valuewhenmaxConcurrency > 1. Parallel async operations shared a singleProxyReference<T>, so a faster operation could overwrite or clear_state.valuebefore a slower one emitted — subscribers received stale orundefinedvalues, and emissions arrived out of order. - Sequence Guard: When
maxConcurrency > 1, each operation receives a monotonic sequence number. Results are placed into an internalPendingResultQueueand emitted to subscribers strictly in data-arrival order. A faster result waits in the queue until all preceding operations have emitted. WhenmaxConcurrency <= 1, the guard is inactive (zero overhead, backward-compatible). AsyncConditionTransfer.shouldEmitnow receives the operation's localdata: Tinstead of the shared_state.value, eliminating cross-operation data leakage. The_stateis written only at emission time inside the guarded_drain().AsyncConditionTransfer.shouldEmitsignature narrowed from(currentState: T | undefined) => Promise<boolean> | booleanto(data: T) => Promise<boolean> | boolean—undefinedis no longer possible at runtime. Backward-compatible via contravariance (a function acceptingT | undefinedis assignable to a parameter expectingT).AsyncConvertTransferandAsyncConditionTransferdestroy()now clears the pending result queue.- New helper classes (
src/helpers.ts):PendingResultQueue<T>(ordered result queue withnextSeq()/submit()/drain()/clear()) andOrderedExecutor(sequential async task executor withsubmit()/reset()).
Ordered execution for AsyncSinkTransfer and AsyncWriteTransfer
- New config option
ordered?: booleanadded toAsyncSinkTransferConfigandAsyncWriteTransferConfig(default:false, backward-compatible). When enabled,callback/flow.write()invocations are executed sequentially in data-arrival order via an internalOrderedExecutor(promise chain). The chain catches errors per-task so a throwing task does not block subsequent tasks; the error is still propagated to theasyncPushcaller. destroy()on both transfers now resets the executor.
ConditionTransfer cleanup
trigger()method removed fromConditionTransfer. It was not part of any implemented interface (isTriggerablewas never set totrue), and its existence created a race condition:shouldEmitcould receiveundefinedfrom_state.valueafter_state.clear()in a priorpush(). Thepush()method now inlines theshouldEmitcheck directly with the incomingdata: T, makingundefinedimpossible.ConditionTransferConfig.shouldEmitsignature narrowed from(currentState: T | undefined) => booleanto(data: T) => boolean—undefinedis no longer possible at runtime. Backward-compatible via contravariance.- README: Removed
!== undefinedguards fromshouldEmitexamples for bothConditionTransferandAsyncConditionTransfer.
Infrastructure
- API docs generator:
typedocadded as devDependency;npm run docsscript generates API reference todocs/api. - GitHub Actions:
deploy-docs.ymlworkflow added — generates and deploys API docs to GitHub Pages on push tomaster. .gitignore:docsdirectory added.interfaces.ts: UnusedOutputTransferimport removed.
Tests
- Sequence Guard tests: Added race-condition regression tests for
AsyncConvertTransfer(287 tests) andAsyncConditionTransfer(459 tests) — covering parallel ordered emission, stale-result prevention, failed-operation queue advancement, anddestroy()queue cleanup. - Ordered execution tests: Added tests for
AsyncSinkTransfer(264 tests) andAsyncWriteTransfer(284 tests) covering ordered callback/write execution, error isolation, anddestroy()reset. - Helper tests: Added
PendingResultQueue(237 tests) andOrderedExecutor(355 tests) test suites. - ConditionTransfer tests: Removed 3 tests that used
trigger()manually; renamed 2 tests from "trigger" to "shouldEmit" naming; removed!== undefinedguards fromshouldEmitpredicates. - Coverage: Maintained 100% test coverage (statements, branches, functions, lines) across all 11 source files. Total tests: 2,086.
DisplaceTransfer added
DisplaceTransfer — switch-map transfer with onDisplace callback
- New transfer:
DisplaceTransfer<TInput, TOutput, TInner>— for each input value, creates a new inner async-pushable + subscribable transfer via a factory function, pushes the value into it viaasyncPush(), and forwards the inner's emissions to outer subscribers. On each newpush(), the previous inner is unsubscribed and destroyed — only the latest inner's emissions pass through. RxJS equivalent:switchMap. - New factory:
createDisplaceTransfer<TInput, TOutput, TInner>().
Documentation
- README — DisplaceTransfer section: New subsection with capabilities, configuration (including
onDisplace), RxJS equivalent, code example, andonDisplaceusage example with a customFetchTransfer(abort pattern). - README — Comparison tables:
DisplaceTransferadded to Transfer Comparison Table, Transformation category, operator-equivalent coverage (switchMap→DisplaceTransfer), and Gate/Flow control row. - README — Debounced search example: Updated to use
DisplaceTransferinstead ofAsyncConvertTransferdirectly, demonstrating switch-map semantics. - JSDoc:
DisplaceTransferclass andcreateDisplaceTransferfactory fully documented with mechanics, error handling, configuration, and use cases.
Tests
- DisplaceTransfer test suite: 37 tests covering capability flags, basic push & subscribe, displace behavior (cancel previous inner), destroy (dispose inner, clean up subscriptions, idempotent), error handling (factory error with/without
onError, previous inner kept active on factory error), real-world scenarios (fetch, WebSocket, readFile, search-as-you-type), async inner transfers (AsyncConvertTransfer,AsyncConditionTransfer), andonDisplace(called with previous inner, not called on first push/destroy, called before destroy, rapid push, custom cleanup, backward-compatible without callback, exception rethrown but inner still destroyed). - Factory tests: 8 tests for
createDisplaceTransfer(type, push, displace, destroy, error handling, async inner). - Use-case tests: Updated debounced search test to use
DisplaceTransfer; added displacement scenario test (slow query cancelled by fast query). - Coverage: Maintained 100% test coverage (statements, branches, functions, lines) across all 11 source files. Total tests: 2,029.
BridgeSelector and BridgeMultiSelector: syncWithChildren feature added
syncWithChildren for BridgeSelector and BridgeMultiSelector
- New optional config field:
syncWithChildren?: booleanadded toBridgeSelectorConfigandBridgeMultiSelectorConfig(defaultfalse). BridgeSelector: when enabled, the selector subscribes toonStateChange()of all child bridges. External activation of a child bridge switches selection to it (select()). External deactivation of the selected bridge deactivates the selector (deactivate()).BridgeMultiSelector: when enabled, the selector subscribes toonStateChange()of all child bridges. External activation of a child bridge adds it to the selection (check()). External deactivation of a selected child bridge removes it from the selection (uncheck()).- Feedback loop prevention: an internal
_syncingguard suppresses child state-change notifications while the selector is performing its ownactivate()/deactivate()/select()/check()/uncheck(), preventing recursive re-entry. - Cleanup:
destroy()unsubscribes from all child state-change subscriptions before destroying owned bridges. - Backward-compatible:
syncWithChildrendefaults tofalse— existing code behaves exactly as before.
Tests
- Added 11 tests for
BridgeSelectorsyncWithChildren(external activation/deactivation, feedback loop prevention on activate/deactivate/select, disabled mode, no-op cases, inactive selector, destroy unsubscribe, onStateChange notification). - Added 14 tests for
BridgeMultiSelectorsyncWithChildren(external activation/deactivation, feedback loop prevention on activate/deactivate/select/check/uncheck, disabled mode, no-op cases, inactive selector, destroy unsubscribe, onStateChange notification, multiple external activations accumulation). - Coverage: Maintained 100% test coverage (statements, branches, functions, lines) across all 11 source files. Total tests: 1,982.
Documentation updated
Documentation
- README — Comparison section: Removed "Transferum vs Callbag" and "Transferum vs AsyncIterator" subsections, their table of contents entries, their columns from the Quick Comparison Table, and their entries from "When to Consider Alternatives." Neither Callbag (a spec, not a library) nor AsyncIterator (a built-in pull-only protocol) represents a realistic alternative for library selection.
Tests
- No test changes. 100% coverage maintained. Total tests: 1,957.
Documentation improved
Documentation
- README — Tagline: Replaced "A reactive data processing pipeline system for TypeScript" with "A language for describing interactions between components" — describes the essence, not an application.
- README — Graph diagram: Added ASCII graph diagram illustrating transfers as nodes and bridges as edges, with the caption "This is a graph."
- README — Architectural Invariants: Integrated the central philosophical formulation: "Behavior can be described as a composition of independent capabilities that simultaneously determine the type, the implementation, and the rules of interaction."
- README — Audit corrections, verbosity reduction.
- package.json: Description aligned with the new tagline.
Code style
src/transfers.ts: Transfer class definitions reordered for logical grouping —ChannelTransfer,StoredChannelTransfer,PushStoredChannelTransfermoved adjacent toPushChannelTransfer. No functional changes.src/factories.ts:createPushStoredChannelTransferfactory moved adjacent tocreatePushChannelTransfer. Multi-line function signatures collapsed to single lines, trailing commas added for consistency. No functional changes.
Tests
- No test changes. 100% coverage maintained. Total tests: 1,957.
Backpressure support added for some async transfers
Backpressure for async transfers
- New shared config:
BackpressureConfig<T>(maxConcurrency?,bufferSize?,onBufferOverflow?) added toconfigs.ts. - Four async transfers gained backpressure support:
AsyncSinkTransfer,AsyncWriteTransfer,AsyncConvertTransfer,AsyncConditionTransfer. TheirasyncPush()methods now route data through_process()/_dequeue()— limiting concurrent async operations, queuing excess data in an internal buffer, and invokingonBufferOverflow(or silently dropping) when both concurrency and buffer are full. - Backward-compatible: All backpressure options default to
Infinity— existing code behaves exactly as before (unlimited parallel processing, no buffering). destroy()on all four transfers now clears the internal buffer, discarding queued items.
Documentation
- README — Backpressure section: New subsection under Async Transfers documenting
BackpressureConfig<T>options, mechanics, and a usage example. - README — Key Benefits: Added "Built-in backpressure" row.
- README — Async Transfer Comparison Table: Added "BP" (Backpressure) column.
- README — Transfer descriptions: Added backpressure notes to
AsyncSinkTransfer,AsyncWriteTransfer,AsyncConvertTransfer,AsyncConditionTransfer. - README — Configurations: Updated async configs table with
maxConcurrency?,bufferSize?,onBufferOverflow?fields andBackpressureConfig<T>reference.
Tests
- Backpressure tests: Added 8 backpressure test scenarios for each of the 4 async transfers (32 tests total):
maxConcurrencysequential/parallel/default,bufferSizewith/withoutonBufferOverflow, error-frees-slot,destroy()clears buffer. - Coverage: Maintained 100% test coverage (statements, branches, functions, lines) across all 11 source files. Total tests: 1,957.
Added project logo
Documentation
- README: Added project logo.
- README — Monitoring & Alerts: Rewritten example to use
OutputPipelineBuilderwithConditionTransfer→ThrottleTransfer→ConvertTransfer(instead of manualPushChannelTransfer+subscribe). Updated imports and accompanying text.
Example tests
- Domain-specific tests: Synced "Monitoring & Alerts" test with the updated README example — pipeline-based with concrete throttle assertion (1 alert out of ~5 polls).
Documentation fixed
Documentation
- README: Examples fixed and improved.
Example tests
- Use-cases tests: synced with README.
- Domain-specific tests:: synced with README.
- Coverage: Maintained 100% test coverage. Total tests: 1,925.
First stable release
Stable release
First stable release. The public API is now frozen — no breaking changes are planned within the v1.x line.
- Codebase Stability:
v1.0.0(as well asv0.3.1) contains absolutely no changes to thesrc/directory. The API surface is officially confirmed as stable. - API Stability Marker:
v0.3.0finalized the error handling model (ErrorHandler<TSource>,handleError(), per-stage handlers, fail-safe polling).
Documentation
- Comparison Tables: Clarified operator counts by distinguishing pure operators (~10, stateless transforms) from flow-control transfers with explicit lifecycle.
- API Mapping: Added an "Operator-equivalent coverage" row mapping RxJS operators to Transferum transfers (
debounceTime→DebounceTransfer,filter→ConditionTransfer,merge→MergeTransfer,share→SplitTransfer,takeUntil→GateTransfer,delay→DelayedPushChannelTransfer). - Architecture Highlights: Updated the "Quick Comparison Table" with a "Flow-control as nodes" row, highlighting Transferum's transfer-based architecture versus operator-only alternatives.
- Alternative Recommendations: The "When to Consider Alternatives" section for RxJS now lists specific uncovered operators (
combineLatest,zip,withLatestFrom,bufferCount,windowTime,retryWhen) instead of using a generic operator-count argument. - Code Examples:
- Expanded the "Debounced search" code comparison to include realistic error handling (
catchError/onError) and empty-result suppression (secondConditionTransfer/filter). - Added a new code comparison: "Conditional routing with runtime switching" showcasing
BridgeMultiSelectorversus manual RxJS subscription management.
- Expanded the "Debounced search" code comparison to include realistic error handling (
Tests
- Test Suite Alignment: Replaced the "Debounced user input with async validation" test with "Debounced search with error handling and empty-result suppression" to perfectly match the updated README examples, covering API failure recovery and empty-result filtering.
- Fixtures: Added the
SearchResulttype to test fixtures. - Coverage: Maintained 100% test coverage (statements, branches, functions, lines) across all 11 source files with a total of 1,927 tests.
Iterative pre-release
Documentation
- README and keywords updated.