The napi loader resolves wickra-linux-arm64-gnu and
wickra-win32-arm64-msvc, but neither was published, so require('wickra')
failed on those platforms. Adds both to napi.triples and
optionalDependencies, adds their npm/ package templates, and extends the
release node-build matrix to build them on GitHub's native ARM runners
(ubuntu-24.04-arm, windows-11-arm).
The WASM binding had no tests; CI only checked that artefacts existed.
Adds a wasm-bindgen-test suite covering SMA reference values, EMA
batch==streaming equivalence, RSI pure-uptrend behaviour, fallible
constructors returning JsError, and the unequal-length batch guards from
B3. Wires wasm-pack test --node into the CI wasm job. The suite
type-checks on the host; it executes under wasm-pack in CI (the local
environment is a non-rustup Rust install without the wasm32 target).
The Releases page previously showed only the source archives GitHub
auto-generates for every tag. Add an explicit github-release job that
runs after every publish job finishes, downloads every uploaded
artefact, and attaches them all to the release.
New per-publish-job upload-artifact additions:
- cargo-publish: 'cargo package' each crate and upload the .crate files
- wasm-publish: 'npm pack' inside pkg/ and upload the wickra-wasm tgz
- node-publish: 'npm pack' the main package + each per-platform subpackage,
upload all six tgz files (main + linux + 2*darwin + win32)
Wheels and .node binaries were already being uploaded earlier in the
matrix builds, so the new job just consumes them via download-artifact.
github-release job:
- Runs on tag pushes (normal) AND workflow_dispatch (so we can backfill
assets to an existing release without rebumping the version).
- Resolves the target tag from github.ref on a tag push, or from
'git tag --sort=-v:refname | head' on dispatch.
- Stages all files into release-assets/, uses softprops/action-gh-release
to create or update the release. generate_release_notes lets GitHub
fill in the commit-list changelog automatically.
The Windows Node 18 and Node 20 CI jobs failed because:
- ci.yml ran 'napi build --release' (no --platform), which produces a
filename without the target triple ('wickra.node').
- The committed loader at bindings/node/index.js looked for the
triple-suffixed file ('wickra.win32-x64-msvc.node') and then for the
per-platform npm subpackage as a fallback.
- 'wickra-win32-x64-msvc' isn't on npm yet (blocked by the spam filter),
so Windows had nothing to load. Linux and macOS passed only because
their optionalDependencies do exist on npm and got fetched.
Two-part fix:
- ci.yml now runs 'napi build --platform --release', matching release.yml.
--platform encodes the target triple in the filename, so the loader's
primary lookup always finds the freshly built binary on every host.
- bindings/node/index.js is now the canonical napi-rs auto-generated
loader (it gets regenerated by 'napi build'). It covers all the platforms
napi knows about (linux glibc/musl, Android, FreeBSD, ARM, etc.) rather
than just the four we publish, so unsupported platforms get a clear
'this binding isn't built for your system' error instead of a confusing
ENOENT.
Local sanity: 'npx napi build --platform --release' then 'node --test
__tests__/' succeeds end to end on Windows; the eight existing tests
pass.
The root cause of the previous failure was the package.json
"prepublishOnly": "napi prepublish -t npm" script. When the workflow
ran `npm publish` for the main wickra package it implicitly invoked
that hook, which re-attempted to publish every platform subpackage and
hit 403 "cannot publish over 0.1.2" because they were already on
the registry. The error trail looked like it came from the main
publish step but the failing command was actually the hook.
Two-part fix:
- Remove prepublishOnly entirely from bindings/node/package.json. The
release workflow already does the per-platform publish itself, in a
loop, idempotently.
- Belt-and-braces: pass --ignore-scripts when publishing the main
package so any prepublish-hook drift in the future is suppressed.
GitHub Actions runs shell steps with bash -e, so when npm view wickra@<v>
returned exit 1 (because the package was not yet on the registry) the
whole step aborted before reaching npm publish. Switch the step to
`set +e` and capture the rc explicitly, so a 404 from npm view is
treated as 'not published yet, go publish' instead of a fatal error.
Also adds a single retry after 30s for spam-filter blocks.
The previous 'napi prepublish -t npm' step was atomic — one failure killed
the whole step, and on retry it tried to republish already-uploaded
versions which 403'd. v0.1.2 left 3 of 4 platform packages and the wasm
package on npm but the main 'wickra' package and 'wickra-win32-x64-msvc'
never got out.
Replace it with a small bash loop that:
- Walks every npm/<platform>/ directory.
- Skips the publish if 'npm view <pkg>@<version>' confirms the version
is already on the registry (idempotent re-runs).
- Tolerates per-package failures (sets rc but always returns 0 from the
helper) so spam-filter blocks on one platform don't take down the
others. A 30-second retry handles transient rate-limit spam blocks.
- Publishes the main 'wickra' meta-package as a separate step with the
same skip-existing guard.
Same publishing semantics, just deconstructed into individually
recoverable steps.
`napi create-npm-dir` failed in CI with both invocations we tried:
positional arg form (`-t <triple> .`) was rejected as extraneous,
and the no-arg form crashed with "path must be a string, received
undefined". The fix used by every napi-rs reference project: commit
the four platform package.json templates directly under
bindings/node/npm/<target>/ instead of generating them at publish time.
- bindings/node/npm/{linux-x64-gnu,darwin-x64,darwin-arm64,win32-x64-msvc}/
each contain a static package.json with the correct os / cpu / libc
filters so npm only installs the right binary per platform.
- Main package.json gains optionalDependencies referencing all four
platform packages by version, so `npm install wickra` pulls the
matching binary on each user's machine.
- Release workflow drops the broken `create-npm-dir` loop. The
`napi artifacts` step now just copies the .node files from the
build artefacts into the existing npm/ directories before publish.
Bump every version to 0.1.2; cargo / pypi / wickra-wasm jobs are
idempotent so they accept the 0.1.1 they already published while still
emitting the new 0.1.2.
v0.1.0 reached crates.io, PyPI, and the wickra-wasm npm package, but
the wickra Node binding never published because the workflow called
`napi create-npm-dirs` (plural). The actual napi CLI command is
`create-npm-dir` (singular, per target).
Changes that make the next tag's release actually finish:
- workflow: replace the broken step with a loop that runs
`napi create-npm-dir -t <triple>` for each of our four build targets.
- workflow: every registry publish step now treats "version already
uploaded" as success. That makes re-runs (and partial-failure
recoveries) safe instead of failing the whole job.
- bindings/node/package.json: trim the napi.triples list to the four
platforms we actually build (linux-x64-gnu, darwin-x64, darwin-arm64,
win32-x64-msvc). The previous defaults+9-extras configuration would
have made napi prepublish expect platform packages we never produced.
- bindings/node/index.js: switch from local-only binary lookup to the
proper napi loader that tries the local `.node` file first and falls
back to the per-platform npm subpackage that's installed as an
optional dependency in production.
- Versions across all four published packages bumped to 0.1.1 so the
Node binding can publish for the first time alongside refreshed
cargo/pypi/wasm artefacts.
Three blockers surfaced when the first tag actually ran the pipeline:
1. PyPI sdist build refused the `readme = "../../README.md"` path
in bindings/python/pyproject.toml. maturin sdist forbids `..`
inside archive entries. Solution: add a Python-specific README at
bindings/python/README.md (covers the Python install + pointers to
the main repo) and point the project.readme key at the local file.
2. Node publish job hit ENOENT on npm/<platform>/wickra.<...>.node
because napi's per-platform scaffolding directories did not exist
yet when `napi artifacts` ran. Insert `napi create-npm-dirs` as
its own step before `napi artifacts` so the platform package layout
is in place before binaries get moved into it.
3. and 4. (crates.io email + npm 2FA-bypass) are registry-side account
settings that have to be done in the user's browser; no code change
needed for those. They'll be sorted before the next tag push.
On every v* tag push the release workflow now publishes the project to
all three public registries in parallel:
- crates.io: wickra-core then wickra-data then wickra, with a 45-second
sleep between each so the registry index can refresh before the next
publish step asserts the previous version is available.
- PyPI: maturin-action builds wheels for Linux x86_64 + aarch64, macOS
x86_64 + aarch64, and Windows x64, plus an sdist; all artefacts upload
to PyPI via MATURIN_PYPI_TOKEN.
- npm: napi-rs builds a native binary per platform (linux-x64-gnu,
darwin-x64, darwin-arm64, win32-x64-msvc), publishes each as its own
platform package, then publishes the main `wickra` meta-package
that resolves to the right platform at install time.
- WASM: wasm-pack builds the bundler-target package and publishes it as
`wickra-wasm` on npm, with the auto-generated package.json enriched
with the author/repo/license metadata.
Package metadata was unified so all targets point at kingchenc/wickra
on GitHub; the Node binding is now plain `wickra` (the @wickra/ scope
was unnecessary because the bare name was free). README install table
updated to match.
Two unrelated failures in the post-release CI run:
- Python jobs: `maturin develop` requires an activated virtualenv on
CI runners that don't have a system Python set up that way. Switch
to `maturin build --release --out dist` followed by `pip install
--find-links dist`, which is venv-agnostic and OS-portable.
- WASM job: the wasm-opt bundled with wasm-pack is older than the WASM
features rustc 1.92 enables by default. The fix is to opt every feature
in explicitly via the package metadata — reference-types, multivalue,
bulk-memory, sign-ext, mutable-globals, nontrapping-float-to-int — so
wasm-opt accepts the input.
Same code as before; only the build steps and the wasm-opt config changed.
A multi-language technical analysis library: 25 indicators across trend,
momentum, volatility, and volume families, every one a state machine with
O(1) per-tick updates. Batch evaluation is provided by a blanket extension
trait over the streaming primitive, so live trading bots and historical
backtests run the same code path.
What ships in this initial drop:
crates/wickra-core - 25 indicators, Indicator/BatchExt/Chain traits,
OHLCV types with validation; 171 unit tests,
property tests, Wilder/Bollinger textbook tests.
crates/wickra - top-level facade + criterion benches for every
indicator at 1K/10K/100K series sizes.
crates/wickra-data - streaming CSV reader, tick-to-candle aggregator,
multi-timeframe resampler, Binance Spot kline
WebSocket adapter behind feature live-binance;
11 unit + 1 doctest.
bindings/python - PyO3 + maturin, NumPy I/O, type stubs (.pyi),
56 pytest tests including streaming==batch
equivalence, Wilder reference values, lifecycle.
bindings/node - napi-rs native module, TypeScript .d.ts
auto-generated, 7 node --test cases.
bindings/wasm - wasm-bindgen ES module for browser/bundler/Node;
interactive HTML demo at examples/index.html.
examples/ - Python and Rust scripts: backtest, live trading,
parallel multi-asset, multi-timeframe, Binance.
benchmarks/ - cross-library comparison against TA-Lib,
pandas-ta, finta, talipp; Wickra wins every
category by 11-1030x (batch) and 17x+ streaming.
.github/workflows/ - CI matrix (Rust + Python + Node + WASM on
Linux/macOS/Windows), release pipeline for
PyPI wheels and npm.
Indicators (25):
Trend SMA EMA WMA DEMA TEMA HMA KAMA
Momentum RSI MACD Stochastic CCI ROC WilliamsR ADX MFI TRIX
AwesomeOscillator Aroon
Volatility BollingerBands ATR Keltner Donchian PSAR
Volume OBV VWAP (cumulative + rolling)
cargo clippy --workspace --all-targets -D warnings is clean. License: Apache-2.0.