Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
149 commits
Select commit Hold shift + click to select a range
d0b9847
chore: workspace + Changesets bootstrap (T-2)
ignromanov May 19, 2026
31b7868
feat(types): package skeleton — TS type declarations (T-4)
ignromanov May 19, 2026
5d4388f
feat(networks): package skeleton — 5 EVM chain configs (no RPC keys) …
ignromanov May 19, 2026
1de5be5
feat(codec): package skeleton — Rust hello-world + wasm-pack manifest…
ignromanov May 19, 2026
969e5f8
ci: Phase 1 scaffold — release.yml LOCKED filename + ci.yml + dependa…
ignromanov May 19, 2026
7384373
docs: Phase 1 documentation foundation — README + CoC + SECURITY + ar…
ignromanov May 19, 2026
f064665
lint: scaffold ESLint 9 flat + Prettier + clippy + rustfmt (T-7)
ignromanov May 19, 2026
53f43ac
chore: persist ESLint deps in package.json + lockfile (T-7 follow-up)
ignromanov May 19, 2026
ae692e6
chore(codec): bump to 0.0.1 for crates.io name reservation
ignromanov May 19, 2026
deebae5
spike(brotli): measure compression + WASM blob — B-i ruled out, B-iv …
ignromanov May 20, 2026
80860e3
spike(bigint): WASM<->JS boundary failure-mode + regression test (D-B11)
ignromanov May 20, 2026
2e1179f
deps(codec): lock Phase 2 dependency set (T-P2-1)
ignromanov May 20, 2026
2cea71e
fix(codec): drop redundant js_sys import — clippy single-component-pa…
ignromanov May 20, 2026
6e7c597
feat(codec): CodecError 9-variant error enum (T-P2-2)
ignromanov May 20, 2026
76cc793
feat(codec): LEB128 varint primitive, MAX_BYTES=37 (T-P2-3)
ignromanov May 20, 2026
74100d0
fix(codec): drop guarded unwrap in shr7_le — AC-15 no-unwrap discipli…
ignromanov May 20, 2026
c3a8acc
feat(codec): TLV record primitives, BTreeMap byte-stable (T-P2-4)
ignromanov May 20, 2026
ec17a0e
feat(codec): phf static dictionaries app + chain (T-P2-5)
ignromanov May 20, 2026
00f1feb
test(codec): lock dictionary snapshot hashes (T-P2-5)
ignromanov May 20, 2026
c19d645
feat(codec): keccak256 content-hash primitive (T-P2-6)
ignromanov May 20, 2026
6f9d0a1
chore(codec): drop brotli-decompressor dep — B-iv superseded by B-v r…
ignromanov May 20, 2026
7759eb3
fix(codec): resolve clippy::format_collect warnings in proptest helpers
ignromanov May 20, 2026
2b69236
feat(codec): B-v canonical encode/decode WASM layer (T-P2-7-alt)
ignromanov May 20, 2026
ba52e5b
refactor(codec): drop tsify + serde_json from production deps
ignromanov May 20, 2026
a1e6753
feat(codec): B-v JS shim — wire encode/decode over brotli-wasm (T-P2-…
ignromanov May 20, 2026
f51851c
style(codec): cargo fmt — resolve fmt --check CI gate (Iris Gate A2)
ignromanov May 20, 2026
575517d
feat(codec): bridge receiptHash JS export (T-P2-9b)
ignromanov May 20, 2026
1cf710d
fix(codec): make proptest target-conditional — unblock wasm-pack test…
ignromanov May 20, 2026
71a2a93
fix(codec): wasm_boundary.rs calls compute_content_hash directly (T-P…
ignromanov May 20, 2026
56e9845
fix(ci): install wasm-pack in lint-and-build job
ignromanov May 20, 2026
616ccb4
feat(codec): widen amount domain u128 -> U256 (T-P2-12a)
ignromanov May 20, 2026
e7b0340
feat(codec): 17 golden vectors v4-codec.json (T-P2-12, schema_version=1)
ignromanov May 20, 2026
57440dd
fix(codec): correct malformed vector set + pnpm-lock straggler (T-P2-…
ignromanov May 20, 2026
0088201
test(codec): golden-vector parity test — Rust + TS surfaces (T-P2-13)
ignromanov May 20, 2026
4f7d482
ci(codec): gzip size-gate + wasm-node test job (T-P2-14)
ignromanov May 20, 2026
2cf3ba8
chore(codec): bundle-budget + hygiene + version 0.1.0 — Phase 2 exit …
ignromanov May 20, 2026
9dba355
fix(codec): Gate B hotfix batch — coverage scope, version lockstep, l…
ignromanov May 21, 2026
9dd044d
chore(codec): publish-prep — release.yml OIDC job, per-pkg LICENSE, p…
ignromanov May 21, 2026
ae826f5
ci(codec): SHA-pin release.yml actions + replace wasm-pack curl-pipe …
ignromanov May 21, 2026
0d9acf6
feat(types): add Invoice type + real vitest suite (PR#7 fix batch)
ignromanov May 21, 2026
c3d49f3
feat(networks): real vitest suite + @alpha token stub + lint script (…
ignromanov May 21, 2026
1c9358d
fix(codec): typed public API, parity test improvements, receipt_hash …
ignromanov May 21, 2026
a18ab4b
ci: lint+test in CI, release contents:write, changeset 0.1.0 entry (P…
ignromanov May 21, 2026
fea15ab
fix(codec): harden decode path — due_at/TLV-length truncation, dict i…
ignromanov May 21, 2026
0c7a8ca
refactor(codec): split encode.rs into encode/ submodule (behavior-pre…
ignromanov May 21, 2026
e0e464f
refactor(codec): split decode.rs into decode/ submodule (behavior-pre…
ignromanov May 21, 2026
9e73cac
fix(codec): encode-path validation — negative qty, due_at order, zero…
ignromanov May 22, 2026
2b3269d
fix(codec): systematic decode-path cast hardening (#8, #12, #2)
ignromanov May 22, 2026
948e505
fix(types): replace InvoiceParty with InvoiceFrom/InvoiceClient — mat…
ignromanov May 22, 2026
af5da24
fix(codec): wire receipt_hash_hex into generate-vectors.ts
ignromanov May 22, 2026
2f41b10
ci: SHA-pin all actions and replace curl|sh wasm-pack install
ignromanov May 22, 2026
4ff58d7
docs(codec): update README to document actual v0.1.0 API
ignromanov May 22, 2026
7e6cfee
fix(codec): dict layer — exact-set reject (#4) + UTF-8 reverse_dict (…
ignromanov May 22, 2026
ef996fb
style(codec): cargo fmt — encode/dict.rs, decode/dict.rs, decode/amou…
ignromanov May 22, 2026
3ceeac6
chore(codec): regenerate v4-codec.json with receipt_hash_hex
ignromanov May 22, 2026
4f05f50
docs(codec): SECURITY.md — clarify domain separator is integrity, not…
ignromanov May 22, 2026
2716ee1
fix(ci): wasm-pack pin 0.14.1 → 0.14.0 (0.14.1 never published)
ignromanov May 22, 2026
739a8cf
fix(codec): declare @void-layer/types workspace dependency
ignromanov May 22, 2026
62b26a8
fix(ci): vector-parity must build workspace deps before codec
ignromanov May 22, 2026
2289ed4
refactor(codec): dedicated error variants + shared limits module
ignromanov May 22, 2026
caf5b9b
perf(codec): zero-alloc apply_dict + reorder-sensitive dict lock
ignromanov May 22, 2026
7418350
feat(codec): deny(missing_docs) + prelude module
ignromanov May 22, 2026
da3813f
fix(codec): TS shim hardening — decompression-bomb cap + typing
ignromanov May 22, 2026
244c60b
docs(codec): breaking-change policy + exact dep pin + size refresh
ignromanov May 22, 2026
5319b8f
fix(ci): align release.yml action SHAs to ci.yml, drop npm escalation…
ignromanov May 22, 2026
fd181c0
docs: update stale Phase 1 references, add invoice module to types RE…
ignromanov May 22, 2026
f56386e
fix(codec): add CodecError::InvalidData variant for non-overflow fail…
ignromanov May 22, 2026
28f7e9b
fix(types,networks): install @vitest/coverage-v8 provider
ignromanov May 22, 2026
c7acd21
fix(coverage): calibrate the coverage gate so it is actually enforced
ignromanov May 22, 2026
32ed9b4
feat(codec): add unicode golden vectors (T1), parametric corpus (T2),…
ignromanov May 22, 2026
43d963e
test(codec): add Tranche A edge-case tests (31 gaps, G-01–G-37)
ignromanov May 22, 2026
b1f37da
fix(codec): harden decoder — reject duplicate/unknown tags, non-canon…
ignromanov May 22, 2026
28dc8f1
fix(codec): resolve clippy warnings in edge_cases.rs (CI lint gate)
ignromanov May 22, 2026
2f73fca
style(codec): apply rustfmt to decoder hardening + edge-case tests (C…
ignromanov May 22, 2026
cc6ff97
docs(codec): reflect Tranche B hardening + test-data expansion across…
ignromanov May 23, 2026
8d78eb7
fix(codec): T1+T2 align encode_token_address with TS reference; rejec…
ignromanov May 25, 2026
1fe10aa
fix(codec): T4 cap decode_mantissa scale + scaled_value f64 range
ignromanov May 25, 2026
cd8d56f
fix(codec): T5 reject quantity precision loss past 9 decimals (encode)
ignromanov May 25, 2026
fce85bf
fix(codec): T6 decoder rejects raw-form for dict-known chain/currency…
ignromanov May 25, 2026
2653f2a
refactor(codec): T7 single source of truth for known TLV tags
ignromanov May 25, 2026
755be04
test(codec): T8 malformed vectors for non-canonical varint + unknown tag
ignromanov May 25, 2026
397ad3c
ci(codec): T3 add ts-rust-parity job vs vl/app pinned SHA e4926b7
ignromanov May 25, 2026
9df7519
docs(codec): T9 document v1.0 even/odd forward-compat deferral
ignromanov May 25, 2026
401b063
fix(ci): T3.1 use repo var instead of secret in job-level if (GH Acti…
ignromanov May 25, 2026
713cded
test(codec): T5.1 migrate G-11 tests to new PrecisionLoss contract
ignromanov May 25, 2026
3da08df
refactor(codec/decode): collapse optional-field reads via Option::map…
ignromanov May 25, 2026
d34d3d2
refactor(codec/decode): extract hex/mantissa helpers + find_map for d…
ignromanov May 25, 2026
bf55783
refactor(codec/encode): hex_decode_fixed shared helper for address + …
ignromanov May 25, 2026
8771d25
refactor(codec/encode): is_none_or for chain range + named quantity c…
ignromanov May 25, 2026
ffbd9b5
refactor(codec/tlv): extract inline tests to sibling tests.rs
ignromanov May 25, 2026
2c2f74f
refactor(codec/varint): extract inline tests to sibling tests.rs
ignromanov May 25, 2026
6881ad8
refactor(codec/encode/amount): extract inline tests to sibling tests.rs
ignromanov May 25, 2026
bb96ab9
refactor(codec/encode/dict): extract inline tests to sibling tests.rs
ignromanov May 25, 2026
59534ef
fix(codec/decode): reject quantity scale > 9 as non-canonical (T6-fam…
ignromanov May 25, 2026
9334508
fix(codec/decode): gate currency raw branch on 0x01 prefix (T6-family…
ignromanov May 25, 2026
1819013
fix(codec/decode): gate token-address raw branch on 0x01 prefix (T6-f…
ignromanov May 25, 2026
1e7e844
fix(codec/decode): enforce exact TLV_DECIMALS length == 1 (T6-family …
ignromanov May 25, 2026
7c6778c
fix(ci): add ci-gate meta-job so skipped ts-rust-parity != pass (P2-F5)
ignromanov May 25, 2026
5851cbd
fix(codec/encode): propagate label through hex_nibble for correct err…
ignromanov May 25, 2026
0c05938
fix(codec/ts): raise MAX_DECOMPRESSED_BYTES to 262144 for round-trip …
ignromanov May 25, 2026
4e32b41
refactor(codec/dict): extract CURRENCY_DICT to shared file (R1)
ignromanov May 25, 2026
8628d14
refactor(codec/dict): extract TOKEN_DICT + CHAIN_CODE_RANGES to share…
ignromanov May 25, 2026
374573a
refactor(codec/canonical): extract domain-separator computation to sh…
ignromanov May 25, 2026
8e962b9
refactor(codec/dict): name DICT_FORM/RAW_FORM wire-prefix discriminat…
ignromanov May 25, 2026
aea773d
refactor(codec/limits): promote MAX_CANONICAL_QUANTITY_SCALE to limit…
ignromanov May 25, 2026
158186d
refactor(codec/decode): TLV read_optional + utf8_or helpers (R6+R7)
ignromanov May 25, 2026
fcebe0d
refactor(codec/decode): lookup_by_code generic for slice dict reverse…
ignromanov May 25, 2026
ac60c12
feat(networks): add getChainConfig + tryGetChainConfig helpers (N1+N3)
ignromanov May 25, 2026
810059f
feat(networks): add block explorer URL builders (N2)
ignromanov May 25, 2026
dc135b9
feat(networks): add wagmi defineChain configs (N4)
ignromanov May 25, 2026
afdf103
feat(networks): add curated token list with metadata (N5)
ignromanov May 25, 2026
7590bf0
test(networks): 81 tests for N1-N5 enriched scope, 100% coverage
ignromanov May 25, 2026
7cae14f
docs(networks): document 0.1.0 enriched scope
ignromanov May 25, 2026
916659a
refactor(codec/decode): decode_prefixed helper for dict/raw dispatch …
ignromanov May 25, 2026
1dacfb8
docs(canvas): refresh architecture canvas for Phase-2 + R1-R9 + netwo…
ignromanov May 25, 2026
c72ff05
docs(codec): regenerate bundle-budget post-R9; flip 200KB cap to advi…
ignromanov May 25, 2026
0bb1245
docs(codec): add 5 decoder invariant rows to reject table (F3)
ignromanov May 25, 2026
8ffa8cc
docs(codec): regenerate CodecError table from error.rs — all 14 varia…
ignromanov May 25, 2026
9ecb2bd
docs(codec): add readme field to Cargo.toml; note pkg-node/README syn…
ignromanov May 25, 2026
9058747
docs(codec): populate CHANGELOG with 0.1.0 pre-publish summary (F7)
ignromanov May 25, 2026
2668726
docs(codec): mark spike-brotli SUPERSEDED; strip tsify/subpath from a…
ignromanov May 25, 2026
f295a62
docs(codec): update golden-vectors count 25 → 27, add rows 26-27 (W3)
ignromanov May 25, 2026
1a140bd
fix(networks): add coverage include/exclude to vitest.config (P2-1)
ignromanov May 25, 2026
f7a55ec
chore(deps): lockfile update for viem peerDep (networks N4 fixup)
ignromanov May 25, 2026
f616c61
fix(ci): ci-gate distinguishes parity opt-out from unexpected skip
ignromanov May 25, 2026
e8c15e0
docs(codec): deep architecture map for human readers
ignromanov May 25, 2026
c208c4c
refactor(codec): split generate-vectors.ts into focused modules
ignromanov May 25, 2026
352e42e
refactor(codec): isolate dict data slices into dict/data/ (Option A)
ignromanov May 25, 2026
83b3450
feat(codec): add 6 demo-invoice vectors to golden corpus (27→33)
ignromanov May 25, 2026
cc3e267
docs(codec): fix tag count comment (28→26, content 25→23)
ignromanov May 25, 2026
b5f84ac
refactor(codec): extract scenarios from generate-vectors.ts main() (5…
ignromanov May 25, 2026
73ed9af
refactor(codec): split edge_cases.rs into category-focused test files…
ignromanov May 25, 2026
14c3c95
refactor(codec): split codec_smoke.rs and parity.rs into focused test…
ignromanov May 25, 2026
bfb4a50
fixup(codec): apply rustfmt to F2/F3 test files (long use lines)
ignromanov May 25, 2026
d788d5e
refactor(codec): extract parity.rs harness to tests/common/mod.rs
ignromanov May 25, 2026
bc52e65
refactor(codec): split parity.rs into parity_roundtrip.rs and parity_…
ignromanov May 25, 2026
9a522d9
feat(codec): odd/even forward-compat on decode (codec-bolt12-odd-even…
ignromanov May 26, 2026
5b6eaea
feat(codec): strict-monotone TLV ordering on decode (codec-bolt12-str…
ignromanov May 26, 2026
b78e5c9
docs(codec): TLV type-range registry (codec-bolt12-type-range-experim…
ignromanov May 26, 2026
1f49adc
fix(codec): re-derive vector for Y1 odd-tag success (codec-bolt12-odd…
ignromanov May 26, 2026
e799d05
fix(ci): target parity_roundtrip + parity_malformed (parity.rs was sp…
ignromanov May 29, 2026
cb61d0e
fix(codec/decode): expect collapsible_if to preserve even/odd branch …
ignromanov May 29, 2026
4b00331
docs(security): correct SECURITY.md — odd-tag forward-compat is live,…
ignromanov May 29, 2026
718daff
fix(codec): reject non-canonical mantissa scale-aliasing and trailing…
ignromanov May 29, 2026
110cd7a
fix(codec): replace post-allocate bomb check with bounded streaming d…
ignromanov May 29, 2026
d83cef9
fix(codec): guard streaming decompress against truncated-stream hang …
ignromanov May 29, 2026
ce864d4
refactor(codec/decode): extract mantissa canonical-form check + expli…
ignromanov May 29, 2026
d202d43
fix(codec/vectors): drop stale malformed-unknown-tlv-tag (odd tag now…
ignromanov May 29, 2026
bfc2601
fix(ci): disable coverage gate on vector-parity single-file vitest ru…
ignromanov May 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}
11 changes: 11 additions & 0 deletions .changeset/initial-release-0-1-0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@void-layer/codec": minor
"@void-layer/types": minor
"@void-layer/networks": minor
---

Initial 0.1.0 release of the @void-layer monorepo.

- `@void-layer/codec`: Canonical TLV + Brotli wire codec (WASM + JS shim). Includes `encodeInvoiceCanonical`, `decodeInvoiceCanonical`, `encodeInvoiceWire`, `decodeInvoiceWire`, and `receiptHash` (keccak-256 content hash). 18 golden vectors in v4-codec.json schema_version=1.
- `@void-layer/types`: TypeScript type definitions for Invoice, InvoiceItem, InvoiceFrom, InvoiceClient, NetworkConfig, ChainId, FrameContext, FrameState, PaymentProof, PaymentRequiredResponse. Zero runtime dependencies.
- `@void-layer/networks`: Chain configs for 5 EVM networks (Ethereum, Base, Arbitrum, Optimism, Polygon) with public RPC URLs. `SUPPORTED_TOKENS` is empty at 0.1.0 (@alpha — populated in a future release from Uniswap Token List).
15 changes: 15 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
root = true

[*]
end_of_line = lf
charset = utf-8
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true

[*.rs]
indent_size = 4

[*.md]
trim_trailing_whitespace = false
4 changes: 4 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Default owner for everything
* @ignromanov

# Phase 3+: add @void-layer/maintainers when team formed
21 changes: 21 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
groups:
changesets:
patterns: ["@changesets/*"]
typescript:
patterns: ["typescript", "@types/*"]
- package-ecosystem: "cargo"
directory: "/packages/codec"
schedule:
interval: "weekly"
open-pull-requests-limit: 3
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
152 changes: 152 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
name: CI
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
lint-and-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
with: { version: 10.24.0 }
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: { node-version: 24, cache: pnpm }
- uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 # v1
with: { rustflags: "" }
- uses: Swatinem/rust-cache@42dc69e1aa15d09112580998cf2ef0119e2e91ae # v2
- run: rustup target add wasm32-unknown-unknown
- name: Install wasm-pack 0.14.0
run: cargo install wasm-pack --version 0.14.0 --locked
- run: pnpm install --frozen-lockfile
- run: pnpm -r build
- run: pnpm -r lint
- run: pnpm -r test
- run: cargo build --manifest-path packages/codec/Cargo.toml --release
- run: cargo test --manifest-path packages/codec/Cargo.toml
- name: Assert size budgets
run: bash scripts/assert-size.sh
working-directory: packages/codec
- run: |
for dir in packages/codec packages/types packages/networks; do
(cd "$dir" && npm pack --dry-run)
done
vector-parity:
needs: [lint-and-build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
with: { version: 10.24.0 }
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: { node-version: 24, cache: pnpm }
- uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 # v1
with: { rustflags: "" }
- uses: Swatinem/rust-cache@42dc69e1aa15d09112580998cf2ef0119e2e91ae # v2
- run: rustup target add wasm32-unknown-unknown
- name: Install wasm-pack 0.14.0
run: cargo install wasm-pack --version 0.14.0 --locked
- run: pnpm install --frozen-lockfile
- run: pnpm -r build
- name: TS/JS parity (vitest)
run: pnpm -C packages/codec exec vitest run tests/parity.test.ts --coverage.enabled=false
- name: Rust parity (cargo)
run: cargo test --manifest-path packages/codec/Cargo.toml --test parity_roundtrip --test parity_malformed
ts-rust-parity:
# Requires VOIDPAY_READ_TOKEN secret (fine-grained PAT: contents:read on ignromanov/voidpay).
# Skipped automatically on fork PRs where the secret is absent.
# To enable: set vars.TS_RUST_PARITY_ENABLED=true AND add secret VOIDPAY_READ_TOKEN in repo Settings.
needs: [lint-and-build]
runs-on: ubuntu-latest
if: ${{ vars.TS_RUST_PARITY_ENABLED == 'true' }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Checkout vl/app at pinned SHA (sparse — codec files only)
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
repository: ignromanov/voidpay
ref: e4926b7f7b08ca4f72b707df8796bfd4a4b0a3b3
token: ${{ secrets.VOIDPAY_READ_TOKEN }}
path: vl-app
sparse-checkout: |
src/features/invoice-codec
src/shared/lib/tlv-codec
- uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
with: { version: 10.24.0 }
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: { node-version: 24, cache: pnpm }
- uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 # v1
with: { rustflags: "" }
- uses: Swatinem/rust-cache@42dc69e1aa15d09112580998cf2ef0119e2e91ae # v2
- run: rustup target add wasm32-unknown-unknown
- name: Install wasm-pack 0.14.0
run: cargo install wasm-pack --version 0.14.0 --locked
- run: pnpm install --frozen-lockfile
- run: pnpm -r build
- name: Run cross-impl parity (Rust WASM vs TS reference)
run: VL_APP_PATH=${{ github.workspace }}/vl-app pnpm -C packages/codec run test:ts-rust-parity
macos-sanity:
runs-on: macos-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 # v1
- uses: Swatinem/rust-cache@42dc69e1aa15d09112580998cf2ef0119e2e91ae # v2
- run: cargo test --manifest-path packages/codec/Cargo.toml
test-wasm-node:
needs: [lint-and-build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 # v1
with: { rustflags: "" }
- uses: Swatinem/rust-cache@42dc69e1aa15d09112580998cf2ef0119e2e91ae # v2
- run: rustup target add wasm32-unknown-unknown
- name: Install wasm-pack 0.14.0
run: cargo install wasm-pack --version 0.14.0 --locked
- name: Run wasm-pack test --node (AC-9 boundary tests)
run: wasm-pack test --node packages/codec
ci-gate:
# Single required branch-protection check. All non-parity jobs must succeed;
# ts-rust-parity may be SKIPPED only when vars.TS_RUST_PARITY_ENABLED != 'true'
# (opt-out for forks or repos without VOIDPAY_READ_TOKEN secret).
needs: [lint-and-build, macos-sanity, vector-parity, test-wasm-node, ts-rust-parity]
if: always()
runs-on: ubuntu-latest
steps:
- name: Verify required jobs (parity opt-out aware)
run: |
fail=0

check() {
local name=$1 result=$2
if [ "$result" != "success" ]; then
echo "❌ $name: $result"
fail=1
else
echo "✅ $name: $result"
fi
}

check "lint-and-build" "${{ needs.lint-and-build.result }}"
check "macos-sanity" "${{ needs.macos-sanity.result }}"
check "vector-parity" "${{ needs.vector-parity.result }}"
check "test-wasm-node" "${{ needs.test-wasm-node.result }}"

parity_result="${{ needs.ts-rust-parity.result }}"
parity_enabled="${{ vars.TS_RUST_PARITY_ENABLED }}"

if [ "$parity_enabled" = "true" ]; then
check "ts-rust-parity (enabled)" "$parity_result"
else
# opt-out path: skipped or success both acceptable
if [ "$parity_result" = "skipped" ] || [ "$parity_result" = "success" ]; then
echo "✅ ts-rust-parity ($parity_result; disabled via vars.TS_RUST_PARITY_ENABLED)"
else
echo "❌ ts-rust-parity: $parity_result"
fail=1
fi
fi

exit $fail
26 changes: 26 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Release
on:
workflow_dispatch:
permissions:
contents: write
id-token: write
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
with: { version: 10.24.0 }
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: { node-version: 24, cache: pnpm, registry-url: 'https://registry.npmjs.org' }
- uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 # v1
with: { rustflags: "" }
- uses: Swatinem/rust-cache@42dc69e1aa15d09112580998cf2ef0119e2e91ae # v2
- run: rustup target add wasm32-unknown-unknown
- name: Install wasm-pack 0.14.0
run: cargo install wasm-pack --version 0.14.0 --locked
- run: pnpm install --frozen-lockfile
- run: pnpm -r build
- run: pnpm changeset publish
env:
NPM_CONFIG_PROVENANCE: true
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
node_modules/
target/
pkg/
pkg-node/
pkg-web/
dist/
.DS_Store
*.log
Expand Down
2 changes: 2 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
save-exact=true
engine-strict=true
8 changes: 8 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
node_modules/
dist/
pkg/
target/
.changeset/
pnpm-lock.yaml
Cargo.lock
*.md
10 changes: 10 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"semi": true,
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"arrowParens": "always",
"endOfLine": "lf"
}
23 changes: 23 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Code of Conduct

This project adopts the [Contributor Covenant version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/) as its Code of Conduct.

Please read the full text at the link above before contributing.

## Reporting

Report unacceptable behavior to **ign.romanov@gmail.com** with subject prefix `[code-of-conduct][@void-layer/codec]`.

Reports are reviewed within 72 hours. Confidentiality is maintained for reporters.

## Scope

This Code of Conduct applies within all project spaces — GitHub issues, pull requests, discussions, and any official communication channels — and when an individual is officially representing the project.

## Enforcement

Maintainers may take any action deemed appropriate, including warning, temporary ban, or permanent ban from the project.

## Attribution

This document is a pointer to the [Contributor Covenant v2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/), which is licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).
49 changes: 49 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Contributing to @void-layer/codec

## Dev Setup

```bash
# Requires Node >=24 and pnpm >=10
pnpm install
```

## Making Changes

Build all packages:
```bash
pnpm build
```

Run tests:
```bash
pnpm test
```

Run lint:
```bash
pnpm lint
```

## Releasing

This repo uses [Changesets](https://github.com/changesets/changesets) for versioning.

Add a changeset for any user-facing change:
```bash
pnpm changeset
```

Then commit the generated `.changeset/*.md` file with your PR.

Maintainers run `pnpm version` to bump versions and `pnpm release` to publish.

## Design Rationale

See [spec 056](https://github.com/ignromanov/voidpay-ai/blob/master/ops/specs/056-void-layer-codec-extraction/spec.md).

The decision to rewrite the codec from TypeScript to Rust+WASM is documented in:
`voidpay-ai/agent-memory/advisors/decisions/2026-05-09-kai-cto-codec-rust-supersedes-ts-first.md`

## Schema

v1 schema is LOCKED. Old invoice URLs must decode forever. Never break existing field assignments.
Loading
Loading