From 443011429507eb4d2306f210963f42d7dcb4b9c1 Mon Sep 17 00:00:00 2001 From: Ty J Everett Date: Mon, 27 Jul 2026 13:20:54 -0700 Subject: [PATCH] chore: enforce stack documentation and package coherence --- .github/SECURITY.md | 197 +++++---- .github/workflows/ci.yml | 3 + .github/workflows/release.yaml | 3 + CONFORMANCE_AND_DOCS_AUDIT.md | 6 + README.md | 2 +- conformance/COVERAGE.md | 6 +- conformance/META.json | 6 +- conformance/PARITY_MATRIX.json | 38 +- docs-codeblock-audit.md | 6 + docs/about/contributing.md | 47 +- docs/about/doc-agent.md | 417 ++++++------------ docs/about/versioning.md | 287 +++++------- docs/architecture/beef.md | 10 +- docs/architecture/brc-100.md | 40 +- docs/architecture/conformance.md | 44 +- docs/architecture/identity.md | 20 +- docs/architecture/index.md | 28 +- docs/architecture/layers.md | 2 +- docs/conformance/contributing-vectors.md | 8 +- docs/conformance/index.md | 59 +-- docs/conformance/runner-ts.md | 16 +- docs/conformance/vectors.md | 90 ++-- docs/get-started/choose-your-stack.md | 46 +- docs/get-started/concepts.md | 8 +- docs/get-started/index.md | 24 +- docs/get-started/install.md | 18 +- docs/guides/compiled-package-examples.md | 180 ++++++++ docs/guides/index.md | 24 +- docs/index.md | 42 +- docs/infrastructure/index.md | 57 ++- docs/infrastructure/overlay-server.md | 106 ++--- docs/packages/helpers/amountinator.md | 43 +- docs/packages/helpers/create-bsv-app.md | 48 ++ docs/packages/helpers/did-client.md | 29 +- docs/packages/helpers/did.md | 15 +- docs/packages/helpers/fund-wallet.md | 23 +- docs/packages/helpers/index.md | 25 +- docs/packages/helpers/simple.md | 23 +- docs/packages/helpers/templates.md | 30 +- docs/packages/helpers/wallet-helper.md | 45 +- docs/packages/index.md | 19 +- docs/packages/messaging/authsocket-client.md | 29 +- docs/packages/messaging/authsocket.md | 33 +- docs/packages/messaging/message-box-client.md | 15 +- docs/packages/messaging/paymail.md | 21 +- docs/packages/middleware/402-pay.md | 43 +- .../middleware/auth-express-middleware.md | 7 +- docs/packages/middleware/auth.md | 60 +++ docs/packages/middleware/index.md | 17 +- .../middleware/payment-express-middleware.md | 7 +- docs/packages/network/index.md | 30 +- docs/packages/network/teranode-listener.md | 18 +- docs/packages/overlays/btms-backend.md | 20 +- docs/packages/overlays/gasp.md | 34 +- docs/packages/overlays/index.md | 24 +- .../overlays/overlay-discovery-services.md | 20 +- docs/packages/overlays/overlay-express.md | 66 +-- docs/packages/overlays/overlay-topics.md | 32 +- docs/packages/overlays/overlay.md | 42 +- docs/packages/sdk/bsv-sdk.md | 104 +++-- docs/packages/sdk/index.md | 65 +-- docs/packages/sdk/verifast.md | 57 +++ .../packages/wallet/btms-permission-module.md | 27 +- docs/packages/wallet/btms.md | 23 +- docs/packages/wallet/index.md | 49 +- docs/packages/wallet/wallet-relay.md | 55 +-- docs/packages/wallet/wallet-toolbox-client.md | 58 +++ .../wallet/wallet-toolbox-examples.md | 12 +- docs/packages/wallet/wallet-toolbox-mobile.md | 57 +++ docs/packages/wallet/wallet-toolbox.md | 85 ++-- docs/reference/brc-index.md | 38 +- docs/reference/dependency-policy.md | 52 ++- docs/reference/index.md | 9 +- docs/reference/npm-package-supply-chain.md | 7 +- docs/reference/release-operations.md | 195 ++++++++ docs/reference/repository-health.md | 22 +- docs/reference/stack-facts.md | 130 ++++++ docs/specs/index.md | 2 +- governance/documentation-policy.json | 25 ++ governance/repository-health/baselines.json | 18 +- governance/repository-health/exceptions.json | 3 +- governance/repository-health/projects.json | 6 + infra/overlay-server/README.md | 2 +- infra/wallet-infra/README.md | 2 +- .../wallet-infra/guides/gcloud_deployment.md | 33 +- .../wallet-infra/guides/local_development.md | 4 +- package.json | 7 +- packages/helpers/bsv-wallet-helper/README.md | 2 +- packages/helpers/create-bsv-app/README.md | 4 + packages/helpers/did/README.md | 4 + packages/helpers/simple/README.md | 14 + packages/messaging/ts-paymail/CHANGELOG.md | 5 +- packages/messaging/ts-paymail/package.json | 4 +- .../auth-express-middleware/BASELINE.md | 24 +- .../auth-express-middleware/package.json | 4 +- packages/middleware/auth/README.md | 4 + .../payment-express-middleware/BASELINE.md | 24 +- .../payment-express-middleware/package.json | 4 +- packages/overlays/gasp-core/README.md | 2 +- .../overlays/overlay-express/CHANGELOG.md | 2 + .../overlays/overlay-express/package.json | 6 +- .../src/__tests__/makeUserInterface.test.ts | 6 +- .../overlay-express/src/makeUserInterface.ts | 2 +- packages/sdk/CHANGELOG.md | 3 + packages/sdk/mkdocs.yml | 2 +- packages/sdk/package.json | 2 +- .../sdk/src/wallet/substrates/window.CWI.ts | 75 +--- packages/verifast/README.md | 13 + packages/wallet/ts-wallet-relay/README.md | 4 + packages/wallet/ts-wallet-relay/package.json | 4 +- packages/wallet/wallet-toolbox/CHANGELOG.md | 4 + .../wallet/wallet-toolbox/client/package.json | 2 +- .../wallet/wallet-toolbox/mobile/package.json | 2 +- packages/wallet/wallet-toolbox/package.json | 3 +- .../src/storage/remoting/StorageServer.ts | 53 ++- .../remoting/__test/StorageServerRpc.test.ts | 95 +++- pnpm-lock.yaml | 33 +- scripts/check-documentation-examples.mjs | 187 ++++++++ scripts/check-package-artifact.mjs | 66 ++- scripts/check-package-artifact.test.mjs | 45 +- scripts/check-versions.mjs | 40 +- scripts/documentation-policy.mjs | 160 +++++++ scripts/generate-parity-matrix.mjs | 48 +- scripts/generate-stack-facts.mjs | 243 ++++++++++ scripts/generated-documentation.test.mjs | 25 ++ scripts/repository-health.mjs | 55 +++ scripts/repository-health.test.mjs | 39 ++ specs/reliability/README.md | 24 +- specs/reliability/arc.md | 3 + specs/reliability/go-sdk.md | 3 + specs/reliability/message-box-server.md | 4 + specs/reliability/overlay-express.md | 4 + specs/reliability/ts-sdk.md | 4 + specs/reliability/wallet-toolbox.md | 4 + 134 files changed, 3519 insertions(+), 1646 deletions(-) create mode 100644 docs/guides/compiled-package-examples.md create mode 100644 docs/packages/helpers/create-bsv-app.md create mode 100644 docs/packages/middleware/auth.md create mode 100644 docs/packages/sdk/verifast.md create mode 100644 docs/packages/wallet/wallet-toolbox-client.md create mode 100644 docs/packages/wallet/wallet-toolbox-mobile.md create mode 100644 docs/reference/release-operations.md create mode 100644 docs/reference/stack-facts.md create mode 100644 governance/documentation-policy.json create mode 100644 scripts/check-documentation-examples.mjs create mode 100644 scripts/documentation-policy.mjs create mode 100644 scripts/generate-stack-facts.mjs create mode 100644 scripts/generated-documentation.test.mjs diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 2d140630f..4f31e6749 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -1,93 +1,134 @@ # Security Policy -## Supported Versions +## Supported versions -| Package tier | Supported | -| ---------------------------------------------- | -------------- | -| Tier 0 (SDK primitives) | Latest release | -| Tier 1 (Wallet, Overlay, Messaging, Broadcast) | Latest release | -| Tier 2 (Apps, UI) | Latest release | -| Tier 3 (Examples, helpers) | Best-effort | +The latest published release of every public package is supported. Older +versions remain available but do not have a blanket backport promise. The +current source package versions and runtime profiles are generated in +[`docs/reference/stack-facts.md`](../docs/reference/stack-facts.md). -## Reporting a Vulnerability +Deployable services under `infra/` are supported from reviewed `main` source +and immutable image digests produced by the infrastructure release workflow. +An unreviewed fork, locally built image, or mutable tag is outside the supported +release boundary. -**Do not open a public GitHub issue for security vulnerabilities.** +## Report a vulnerability privately -Report via GitHub Security Advisories: -**[https://github.com/bsv-blockchain/ts-stack/security/advisories/new](https://github.com/bsv-blockchain/ts-stack/security/advisories/new)** +**Do not open a public issue for a suspected vulnerability.** -Or email: **security@bsvblockchain.org** +Use a [private GitHub security advisory](https://github.com/bsv-blockchain/ts-stack/security/advisories/new) +or email **security@bsvblockchain.org**. Include: -Include: +- affected package, service, version, source SHA, or image digest; +- practical impact and deployment assumptions; +- reproduction steps or a proof of concept; +- whether exploitation is observed or believed active; and +- a proposed fix, mitigation, or disclosure constraint if known. -- Affected package(s) and version(s) -- Description of the vulnerability and its impact -- Steps to reproduce or proof-of-concept (can be shared privately) -- Whether you have a proposed fix +Do not include real private keys, production credentials, personal data, or +other unrelated secrets. Use synthetic fixtures or arrange a private handoff. -## Response SLA +## Response targets -| Step | Target | -| --------------------------- | -------------------------------------------------------- | -| Acknowledge receipt | 3 business days | -| Initial severity assessment | 5 business days | -| Patch plan communicated | 14 calendar days | -| Patch released (P0/P1) | As fast as possible, typically < 30 days | -| Public disclosure | Coordinated — 90-day default window from acknowledgement | +| Step | Target | +| ------------------------------------- | ------------------------------------------------------------------------------------------------ | +| Acknowledge receipt | 3 business days | +| Initial severity and scope assessment | 5 business days | +| Remediation plan or next update | 14 calendar days | +| Critical/high fix | As fast as safely practical | +| Disclosure | Coordinated with the reporter; 90 days is the default maximum, not a reason to delay a ready fix | -Security fixes bypass the standard 60-day deprecation policy and are released out of band. - -## Coordinated Disclosure - -We follow a 90-day coordinated disclosure window by default. If a vulnerability is being actively exploited, we reserve the right to release a patch immediately and publish the advisory simultaneously. - -Reporters who follow this process responsibly will be credited in the security advisory (unless anonymity is requested). +Active exploitation, exposed signing material, or a compromised release +boundary may require immediate mitigation and disclosure. Security fixes do not +wait for the normal dependency or feature cadence. ## Scope -**In scope:** - -- All packages in `packages/` (Tier 0 and Tier 1 packages are highest priority) -- Conformance runners and test infrastructure -- CI/CD workflows that handle secrets or produce signed artifacts - -**High-risk paths requiring extra scrutiny (see MBGA.md §7.3):** - -- Key generation, handling, and derivation -- ECDSA signing, verification, and sighash computation -- Encryption, decryption, HMAC, ECIES -- Transaction construction, BEEF parsing, BUMP/Merkle validation -- Script evaluation -- Authentication and session establishment -- Payment verification -- Any parser of untrusted network input - -**Out of scope:** - -- Third-party dependencies (report to the upstream maintainer) -- Issues in `Tier 3` examples that have no production impact -- Theoretical vulnerabilities with no practical exploitation path - -## Security Hardening Targets - -This repository follows the MBGA reliability and security programme: - -- Tier 0 packages target RL5 (fuzz/property tests, threat model, signed artifacts, SBOM) -- Tier 1 packages target RL4+ with security findings tracked to closure -- Supply chain controls currently enforce frozen lockfiles, deny dependency - lifecycle scripts by default in CI, explicitly rebuild audited native/build - tools, run dependency review and high/critical audits, and enable Dependabot - security updates. Container builds additionally use digest-pinned bases, - committed locks, high/critical image gates, SPDX SBOMs, SLSA provenance, - immutable release tags, and keyless signatures or attestations with - verification before release completion. npm releases likewise pack once, - produce per-package and aggregate CycloneDX SBOMs, reject high/critical - vulnerability and license findings, attest and verify the exact tarballs, - retain offline evidence, publish with npm OIDC provenance, and verify registry - digests. Automated Open BSV license-policy enforcement covers every package. - -See `specs/reliability/` for per-package security status. -See `docs/reference/container-supply-chain.md` for image release and -verification procedures. -See `docs/reference/npm-package-supply-chain.md` for npm release and -verification procedures. +In scope: + +- all public packages and private package workspaces under `packages/`; +- all deployable services, images, and manifests under `infra/`; +- authentication, payment, wallet, storage, Overlay, messaging, discovery, + relay, browser, mobile, and cross-origin behavior; +- conformance runners, generators, build/release scripts, and CI workflows; +- npm/GHCR artifacts, SBOMs, provenance, attestations, and release + reconciliation; and +- exploitable first- or third-party dependency behavior in a supported + ts-stack artifact. + +Especially sensitive boundaries include keys and derivation, signatures and +sighash, encryption/HMAC/ECIES, transactions/BEEF/BUMP/Merkle proofs, script +evaluation, authentication sessions, payments and replay prevention, parsers +of untrusted binary/JSON/network input, URLs/paths/origins, database access, +resource bounds, and release credentials. + +Purely theoretical issues without a practical path may be deprioritized, but +they may still be reported privately. Dependency vulnerabilities should also +be reported upstream; they remain in scope here when the supported stack is +exposed or needs a mitigation. + +## Implemented controls + +Pull requests and releases enforce, as applicable: + +- frozen committed locks, denied dependency lifecycle scripts, explicit + allowlisted rebuilds, dependency review, Socket analysis, and high/critical + audit gates; +- warning-free lint, strict TypeScript build/typecheck, unit/integration, + conformance, clean-consumer, browser, mobile, CLI, and WASM package checks; +- governed property tests and mutation targets for implementation trust + boundaries, with replayable seeds and scheduled long campaigns; +- CodeQL security-extended analysis, secret scanning, OpenSSF Scorecard, and + Sonar semantic review; +- runtime input validation, request/body/rate bounds, replay protection, and + synchronized service edge policies; +- digest-pinned Linux/amd64 images, Trivy gates, SPDX SBOMs, SLSA provenance, + immutable tags, keyless signatures/attestations, and verification; +- pack-once npm candidates, CycloneDX SBOMs, vulnerability/license scans, + GitHub attestations, npm OIDC provenance, and registry digest + reconciliation; and +- uniform Open BSV License Version 6 checks across package and image artifacts. + +Coverage-guided fuzzing, remaining manual/browser/performance review, and the +final QA hardening campaign are deliberately tracked as unfinished in +[issue #324](https://github.com/bsv-blockchain/ts-stack/issues/324). They must +not be described as complete until their preserved branch is finished, +reviewed, merged, and validated. + +## Security review and exceptions + +Security-relevant changes require an explicit trust-boundary and deployed-impact +review, tests that fail on the old behavior when practical, required analysis, +and exact-head evidence. Maintainers may facilitate an admin merge after +required checks and review-thread resolution; a second reviewer or +last-pusher-independent approval is not an unconditional requirement. + +Do not dismiss a finding or add an override merely to make CI green. A genuine +false positive or unavoidable temporary compatibility substitution must be +registered in `governance/repository-health/exceptions.json` with an owner, +rationale, evidence, review deadline, and objective removal condition. Expired +exceptions fail CI. + +Public services such as Overlay, Wallet Storage, WAB, Message Box, and Wallet +Relay may need to accept clients from previously unknown domains. Their public +default and opt-in CORS/CSP/origin allowlists are deployment policy, not a +replacement for authentication, authorization, signatures, topic validation, +rate limits, or request bounds. A hosting URL or fallback origin must not +silently become an allowlist. + +## Release and incident handling + +Never publish from a workstation. Follow the +[npm package](../docs/reference/npm-package-supply-chain.md), +[container](../docs/reference/container-supply-chain.md), and +[release/operations](../docs/reference/release-operations.md) guides. + +For a suspected release compromise: + +1. stop publication and deployment promotion; +2. preserve workflow, artifact, digest, attestation, and audit evidence; +3. rotate affected credentials and isolate compromised systems; +4. inventory exact package versions and image digests; +5. deprecate and forward-fix immutable npm versions or roll deployments back to + a previously verified image digest; and +6. coordinate advisory, consumer guidance, and post-incident control changes. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e1484d09c..d2bc831b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -179,6 +179,9 @@ jobs: # catches cross-package nominal-type drift that isolated builds can miss. run: pnpm typecheck + - name: Compile documentation examples against exact package tarballs + run: pnpm docs:examples + - name: Verify changed package artifacts env: SCOPE_FILTER: ${{ steps.scope.outputs.filter }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 38d424d4a..76ffe73c8 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -83,6 +83,9 @@ jobs: - name: Typecheck workspace run: pnpm typecheck + - name: Compile documentation examples against exact package tarballs + run: pnpm docs:examples + - name: Verify package license payloads run: pnpm license:pack-check diff --git a/CONFORMANCE_AND_DOCS_AUDIT.md b/CONFORMANCE_AND_DOCS_AUDIT.md index f54ee7309..e71c013f6 100644 --- a/CONFORMANCE_AND_DOCS_AUDIT.md +++ b/CONFORMANCE_AND_DOCS_AUDIT.md @@ -1,5 +1,11 @@ # Conformance Vectors & Documentation Audit +> **Archived point-in-time evidence (2026-05-14).** Findings and counts in this +> report are not the current backlog. Use +> `docs/reference/stack-facts.md`, `conformance/PARITY_MATRIX.json`, and +> [tracker #324](https://github.com/bsv-blockchain/ts-stack/issues/324) for the +> enforced current state. This report remains committed only for provenance. + **Date**: 2026-05-14 **Purpose**: Pre-port audit for Golang, Python, and Rust SDK/wallet implementations. **Auditor**: Full analysis + concrete fixes performed in this session. diff --git a/README.md b/README.md index aea1466cf..a06f57a57 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Most applications should start with `@bsv/simple` or `@bsv/sdk`. Wallet builders Prerequisites: - Node.js >= 24.11 for repository development (published packages support Node.js >= 22) -- pnpm >= 9; this repo is pinned to `pnpm@10.33.2` +- pnpm >= 10; this repo is pinned to `pnpm@10.33.2` ```sh pnpm install diff --git a/conformance/COVERAGE.md b/conformance/COVERAGE.md index db3aa39b0..d8d299f48 100644 --- a/conformance/COVERAGE.md +++ b/conformance/COVERAGE.md @@ -2,7 +2,11 @@ **Wave 4 Final Verification (Historical Snapshot)** | Generated: 2026-05-07 -> **Note**: This document reflects the corpus state at the end of Wave 4. As of 2026-05-14 the corpus has grown to **72 files / 6,625 vectors** (see `conformance/META.json` for the authoritative current count). Several legacy-format vector files were normalized and the structural runner was improved to cleanly support the special regression format. For the latest numbers and coverage, run `node conformance/runner/src/runner.js --validate-only` or consult `META.json`. +> **Historical evidence only.** The tables below are retained to explain the +> Wave 4 decisions and must not be used as current status. Current totals are +> generated in `docs/reference/stack-facts.md`; file-level classifications are +> generated in `conformance/PARITY_MATRIX.json`; current runner behavior comes +> from `pnpm conformance` and `pnpm test:governance`. ## Full-Suite Summary diff --git a/conformance/META.json b/conformance/META.json index a6113bca4..36c52621f 100644 --- a/conformance/META.json +++ b/conformance/META.json @@ -103,9 +103,9 @@ ] }, "stats": { - "total_files": 73, - "total_vectors": 6646, - "last_updated": "2026-05-19" + "total_files": 74, + "total_vectors": 6650, + "last_updated": "2026-07-27" }, "regression_index": { "beef-v2-txid-panic": "go-sdk#306", diff --git a/conformance/PARITY_MATRIX.json b/conformance/PARITY_MATRIX.json index 460d0ca4d..100998d8b 100644 --- a/conformance/PARITY_MATRIX.json +++ b/conformance/PARITY_MATRIX.json @@ -1,23 +1,25 @@ { "schema_version": "1.0", - "generated_at": "2026-05-19", + "generated_at": "2026-07-27", "source": "ts-stack conformance corpus", "description": "Machine-readable parity status for cross-language SDK implementations (Go, Rust, Python). Use this to track and drive conformance.", "summary": { - "total_files": 73, - "total_vectors": 6646, - "fully_required_files": 54, + "total_files": 74, + "total_vectors": 6650, + "fully_required_files": 55, "files_with_intended": 17, "files_with_mixed_status": 15, "vectors_by_status": { - "required": 6442, + "required": 6446, "intended": 204, - "skipped": 8 + "skipped": 7 }, "by_reason_category": { - "fully_supported": 1304, + "fully_supported": 1234, + "governed_vector_skip": 50, "historical_regression": 36, "partial_ts_behavioral_difference": 5116, + "intended_parity_work": 24, "wallet_stateful_harness_required": 190 } }, @@ -91,7 +93,7 @@ "required_count": 28, "intended_count": 0, "skipped_count": 4, - "reason_category": "fully_supported", + "reason_category": "governed_vector_skip", "justification": "Expected signature was generated by an earlier SDK version and does not match current RFC6979-deterministic output. Superseded by messaging.brc31.authrite-signature.5. | Signature value from old SDK version; superseded by messaging.brc31.authrite-signature.6. | Expected signature was generated by an earlier SDK version and does not match current RFC6979-deterministic output. Superseded by messaging.brc31.authrite-signature.8. | Signature value from old SDK version; superseded by messaging.brc31.authrite-signature.9.", "categories": [] }, @@ -368,7 +370,7 @@ "required_count": 22, "intended_count": 0, "skipped_count": 1, - "reason_category": "fully_supported", + "reason_category": "governed_vector_skip", "justification": "runner dispatchECIES decrypt-only shape does not check throws; wrong-key error is tested via sdk.crypto.ecies.16 (full form with tampered_ciphertext_hex)", "categories": [] }, @@ -517,6 +519,18 @@ "reason_category": "fully_supported", "categories": [] }, + { + "path": "sync/brc136-basm.json", + "id": "sync.brc136-basm", + "total_vectors": 4, + "file_level_parity": "required", + "effective_status": "required", + "required_count": 4, + "intended_count": 0, + "skipped_count": 0, + "reason_category": "fully_supported", + "categories": [] + }, { "path": "sync/brc40-user-state.json", "id": "sync.brc40", @@ -525,9 +539,9 @@ "effective_status": "intended", "required_count": 0, "intended_count": 24, - "skipped_count": 1, - "reason_category": "fully_supported", - "justification": "Runtime-state assertion; requires producer with seeded user table. Cannot be validated by shape-only dispatcher.", + "skipped_count": 0, + "reason_category": "intended_parity_work", + "justification": "24 vector(s) are classified as intended rather than required", "categories": [] }, { diff --git a/docs-codeblock-audit.md b/docs-codeblock-audit.md index dc12f196b..11b5a5662 100644 --- a/docs-codeblock-audit.md +++ b/docs-codeblock-audit.md @@ -1,5 +1,11 @@ # Docs Code Block Audit +> **Archived manual evidence.** This 312-block snapshot is not a current +> compiler or freshness guarantee. Current documentation is gated by +> frontmatter/link/render checks, generated fact checks, package artifact +> consumers, and the package README contract. New executable example checks +> must be automated rather than marked complete in this file. + Generated from fenced code blocks under `docs/`. Total blocks: 312. Status key: ✅ = checked against local source/package docs/tests and patched if needed. diff --git a/docs/about/contributing.md b/docs/about/contributing.md index 94c94000e..e627772ba 100644 --- a/docs/about/contributing.md +++ b/docs/about/contributing.md @@ -3,9 +3,9 @@ id: about-contributing title: 'Contributing' kind: meta version: '1.0.0' -last_updated: '2026-04-28' -last_verified: '2026-04-28' -review_cadence_days: 90 +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 status: stable tags: [about, contributing, development, community] --- @@ -44,7 +44,7 @@ The project uses **pnpm workspaces** for multi-package management. ``` ts-stack/ - packages/ # 27 npm packages + packages/ # 30 public npm packages plus private workspaces conformance/ # Test vectors and runners docs/ # Documentation source (Markdown) docs-site/ # Vite+React+MDX docs site @@ -95,17 +95,15 @@ export function sign(message: string): string { ### Run Tests ```bash -# Unit tests +# Build declarations, then run all package tests +pnpm build pnpm test # Specific package -pnpm test --filter=@bsv/sdk - -# Watch mode -pnpm test --watch +pnpm --filter @bsv/sdk test -# Coverage -pnpm test --coverage +# Package coverage +pnpm --filter @bsv/sdk test:coverage ``` Required tests must not be empty or anonymously skipped. Manual, live-network, @@ -164,7 +162,9 @@ pnpm build --filter=@bsv/sdk ## Adding Conformance Vectors -Required for all bug fixes. See [Contributing Vectors](../conformance/contributing-vectors/) for details. +Add or update a conformance vector when a change fixes or modifies a portable +protocol behavior. See +[Contributing Vectors](../conformance/contributing-vectors.md) for details. Example: @@ -286,11 +286,13 @@ if (!isValid(input)) { ## Testing Requirements -All pull requests must include: +Pull requests must include the evidence appropriate to their change: -- **Unit tests** — Test the change in isolation -- **Integration tests** — Test interaction with other parts -- **Conformance vectors** — For protocol compliance +- **Unit tests** for changed behavior +- **Integration tests** for cross-component behavior +- **Conformance vectors** for portable protocol behavior +- **Consumer or browser/mobile checks** for package-boundary changes +- **Migration and rollback notes** for breaking or deployed behavior Run before submitting: @@ -325,9 +327,9 @@ Template: ### Environment -- Node: v18.0.0 -- @bsv/sdk: 1.2.3 -- OS: macOS 13.0 +- Node: v24.18.0 +- @bsv/sdk: +- OS: macOS 15.6 ### Reproduction @@ -351,7 +353,10 @@ Help improve docs: 1. Find unclear sections in `docs/` 2. Edit the relevant `.md` file 3. Preview locally: `pnpm docs:dev` → `http://localhost:5173` -4. Submit a PR — the docs site build (`pnpm docs:build`) validates frontmatter + links on deploy (run `pnpm --filter docs-site validate` locally first for fast feedback) +4. Run `pnpm docs:facts:check` when package, runtime, release, README, or + conformance facts changed. +5. Submit a PR — the docs site build (`pnpm docs:build`) validates frontmatter + and links (run `pnpm --filter docs-site validate` locally first). **Do not delete the `gh-pages` branch** — it hosts the TypeDoc `/api/` tree that the deploy workflow merges into the artifact before publishing. @@ -396,7 +401,7 @@ All PRs run through GitHub Actions: 1. **Unit tests** — Must pass 2. **Linting** — Must pass 3. **Type checking** — Must pass -4. **Conformance** — TS and Go must pass +4. **Conformance** — structural and TypeScript behavior runners must pass 5. **Build** — All packages must build If any check fails, fix the issue and push again. diff --git a/docs/about/doc-agent.md b/docs/about/doc-agent.md index 5299b815f..e6fcf6d8f 100644 --- a/docs/about/doc-agent.md +++ b/docs/about/doc-agent.md @@ -1,10 +1,10 @@ --- id: about-doc-agent -title: "Documentation Maintenance" +title: 'Documentation Maintenance' kind: meta -version: "1.0.0" -last_updated: "2026-04-28" -last_verified: "2026-04-28" +version: '2.0.0' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable tags: [about, documentation, maintenance, automation] @@ -12,315 +12,146 @@ tags: [about, documentation, maintenance, automation] # Documentation Maintenance -This documentation site is maintained with automated tools to keep docs synchronized with the codebase. +Documentation is part of the supported package and service contract. A page is +not current merely because it renders: its links, frontmatter, versions, +generated facts, examples, and operational claims must agree with source. -## Frontmatter Schema +## Sources of truth -Every doc page must have frontmatter following this schema: +- Package name, version, engines, exports, and dependencies: the package's + `package.json`. +- Governed projects, profiles, runtime targets, release routes, and ownership: + `governance/repository-health/projects.json`. +- Public README requirements and support-language policy: + `governance/documentation-policy.json`. +- Conformance totals: `conformance/META.json`; file-level parity: + `conformance/PARITY_MATRIX.json`; runner behavior: current CI reports. +- Release behavior: `.github/workflows/release.yaml`, + `.github/workflows/infra-release.yaml`, and the machine-readable supply-chain + policies. +- Program state and deferred work: + [tracker #324](https://github.com/bsv-blockchain/ts-stack/issues/324). -```yaml ---- -id: unique-slug -title: "Page Title" -kind: spec|infra|conformance|guide|reference|meta -version: "1.2.3" -last_updated: "2026-04-28" -last_verified: "2026-04-28" -review_cadence_days: 30 -status: stable -tags: [tag1, tag2] ---- -``` - -### Required Fields - -| Field | Type | Example | Purpose | -|-------|------|---------|---------| -| `id` | string | `spec-brc-100` | Unique slug for page | -| `title` | string | `"BRC-100 Wallet"` | Page title | -| `kind` | enum | `spec` | Page category | -| `version` | string | `"1.2.3"` | Latest tested version | -| `last_updated` | date | `2026-04-28` | When content was written | -| `last_verified` | date | `2026-04-28` | When last tested | -| `review_cadence_days` | number | `30` | Days until next review | -| `status` | enum | `stable` | Stability status | -| `tags` | array | `[wallet, brc-100]` | Keywords | - -### Kind Values - -- **spec** — Protocol specification -- **infra** — Infrastructure service -- **conformance** — Test vectors/runners -- **guide** — How-to guide -- **reference** — API reference -- **meta** — About, versioning, etc. - -### Status Values - -- **stable** — Production ready -- **beta** — Feature complete, testing -- **deprecated** — Marked for removal -- **experimental** — Unstable, may change - -## Version Management - -The `version` field tracks the latest tested version of what the page documents: +Do not copy source-manifest tables into prose. Run `pnpm docs:facts` and link to +[Generated Stack Facts](../reference/stack-facts.md). -```yaml -# For package docs -version: "1.2.3" # Latest tested npm version - -# For spec docs -version: "2.0" # Spec version - -# For meta pages -version: "1.0.0" # Documentation version -``` - -### Version Checking - -Automated tools check if docs match the current npm version: - -```bash -# Check workspace cross-package versions -pnpm check-versions +## Required frontmatter -# Rewrite workspace dependency references to current package versions -pnpm sync-versions - -# Validate docs frontmatter and relative links -pnpm --filter docs-site validate -``` - -## Review Cadence - -The `review_cadence_days` field indicates how often a page should be reviewed: +Every rendered page uses: ```yaml -review_cadence_days: 30 # Review monthly -``` - -Suggested cadences: - -- **7 days** — Actively maintained features, new packages -- **14 days** — Frequently changed APIs -- **30 days** — Stable packages, specs -- **90 days** — Rarely changed (versioning, about pages) - -### Staleness Calculation - -A page becomes stale after: - -``` -stale_date = last_verified + review_cadence_days -``` - -Example: -``` -last_verified: "2026-04-28" -review_cadence_days: 30 -stale_date: "2026-05-28" -``` - -Automated agents flag stale pages and create issues/PRs to update them. - -## Maintenance Tasks - -### Update Package Version - -When a package releases a new version: - -```bash -pnpm sync-versions -pnpm check-versions -``` - -This updates workspace package references and verifies they match the current package versions. - -### Verify Documentation - -Check that examples work and links are correct: - -```bash -pnpm --filter docs-site validate -pnpm docs:build - -# Build only the documentation site -pnpm --filter docs-site build -``` - -Checks: -- All links are valid (HTTP 200) -- Code examples syntactically correct -- Version matches npm -- Required frontmatter present - -### Extract API Docs - -For package documentation, extract TypeDoc: - -```bash -pnpm --filter @bsv/sdk doc - -# Package API docs are then consumed by the docs site build -pnpm docs:build -``` - -## Automated Maintenance - -### Scheduled Review - -Automated agents check stale docs daily: - -1. Find pages where `last_verified + review_cadence_days < today` -2. Create issue requesting verification -3. If version mismatch found, create PR with updates -4. Update `last_verified` date after verification - -### GitHub Actions & Validation (Current State) - -Frontmatter and link validation run automatically as part of the docs site build: - -- Local author command: `pnpm --filter docs-site validate` (runs `validate-frontmatter.mjs` + `check-links.mjs`) -- Full build (includes the above + built-link hygiene + pagefind): `pnpm docs:build` -- Production deployment: `.github/workflows/docs-deploy.yml` runs `pnpm docs:build` on every push to `main` that touches `docs/**`, `docs-site/**`, `specs/**`, or the deploy workflow itself. - -A dedicated scheduled "docs-check" workflow (staleness flagging + PR validation on docs changes) is planned but not yet present. Until then, contributors should run `pnpm --filter docs-site validate` locally before opening docs PRs (this is also what the build does). - -See also: -- `docs-site/scripts/validate-frontmatter.mjs` + `docs/_schemas/page.schema.json` -- `docs-site/scripts/check-links.mjs` and `check-built-links.mjs` -- `.github/workflows/docs-deploy.yml` (the actual deploy pipeline) - -## Contributing Documentation - -### Edit a Doc Page - -1. Find the file in `/docs` -2. Edit the content (below frontmatter) -3. Update `last_updated` to today -4. If you verified the content, update `last_verified` -5. Commit and create PR - -Example: - -```markdown --- -id: spec-brc-100 -title: "BRC-100 Wallet Interface" +id: unique-slug +title: 'Page title' kind: spec -version: "1.0" -last_updated: "2026-04-28" # ← Update to today -last_verified: "2026-04-28" # ← Update if you tested +version: '1.0.0' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable -tags: [wallet, brc-100] +tags: [protocol, reference] --- - -# BRC-100 Wallet Interface - -[Your content here] ``` -### Create a New Page - -1. Create file in appropriate directory (`docs/specs/`, `docs/guides/`, etc.) -2. Add required frontmatter -3. Write content -4. Run `pnpm --filter docs-site validate` (and `pnpm docs:build` for the full check) to validate -5. Commit and create PR - -Template: - -```markdown ---- -id: unique-identifier -title: "Page Title" -kind: spec -version: "1.0.0" -last_updated: "2026-04-28" -last_verified: "2026-04-28" -review_cadence_days: 30 -status: stable -tags: [tag1, tag2] ---- - -# Page Title +- `version` is the source package version verified by a package page, the + protocol/doc version for a spec, or the page's own revision for meta content. +- `last_updated` changes when prose or structure changes. +- `last_verified` changes only after checking the page against its current + source and applicable commands. +- `review_cadence_days` is enforced. Use 30 days for active package, protocol, + operational, and security pages; use a longer cadence only for truly stable + conceptual material. +- `status` describes the documented contract, not whether the page is finished. -[Content] -``` +## Blocking checks -## Frontmatter Validation +```bash +# Generate after package, runtime, release-route, or conformance changes +pnpm docs:facts -All pages are validated on commit: +# Verify generated facts, parity metadata, package README contracts, +# package-doc versions, and review cadence +pnpm docs:facts:check -```bash -# Validate frontmatter and relative links +# Validate frontmatter and source links pnpm --filter docs-site validate -# Build static docs and check built links +# Render the complete site and check built links pnpm docs:build ``` -Checks: -- Required fields present -- Valid enum values (kind, status) -- Date format (ISO 8601) -- ID is unique -- Version format is valid - -## Examples - -### Spec Page - -```yaml ---- -id: spec-brc-100 -title: "BRC-100 Wallet Interface" -kind: spec -version: "1.0" -last_updated: "2026-04-28" -last_verified: "2026-04-28" -review_cadence_days: 30 -status: stable -tags: [wallet, brc-100, rpc] ---- -``` - -### Package Page - -```yaml ---- -id: pkg-sdk -title: "@bsv/sdk" -kind: reference -version: "1.2.3" -last_updated: "2026-04-28" -last_verified: "2026-04-28" -review_cadence_days: 14 -status: stable -tags: [sdk, bitcoin, crypto] ---- -``` - -### Guide Page - -```yaml ---- -id: guide-wallet-aware -title: "Build a Wallet-Aware App" -kind: guide -version: "1.0.0" -last_updated: "2026-04-28" -last_verified: "2026-04-28" -review_cadence_days: 30 -status: stable -tags: [guide, wallet, tutorial] ---- -``` - -## Next Steps - -- [Contributing Guide](./contributing.md) — Source code contributions -- [Versioning Policy](./versioning.md) — Version management -- [GitHub Releases](https://github.com/bsv-blockchain/ts-stack/releases) — See all updates +The package README contract covers every public package and requires registry +consumers to be able to identify, install, exercise, and license it. Package +artifact checks separately prove that each README and `LICENSE.txt` ships in +the exact tarball. Every public package also has one current page under +`docs/packages`; the policy rejects missing or duplicate pages, stale versions, +retired source repositories, point-in-time source commits presented as current +authority, and npm links on private workspaces. + +`pnpm check-versions` validates first-party package ranges; it does not publish, +query npm for documentation freshness, or replace `docs:facts:check`. +`pnpm sync-versions` is a release-reconciliation mutation and must not be run +as a casual documentation fix. + +## Review procedure + +When changing or re-verifying a page: + +1. Identify every factual authority used by the page. +2. Compare package versions, exports, scripts, runtime requirements, service + configuration, and release behavior with those sources. +3. Run or compile commands/examples that are meant to be executable. Label + placeholders, pseudocode, destructive commands, live-service requirements, + and platform assumptions honestly. +4. Remove obsolete promises, versions, counts, copied lists, unsafe defaults, + and links to pre-consolidation repositories. +5. Preserve historical audits as clearly labeled point-in-time evidence; do not + present them as the current backlog. +6. Update `last_updated` and, only after verification, `last_verified`. +7. Run all blocking checks above and review the rendered output. + +For public services, document both the public-by-default cross-domain path and +the optional operator allowlist. CORS, CSP, or origin filtering must not be +described as authentication, and a hosting/fallback URL must not silently imply +same-origin-only access. + +For releases, distinguish source, registry, and deployed state. Never say a +version or image is available until registry or deployment evidence proves it. +See [Release and Operations Guide](../reference/release-operations.md). + +## Example quality + +Prefer examples exercised by package tests, clean consumers, generated clients, +or an automated documentation-example check. A historical checklist that once +marked a code block correct is not a current test. + +Examples must: + +- import public entry points, not monorepo source paths; +- match current TypeScript declarations and runtime profiles; +- use synthetic keys, credentials, identities, and endpoints; +- avoid public database/firewall defaults and mutable production image tags; +- explain external services, wallets, databases, funded state, or live network + requirements; and +- include error/security handling when omission would make the example unsafe. + +## Historical and generated content + +Generated output must declare its source and check command and must never be +hand-edited. Historical benchmark, audit, and migration records keep their +original measurements but carry a prominent archive banner and point to current +facts and tracker state. + +## Pull request evidence + +A documentation PR should state: + +- pages and source authorities reviewed; +- commands/examples actually executed; +- generated files refreshed; +- runtime, deployment, security, or migration claims changed; and +- intentionally historical or deferred content left unchanged. + +Update [tracker #324](https://github.com/bsv-blockchain/ts-stack/issues/324) +when the work completes or changes the remaining program, so the issue and +repository do not diverge. diff --git a/docs/about/versioning.md b/docs/about/versioning.md index 6f259b24a..bd5f20b4e 100644 --- a/docs/about/versioning.md +++ b/docs/about/versioning.md @@ -1,187 +1,118 @@ --- id: about-versioning -title: "Versioning Policy" +title: 'Versioning Policy' kind: meta -version: "1.0.0" -last_updated: "2026-04-28" -last_verified: "2026-04-28" -review_cadence_days: 90 +version: '2.0.0' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 status: stable tags: [about, versioning, semver, releases] --- # Versioning Policy -ts-stack follows Semantic Versioning (MAJOR.MINOR.PATCH) for all packages. - -## Version Format - -``` -MAJOR.MINOR.PATCH - ↓ ↓ ↓ - 1 2 3 -``` - -- **MAJOR** — Breaking changes (incompatible API changes) -- **MINOR** — New features (backward compatible) -- **PATCH** — Bug fixes (backward compatible) - -## Release Cadence - -Different stability levels have different release schedules: - -### Stable Packages (status: stable) -``` -@bsv/sdk@1.2.3 -@bsv/wallet-toolbox@1.0.0 -@bsv/authsocket@2.1.6 -``` - -- Monthly or as-needed for critical bugs -- Extensive testing before release -- OIDC npm provenance verification -- Breaking changes only in major versions - -### Beta Packages (status: beta) -``` -@bsv/wab-server@0.2.1 -@bsv/uhrp-lite@0.1.0 -``` - -- More frequent releases (weekly possible) -- May have breaking changes in minor versions -- Should not be used in production - -### Experimental Packages (status: experimental) -- Expect significant changes -- Not ready for general use -- API may change without notice - -## Support Windows - -Only the latest major version receives bug fixes: - -``` -@bsv/sdk@1.x.x — Supported (bug fixes) -@bsv/sdk@2.x.x — Supported (full support) - -Older versions — Unsupported -``` - -Critical security fixes (CVE/CWE) are backported to the previous major version for 6 months after new major release. - -## Documentation Versioning - -Doc pages track versions via frontmatter: - -```yaml ---- -version: "1.2.3" -last_updated: "2026-04-28" -last_verified: "2026-04-28" -review_cadence_days: 30 ---- -``` - -### Fields - -- **version** — Latest tested version of package/spec -- **last_updated** — When documentation was last written -- **last_verified** — When documentation was last tested -- **review_cadence_days** — How often to re-verify - -### Staleness - -Docs are considered stale after `review_cadence_days` without verification: - -``` -last_verified: "2026-04-28" -review_cadence_days: 30 - -Stale after: 2026-05-28 -``` - -Automated agents check stale docs and update them against current npm versions. - -## Breaking Changes - -When a breaking change occurs, all affected users are notified: - -1. Major version bump (e.g., 1.x.x → 2.0.0) -2. Migration guide published -3. GitHub releases page annotated -4. NPM deprecation message on old version - -### Deprecation Path - -Features may be deprecated before removal: - -1. **v1.x** — Feature works, deprecation warning logged -2. **v2.0** — Feature removed, migration guide updated - -## Dependencies - -ts-stack declares compatible public semver ranges and keeps internal workspace -links canonical: - -```json -{ - "dependencies": { - "express": "^4.18.0", - "postgres": "^14.0.0" - } -} -``` - -This allows compatible minor and patch updates while reserving major upgrades -for explicit migrations. Runtime, development, and optional references to other -workspace packages use `workspace:^`; published peer dependencies use a broad -public range such as `^2`. - -See [Dependency and Release Policy](../reference/dependency-policy.md) for the -audit gate, supply-chain controls, residual advisory policy, and release flow. - -## Publishing - -All packages are published via: - -1. **NPM Registry** — npm.js.org -2. **OIDC Provenance** — Proves packages came from CI/CD -3. **Checksums** — Verify package integrity -4. **Tags** — `latest`, `beta`, `experimental` - -Example: - -```bash -npm install @bsv/sdk@latest # Stable -npm install @bsv/wab-server@beta # Beta -``` - -## Changelog - -See the [GitHub Releases](https://github.com/bsv-blockchain/ts-stack/releases) page for: -- Each package's release notes -- Breaking changes -- New features -- Bug fixes - -Format per [Keep a Changelog](https://keepachangelog.com/): - -``` -## [1.2.0] - 2026-04-28 - -### Added -- New feature X - -### Changed -- Breaking change Y - -### Fixed -- Bug Z -``` - -## Next Steps - -- [Contributing Guide](contributing.md) — How to contribute -- [Doc Agent Guide](doc-agent.md) — Maintaining docs -- Package Updates — Syncing with releases +Each public package in ts-stack has its own Semantic Versioning version. A +source version and a published registry version are separate facts: merging a +version change does not publish it, and publication occurs only through the +protected npm OIDC workflow. + +The exact source versions, runtime profiles, and release routes are generated +on [Generated Stack Facts](../reference/stack-facts.md). Do not copy that table +into hand-maintained pages. + +## Semantic Versioning + +- **PATCH** fixes a defect without changing the supported public contract. +- **MINOR** adds backward-compatible behavior or public API. +- **MAJOR** removes, renames, or incompatibly changes supported behavior, + types, entry points, wire formats, persistence, or runtime requirements. + +For a package below 1.0, an incompatible public change may use a minor bump, +but it still requires explicit migration notes and cannot be hidden in a patch. +Changing an internal implementation without changing its packed or runtime +contract does not automatically require bumping unrelated packages. + +## Affected-package decisions + +Version every public package whose published bytes or manifest will change. +Then inspect its first-party dependents: + +1. A dependent package needs a bump when its packed manifest range changes, its + generated declarations or bundles change, or consumers must receive the new + dependency to obtain correct behavior. +2. A dependent package does not need a bump merely because a compatible + workspace implementation changed while its own packed bytes and declared + contract remain identical. +3. Breaking first-party changes require one coordinated migration across all + affected dependents before publication. +4. Infrastructure manifests and locks are reconciled after a successful + cascade release; they are deployed separately as immutable images. + +Workspace runtime and development references use `workspace:^`; public peer +dependencies use reviewed public ranges. `scripts/check-versions.mjs` rejects +incoherent first-party references before release. + +## Support policy + +The latest published release of each package is the supported default. Older +versions remain available from npm but do not receive a blanket maintenance or +security-backport promise. When a serious vulnerability affects a previous +major, maintainers decide whether a safe backport is practical based on +exploitability, dependency constraints, and deployment exposure, and record +that decision in the private advisory. + +Browser, React Native, Node consumer, contributor, and infrastructure support +are different profiles. The generated facts page and package manifests are +authoritative; contributor CI currently uses the stricter root toolchain. + +## Breaking changes and deprecation + +A breaking release must include: + +- an explicit compatibility and deployment-impact review; +- migration instructions with before/after examples; +- updates to package READMEs, API docs, examples, and conformance contracts; +- a rollback or forward-fix plan for persisted or remotely deployed behavior; + and +- coordinated versions for affected first-party dependents. + +Prefer a deprecation period when it can be implemented without creating a +security or correctness hazard. There is no universal 60-day window. Do not +unpublish or move an immutable version to simulate rollback; deprecate a bad +version and publish a corrected version. + +## Documentation and release notes + +Package documentation frontmatter versions describe the package version +verified by that page. Cross-stack version and support facts come from the +generated page. A package change updates: + +- its README and API/reference docs when the consumer contract changes; +- a migration note for any incompatible behavior; +- a changelog when that package already maintains one; and +- the pull request and release evidence needed to explain the change when it + does not maintain a standalone changelog. + +Do not promise a GitHub Release, npm dist-tag, changelog format, cadence, or +support window that the workflow does not actually enforce. + +## Publication + +Publication is an explicit operator action after reviewed source versions are +on `main`. The supported paths are: + +- `packages//vX.Y.Z` for a single governed package; +- `release/vYYYY-MM-DD` for a cascade of every source version absent from npm; +- a legacy `vX.Y.Z` cascade; or +- a manual protected workflow dispatch from `main`. + +The workflow packs once, produces and scans SBOMs, verifies licenses, +attestations, provenance, and registry integrity, then opens a reviewed +post-publication version-sync PR when a cascade changes first-party ranges. +Nothing should be published from a maintainer workstation. + +See [Dependency and Release Policy](../reference/dependency-policy.md), +[npm Package Supply Chain](../reference/npm-package-supply-chain.md), and +[Release and Operations Guide](../reference/release-operations.md) for the +complete gates, failure handling, and rollback path. diff --git a/docs/architecture/beef.md b/docs/architecture/beef.md index c771b7867..e696f241e 100644 --- a/docs/architecture/beef.md +++ b/docs/architecture/beef.md @@ -2,12 +2,12 @@ id: architecture-beef title: BEEF — Background Evaluation Extended Format (BRC-62) kind: meta -version: "n/a" -last_updated: "2026-04-29" -last_verified: "2026-04-29" +version: 'n/a' +last_updated: '2026-04-29' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable -tags: ["architecture", "BEEF", "BRC-62", "SPV"] +tags: ['architecture', 'BEEF', 'BRC-62', 'SPV'] --- # BEEF — Background Evaluation Extended Format (BRC-62) @@ -17,6 +17,7 @@ BEEF is the standardized binary format for peer-to-peer transaction exchange on ## Why BEEF? Traditional transaction relay requires a recipient to either: + - Trust the sender ("this transaction is valid"), or - Query a full node to verify inputs @@ -49,6 +50,7 @@ The `MerklePath` class in `@bsv/sdk` implements BRC-74 encoding, decoding, and c ## Ancestor Transactions BEEF includes the minimal set of parent transactions required to reach a mined anchor on the longest chain. Each included ancestor either: + - Has a BUMP (is confirmed), or - Has its own ancestors included in the package diff --git a/docs/architecture/brc-100.md b/docs/architecture/brc-100.md index 3624fe9e7..4fb603ae0 100644 --- a/docs/architecture/brc-100.md +++ b/docs/architecture/brc-100.md @@ -2,12 +2,12 @@ id: architecture-brc100 title: BRC-100 Wallet Interface kind: meta -version: "n/a" -last_updated: "2026-04-30" -last_verified: "2026-04-30" +version: 'n/a' +last_updated: '2026-04-30' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable -tags: ["architecture", "BRC-100", "wallet"] +tags: ['architecture', 'BRC-100', 'wallet'] --- # BRC-100 Wallet Interface @@ -49,32 +49,32 @@ The application does not need separate business logic for desktop and mobile if ## Method Groups -| Group | Purpose | Method reference | -|-------|---------|------------------| -| Actions | Create, sign, abort, list, and internalize transactions. | [`createAction`](../specs/brc-100-wallet.md#createaction), [`signAction`](../specs/brc-100-wallet.md#signaction), [`internalizeAction`](../specs/brc-100-wallet.md#internalizeaction) | -| Outputs | Query and relinquish tracked outputs in baskets. | [`listOutputs`](../specs/brc-100-wallet.md#listoutputs), [`relinquishOutput`](../specs/brc-100-wallet.md#relinquishoutput) | -| Keys and crypto | Derive public keys, encrypt/decrypt, HMAC, signatures, key linkage. | [`getPublicKey`](../specs/brc-100-wallet.md#getpublickey), [`encrypt`](../specs/brc-100-wallet.md#encrypt), [`createSignature`](../specs/brc-100-wallet.md#createsignature) | -| Certificates | Acquire, list, prove, relinquish, and discover identity certificates. | [`acquireCertificate`](../specs/brc-100-wallet.md#acquirecertificate), [`proveCertificate`](../specs/brc-100-wallet.md#provecertificate) | -| Wallet state | Authentication, chain height, headers, network, version. | [`getHeight`](../specs/brc-100-wallet.md#getheight), [`getVersion`](../specs/brc-100-wallet.md#getversion) | +| Group | Purpose | Method reference | +| --------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Actions | Create, sign, abort, list, and internalize transactions. | [`createAction`](../specs/brc-100-wallet.md#createaction), [`signAction`](../specs/brc-100-wallet.md#signaction), [`internalizeAction`](../specs/brc-100-wallet.md#internalizeaction) | +| Outputs | Query and relinquish tracked outputs in baskets. | [`listOutputs`](../specs/brc-100-wallet.md#listoutputs), [`relinquishOutput`](../specs/brc-100-wallet.md#relinquishoutput) | +| Keys and crypto | Derive public keys, encrypt/decrypt, HMAC, signatures, key linkage. | [`getPublicKey`](../specs/brc-100-wallet.md#getpublickey), [`encrypt`](../specs/brc-100-wallet.md#encrypt), [`createSignature`](../specs/brc-100-wallet.md#createsignature) | +| Certificates | Acquire, list, prove, relinquish, and discover identity certificates. | [`acquireCertificate`](../specs/brc-100-wallet.md#acquirecertificate), [`proveCertificate`](../specs/brc-100-wallet.md#provecertificate) | +| Wallet state | Authentication, chain height, headers, network, version. | [`getHeight`](../specs/brc-100-wallet.md#getheight), [`getVersion`](../specs/brc-100-wallet.md#getversion) | ## Action Lifecycle `createAction` has two common outcomes: -| Outcome | What the app receives | What happens next | -|---------|------------------------|-------------------| -| Immediate action | `txid` and/or `tx` | Wallet had enough information to fund, sign, and process the transaction. | -| Signable action | `signableTransaction: { tx, reference }` | App signs specific inputs or creates unlocking scripts, then calls `signAction({ reference, spends })`. | +| Outcome | What the app receives | What happens next | +| ---------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------- | +| Immediate action | `txid` and/or `tx` | Wallet had enough information to fund, sign, and process the transaction. | +| Signable action | `signableTransaction: { tx, reference }` | App signs specific inputs or creates unlocking scripts, then calls `signAction({ reference, spends })`. | `noSend` and `sendWith` support chained batches. A wallet can create several actions without broadcasting them, pass change forward through `noSendChange`, and later send them together. ## Labels vs Tags -| Concept | Scope | Used by | -|---------|-------|---------| -| Labels | Whole action/transaction | `createAction({ labels })`, `listActions({ labels })` | -| Tags | Specific output | `createAction({ outputs: [{ tags }] })`, `listOutputs({ tags })` | -| Baskets | Named output containers | `listOutputs({ basket })`, `internalizeAction` basket insertions | +| Concept | Scope | Used by | +| ------- | ------------------------ | ---------------------------------------------------------------- | +| Labels | Whole action/transaction | `createAction({ labels })`, `listActions({ labels })` | +| Tags | Specific output | `createAction({ outputs: [{ tags }] })`, `listOutputs({ tags })` | +| Baskets | Named output containers | `listOutputs({ basket })`, `internalizeAction` basket insertions | Do not use labels as output tags or tags as action labels. They are different indexes. diff --git a/docs/architecture/conformance.md b/docs/architecture/conformance.md index 95d6f39bb..ca989b37d 100644 --- a/docs/architecture/conformance.md +++ b/docs/architecture/conformance.md @@ -2,12 +2,12 @@ id: architecture-conformance title: Conformance Pipeline kind: meta -version: "n/a" -last_updated: "2026-05-14" -last_verified: "2026-05-14" +version: 'n/a' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable -tags: ["architecture", "conformance", "cross-language"] +tags: ['architecture', 'conformance', 'cross-language'] --- # Conformance Pipeline @@ -47,24 +47,30 @@ conformance/vectors/*.json consume the same JSON corpus and compare outputs ``` -The corpus metadata is in `conformance/META.json`: file count, vector count, BRC coverage, and regression index. +Corpus totals and BRC metadata are in `conformance/META.json`; file-level +classifications are generated in `conformance/PARITY_MATRIX.json`. ## Current Coverage -The current corpus (as of 2026-05-14) contains **6,625 vectors across 72 JSON files**: - -| Area | Size | Notes | -|-----------------------------|-------------------------------|-------| -| `sdk/scripts/evaluation.json` | 5,116 vectors | BRC-14 — Script parsing, encoding, sighash, and full evaluation parity with SV Node + Teranode (normalized hex fixtures) | -| `wallet/brc100/` | 27 files, ~950 vectors | Full `WalletInterface` (getPublicKey, create/verify HMAC+Signature, encrypt/decrypt, key linkage, create/sign/abortAction, listActions/Outputs, certificates, discover*, state methods). Many stateful success paths are marked `intended` pending funded mock-chain harness. | -| `sdk/crypto/` | 8 files | AES-GCM, ECDSA, ECIES, HMAC, SHA-256, RIPEMD-160, Hash160, Signature | -| `sdk/keys/` | 3 files | BRC-42 HD derivation, PrivateKey / PublicKey behavior | -| `sdk/transactions/` | 2 files | MerklePath (BRC-74) + Transaction serialization / BEEF / EF (BRC-62) | -| `sdk/compat/` | 1 file | BRC-77 BSM compatibility | -| `regressions/` | 12 files, 36 vectors | Historical cross-SDK bugs (go-sdk#306, ts-sdk#31, etc.). Special regression format with `regression.issue` metadata. | -| Protocol domains | ~15 files | auth (BRC-31), broadcast (ARC + Merkle service), messaging (authsocket + message-box), overlay (submit/lookup/topic mgmt), payments (BRC-29/121), storage (UHRP), sync (GASP + BRC-40) | - -`conformance/META.json` is the single source of truth for exact file counts, vector counts, and the `brc_coverage` mapping. The corpus was recently cleaned up (legacy format files normalized, regression handling improved in the structural runner) to make it a reliable contract for new language implementations. +Current totals and structural runner outcomes are generated on +[Generated Stack Facts](../reference/stack-facts.md). The durable coverage +shape is: + +| Area | Size | Notes | +| ----------------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `sdk/scripts/evaluation.json` | 5,116 vectors | BRC-14 — Script parsing, encoding, sighash, and full evaluation parity with SV Node + Teranode (normalized hex fixtures) | +| `wallet/brc100/` | Method-level corpus | `WalletInterface` crypto, action, output, certificate, discovery, authentication, chain, and network behavior. Stateful gaps are explicitly governed rather than counted as passes. | +| `sdk/crypto/` | 8 files | AES-GCM, ECDSA, ECIES, HMAC, SHA-256, RIPEMD-160, Hash160, Signature | +| `sdk/keys/` | 3 files | BRC-42 HD derivation, PrivateKey / PublicKey behavior | +| `sdk/transactions/` | 2 files | MerklePath (BRC-74) + Transaction serialization / BEEF / EF (BRC-62) | +| `sdk/compat/` | 1 file | BRC-77 BSM compatibility | +| `regressions/` | Historical regressions | Cross-SDK bugs with stable IDs and source-issue metadata. | +| Protocol domains | Auth, broadcast, messaging, Overlay, payments, storage, sync | Includes BRC-20/21/22/26/29/31/40/121/136 and related HTTP or message contracts. | + +`pnpm docs:facts:check` rejects drift among metadata, the generated parity +matrix, and the corpus. `pnpm test:governance` separately owns all runner skips +and intended behaviors. A structural vector count is never a claim that all +vectors execute against every implementation. ## Running The Pipeline diff --git a/docs/architecture/identity.md b/docs/architecture/identity.md index 44dbee3fe..da829a5ad 100644 --- a/docs/architecture/identity.md +++ b/docs/architecture/identity.md @@ -2,12 +2,12 @@ id: architecture-identity title: Identity & Mutual Authentication kind: meta -version: "n/a" -last_updated: "2026-04-29" -last_verified: "2026-04-29" +version: 'n/a' +last_updated: '2026-04-29' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable -tags: ["architecture", "identity", "auth", "BRC-31", "BRC-103", "BRC-104"] +tags: ['architecture', 'identity', 'auth', 'BRC-31', 'BRC-103', 'BRC-104'] --- # Identity & Mutual Authentication @@ -88,12 +88,12 @@ MessageBox is a higher-level messaging substrate built on BRC-103/104: ## BRC-31 vs BRC-103/104: When to Use Which -| Use case | Use | -|----------|-----| -| HTTP API mutual auth (REST/Express) | BRC-31 via `@bsv/auth-express-middleware` | -| Persistent WebSocket channel | BRC-103/104 via `@bsv/authsocket` | -| Store-and-forward messaging | MessageBox via `@bsv/message-box-client` (uses BRC-103/104 internally) | -| Payment + identity in one HTTP request | BRC-121 + BRC-31 together | +| Use case | Use | +| -------------------------------------- | ---------------------------------------------------------------------- | +| HTTP API mutual auth (REST/Express) | BRC-31 via `@bsv/auth-express-middleware` | +| Persistent WebSocket channel | BRC-103/104 via `@bsv/authsocket` | +| Store-and-forward messaging | MessageBox via `@bsv/message-box-client` (uses BRC-103/104 internally) | +| Payment + identity in one HTTP request | BRC-121 + BRC-31 together | ## Certificate-Based Identity (BRC-103/104 Extension) diff --git a/docs/architecture/index.md b/docs/architecture/index.md index db265490e..a3a9316ce 100644 --- a/docs/architecture/index.md +++ b/docs/architecture/index.md @@ -2,12 +2,12 @@ id: architecture-overview title: Architecture kind: meta -version: "n/a" -last_updated: "2026-04-29" -last_verified: "2026-04-29" +version: 'n/a' +last_updated: '2026-04-29' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable -tags: ["architecture"] +tags: ['architecture'] --- # Architecture @@ -16,16 +16,16 @@ The BSV TypeScript stack is organized as a foundation-to-application hierarchy. ## Layers -| Layer | Package(s) | Who uses it | -|-------|-----------|-------------| -| Foundation | `@bsv/sdk` | Protocol engineers — direct access to cryptographic primitives and script engine | -| Wallet Interface | BRC-100 boundary | All layers above communicate with wallets through this standard interface | -| Application wrapper | `@bsv/simple` | App developers — high-level payments, tokens, inscriptions, credentials | -| Wallet builder toolkit | `@bsv/wallet-toolbox` | Wallet developers — assemble BRC-100-compliant wallets from modular pieces | -| Overlay network | `@bsv/overlay`, `@bsv/overlay-express` | Service operators — index and serve on-chain data | -| Messaging | `@bsv/authsocket`, `@bsv/message-box-client` | Apps needing encrypted P2P communication | -| Monetization | `@bsv/402-pay`, `@bsv/payment-express-middleware` | APIs requiring micropayment access control | -| Identity | `@bsv/auth-express-middleware`, `@bsv/authsocket` | Apps requiring mutual authentication | +| Layer | Package(s) | Who uses it | +| ---------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------- | +| Foundation | `@bsv/sdk` | Protocol engineers — direct access to cryptographic primitives and script engine | +| Wallet Interface | BRC-100 boundary | All layers above communicate with wallets through this standard interface | +| Application wrapper | `@bsv/simple` | App developers — high-level payments, tokens, inscriptions, credentials | +| Wallet builder toolkit | `@bsv/wallet-toolbox` | Wallet developers — assemble BRC-100-compliant wallets from modular pieces | +| Overlay network | `@bsv/overlay`, `@bsv/overlay-express` | Service operators — index and serve on-chain data | +| Messaging | `@bsv/authsocket`, `@bsv/message-box-client` | Apps needing encrypted P2P communication | +| Monetization | `@bsv/402-pay`, `@bsv/payment-express-middleware` | APIs requiring micropayment access control | +| Identity | `@bsv/auth-express-middleware`, `@bsv/authsocket` | Apps requiring mutual authentication | ## Key Design Documents diff --git a/docs/architecture/layers.md b/docs/architecture/layers.md index f5c415244..da4b77277 100644 --- a/docs/architecture/layers.md +++ b/docs/architecture/layers.md @@ -4,7 +4,7 @@ title: Stack Layers kind: meta version: 'n/a' last_updated: '2026-05-01' -last_verified: '2026-05-01' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable tags: ['architecture', 'layers'] diff --git a/docs/conformance/contributing-vectors.md b/docs/conformance/contributing-vectors.md index 026299ddf..f1fd0463b 100644 --- a/docs/conformance/contributing-vectors.md +++ b/docs/conformance/contributing-vectors.md @@ -1,10 +1,10 @@ --- id: conformance-contributing -title: "Contributing Vectors" +title: 'Contributing Vectors' kind: conformance -version: "1.0.0" -last_updated: "2026-05-14" -last_verified: "2026-05-14" +version: '1.0.0' +last_updated: '2026-05-14' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable tags: [conformance, contributing, vectors] diff --git a/docs/conformance/index.md b/docs/conformance/index.md index cbb7624d3..b4ec4ffc6 100644 --- a/docs/conformance/index.md +++ b/docs/conformance/index.md @@ -1,10 +1,10 @@ --- id: conformance-overview -title: "Conformance" +title: 'Conformance' kind: meta -version: "n/a" -last_updated: "2026-05-14" -last_verified: "2026-05-14" +version: 'n/a' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable tags: [conformance, testing, cross-language, vectors] @@ -14,7 +14,9 @@ tags: [conformance, testing, cross-language, vectors] The TypeScript stack is the reference source for portable BSV behavior. The conformance corpus turns that behavior into language-neutral JSON fixtures that SDKs, wallets, and infrastructure clients can reuse. -Current corpus: **6,625 vectors across 72 JSON files** (as of 2026-05-14). `conformance/META.json` is the authoritative index. +The current corpus totals are generated from `conformance/META.json` and the +parity matrix on the [Generated Stack Facts](../reference/stack-facts.md) page. +CI rejects drift between those sources and the 74 JSON vector files. ## How It Works @@ -26,28 +28,28 @@ Current corpus: **6,625 vectors across 72 JSON files** (as of 2026-05-14). `conf ## Runner Entry Points -| Command | What It Does | -|---|---| -| `pnpm conformance` | Runs `conformance/runner/src/runner.js`; validates vector structure and writes reports | -| `pnpm conformance --validate-only` | Validates vector JSON only | -| `pnpm conformance --vectors conformance/vectors/wallet/brc100` | Runs the structural runner against a subset directory | -| `pnpm --filter @bsv/conformance-runner-ts test` | Runs the TypeScript/Jest dispatcher for SDK categories it recognizes | +| Command | What It Does | +| -------------------------------------------------------------- | -------------------------------------------------------------------------------------- | +| `pnpm conformance` | Runs `conformance/runner/src/runner.js`; validates vector structure and writes reports | +| `pnpm conformance --validate-only` | Validates vector JSON only | +| `pnpm conformance --vectors conformance/vectors/wallet/brc100` | Runs the structural runner against a subset directory | +| `pnpm --filter @bsv/conformance-runner-ts test` | Runs the TypeScript/Jest dispatcher for SDK categories it recognizes | Reports from the structural runner land in `conformance/runner/reports/`. ## Coverage -| Domain | BRCs Covered | Vector Path | -|---|---|---| -| SDK keys + crypto | BRC-42 + general primitives (AES, ECDSA, ECIES, hashes, HMAC, signatures) | `conformance/vectors/sdk/{keys,crypto}/` (8 files) | -| SDK transactions | BRC-74 MerklePath + BRC-62 serialization / BEEF / EF | `conformance/vectors/sdk/transactions/` | -| SDK scripts | BRC-14 Script parsing, encoding, sighash, evaluation (SV Node + Teranode fixtures) | `conformance/vectors/sdk/scripts/evaluation.json` (5,116 vectors) | -| SDK compat | BRC-77 BSM compatibility | `conformance/vectors/sdk/compat/bsm.json` | -| Wallet BRC-100 | Full `WalletInterface` (27 method files, ~950 vectors) | `conformance/vectors/wallet/brc100/` | -| Wallet BRC-29 | Payment key derivation | `conformance/vectors/wallet/brc29/payment-derivation.json` | -| Messaging BRC-31 | Authrite signature format + authsocket | `conformance/vectors/messaging/{brc31,authsocket}.json` | -| Auth / Overlay / Broadcast / Payments / Storage / Sync | BRC-31 handshake, BRC-62/20/22, BRC-29/121, BRC-26 UHRP, GASP, etc. | Multiple files under each domain | -| Regressions | 12 historical cross-SDK bug reproductions (go-sdk#306, ts-sdk#31, etc.) | `conformance/vectors/regressions/` (36 vectors) | +| Domain | BRCs Covered | Vector Path | +| ------------------------------------------------------ | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------- | +| SDK keys + crypto | BRC-42 + general primitives (AES, ECDSA, ECIES, hashes, HMAC, signatures) | `conformance/vectors/sdk/{keys,crypto}/` (8 files) | +| SDK transactions | BRC-74 MerklePath + BRC-62 serialization / BEEF / EF | `conformance/vectors/sdk/transactions/` | +| SDK scripts | BRC-14 Script parsing, encoding, sighash, evaluation (SV Node + Teranode fixtures) | `conformance/vectors/sdk/scripts/evaluation.json` (5,116 vectors) | +| SDK compat | BRC-77 BSM compatibility | `conformance/vectors/sdk/compat/bsm.json` | +| Wallet BRC-100 | Full `WalletInterface` (27 method files, ~950 vectors) | `conformance/vectors/wallet/brc100/` | +| Wallet BRC-29 | Payment key derivation | `conformance/vectors/wallet/brc29/payment-derivation.json` | +| Messaging BRC-31 | Authrite signature format + authsocket | `conformance/vectors/messaging/{brc31,authsocket}.json` | +| Auth / Overlay / Broadcast / Payments / Storage / Sync | BRC-31 handshake, BRC-62/20/22, BRC-29/121, BRC-26 UHRP, GASP, etc. | Multiple files under each domain | +| Regressions | Historical cross-SDK bug reproductions (go-sdk#306, ts-sdk#31, etc.) | `conformance/vectors/regressions/` | ## Vector Format @@ -89,11 +91,16 @@ For a non-TypeScript SDK or wallet: 4. Compare your actual output to each vector's `expected` object. 5. Track unsupported categories explicitly rather than silently ignoring them. -## Recent Improvements (May 2026) +## Maintained contracts -- All legacy-format vector files were normalized to the modern schema-compliant shape (`brc` as array, correct `parity_class` enum, relative `$schema`). -- The structural runner (`conformance/runner/src/runner.js`) was updated to cleanly support the special regression vector format with no warning spam. -- The corpus is now in a robust state for cross-language ports (Go, Rust, Python). +- `pnpm conformance --validate-only` validates the complete structural corpus. +- `pnpm docs:facts:check` verifies metadata, parity classifications, and + generated totals. +- `pnpm test:governance` owns every intended or skipped behavior with a reason, + owner, review date, and removal condition. +- The TypeScript/Jest behavior runner and package suites provide executable + implementation assertions; a structural pass must not be described as a + behavioral pass. ## Next Steps diff --git a/docs/conformance/runner-ts.md b/docs/conformance/runner-ts.md index e627cac9c..3ac44341a 100644 --- a/docs/conformance/runner-ts.md +++ b/docs/conformance/runner-ts.md @@ -1,10 +1,10 @@ --- id: conformance-runner-ts -title: "TypeScript Runner" +title: 'TypeScript Runner' kind: conformance -version: "1.0.0" -last_updated: "2026-05-14" -last_verified: "2026-05-14" +version: '1.0.0' +last_updated: '2026-05-14' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable tags: [conformance, runner, typescript] @@ -37,11 +37,11 @@ What it does: Supported flags: -| Flag | Meaning | -|---|---| +| Flag | Meaning | +| ----------------- | ---------------------------------------------------------------------- | | `--validate-only` | Load and validate vector files without writing execution-style results | -| `--vectors ` | Use a vector root other than `conformance/vectors` | -| `--report ` | Write JUnit XML to the supplied path | +| `--vectors ` | Use a vector root other than `conformance/vectors` | +| `--report ` | Write JUnit XML to the supplied path | Examples: diff --git a/docs/conformance/vectors.md b/docs/conformance/vectors.md index 86cd642b6..1e26c9960 100644 --- a/docs/conformance/vectors.md +++ b/docs/conformance/vectors.md @@ -1,10 +1,10 @@ --- id: conformance-vectors -title: "Vector Catalog" +title: 'Vector Catalog' kind: conformance -version: "1.0.0" -last_updated: "2026-05-14" -last_verified: "2026-05-14" +version: '1.0.0' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable tags: [conformance, vectors, catalog] @@ -14,7 +14,10 @@ tags: [conformance, vectors, catalog] The conformance corpus is the shared test fixture set for TypeScript and other implementations. It is intentionally implementation-neutral: each JSON file defines inputs, expected outputs, metadata, and the specification area it exercises. -Current corpus: **6,625 vectors across 72 JSON files**, last indexed on 2026-05-14 in `conformance/META.json`. +Current totals and runner outcomes are published on +[Generated Stack Facts](../reference/stack-facts.md). The detailed, +machine-readable file-by-file view is `conformance/PARITY_MATRIX.json`; CI +regenerates and compares it to the corpus. ## Repository Layout @@ -32,7 +35,7 @@ conformance/vectors/ sdk/scripts/evaluation.json (5,116 vectors) sdk/transactions/{merkle-path,serialization}.json storage/uhrp-http.json - sync/{brc40-user-state,gasp-protocol}.json + sync/{brc40-user-state,brc136-basm,gasp-protocol}.json wallet/brc100/*.json (27 files) wallet/brc29/payment-derivation.json wallet/storage/adapter-conformance.json @@ -66,57 +69,57 @@ Always inspect the target JSON file before porting a vector to another language; ## Coverage By Directory -| Directory | Vector Count | What It Covers | -|---|---:|---| -| `sdk/crypto` + `sdk/keys` | ~140 | AES, ECDSA, ECIES, HMAC, hashes, BRC-42 derivation, PrivateKey/PublicKey | -| `sdk/transactions` | 31 | BRC-62 serialization, BEEF, EF, BRC-74 MerklePath | -| `sdk/scripts` | 5,116 | Full script engine parity (parsing, encoding, sighash, evaluation with SV Node + Teranode fixtures) | -| `sdk/compat` | 9 | BRC-77 BSM | -| `wallet/brc100` | ~950 | Complete WalletInterface coverage across 27 files (many stateful methods marked `intended`) | -| `wallet/brc29` + `wallet/storage` | 45 | BRC-29 derivation + storage adapter conformance | -| `messaging` + `auth` + `overlay` + `broadcast` + `payments` + `storage` + `sync` | ~200 | Full protocol shape validation for BRC-31, BRC-29/121, BRC-62/20/22, BRC-26, GASP, etc. | -| `regressions` | 36 | 12 historical cross-implementation bug reproductions | +| Directory | Vector Count | What It Covers | +| -------------------------------------------------------------------------------- | -----------: | --------------------------------------------------------------------------------------------------- | +| `sdk/crypto` + `sdk/keys` | ~140 | AES, ECDSA, ECIES, HMAC, hashes, BRC-42 derivation, PrivateKey/PublicKey | +| `sdk/transactions` | 31 | BRC-62 serialization, BEEF, EF, BRC-74 MerklePath | +| `sdk/scripts` | 5,116 | Full script engine parity (parsing, encoding, sighash, evaluation with SV Node + Teranode fixtures) | +| `sdk/compat` | 9 | BRC-77 BSM | +| `wallet/brc100` | ~950 | Complete WalletInterface coverage across 27 files (many stateful methods marked `intended`) | +| `wallet/brc29` + `wallet/storage` | 45 | BRC-29 derivation + storage adapter conformance | +| `messaging` + `auth` + `overlay` + `broadcast` + `payments` + `storage` + `sync` | ~200 | Full protocol shape validation for BRC-31, BRC-29/121, BRC-62/20/22, BRC-26, GASP, etc. | +| `regressions` | 36 | 12 historical cross-implementation bug reproductions | ## Wallet BRC-100 Current BRC-100 conformance coverage is focused on deterministic crypto and key methods: -| File | Vectors | Methods | -|---|---:|---| -| `wallet/brc100/*.json` (25 files) | 950 | Full `WalletInterface`: getPublicKey, create/verifyHmac/Signature, encrypt/decrypt, revealKeyLinkage*, create/sign/abortAction, listActions, internalizeAction, list/relinquishOutputs, acquire/list/prove/relinquishCertificates, discover*, isAuthenticated, waitForAuthentication, getHeight/Header/Network/Version (100% coverage) | +| File | Vectors | Methods | +| ---------------------- | --------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `wallet/brc100/*.json` | Method-level fixtures | `WalletInterface` crypto, action, output, certificate, discovery, authentication, chain, network, and version methods; stateful cases retain explicit intended classifications | Use the [BRC-100 wallet method reference](../specs/brc-100-wallet.md) for the full interface shape. Use this catalog to see which parts already have portable fixtures. ## Coverage By BRC -| BRC | Current Vector Areas | Status | -|---|---|---| -| BRC-29 | `wallet/brc29/payment-derivation.json` | available | -| BRC-31 | `messaging/brc31/authrite-signature.json` | available | -| BRC-42 | `sdk/keys/key-derivation.json`, key fixtures | available | -| BRC-74 | `sdk/transactions/merkle-path.json` | available | -| BRC-77 | `sdk/compat/bsm.json` | available | -| BRC-100 | `wallet/brc100/*.json` (25 files) | full (100%) | -| BRC-14 | `sdk/scripts/evaluation.json` | available, including SV Node and Teranode fixtures | +| BRC | Current Vector Areas | Status | +| ------- | -------------------------------------------- | -------------------------------------------------- | +| BRC-29 | `wallet/brc29/payment-derivation.json` | available | +| BRC-31 | `messaging/brc31/authrite-signature.json` | available | +| BRC-42 | `sdk/keys/key-derivation.json`, key fixtures | available | +| BRC-74 | `sdk/transactions/merkle-path.json` | available | +| BRC-77 | `sdk/compat/bsm.json` | available | +| BRC-100 | `wallet/brc100/*.json` (25 files) | full (100%) | +| BRC-14 | `sdk/scripts/evaluation.json` | available, including SV Node and Teranode fixtures | ## Regression Fixtures Regression files reproduce bugs found in TypeScript or other SDKs so new implementations can prove they do not repeat them. -| Regression | Source Issue | -|---|---| -| `beef-v2-txid-panic` | `go-sdk#306` | -| `privatekey-modular-reduction` | `ts-sdk#31` | -| `merkle-path-odd-node` | `go-sdk#298` | -| `uhrp-url-parity` | `go-sdk#310` | -| `script-lshift-truncation` | `ts-sdk#493` | -| `script-shift-endianness` | `ts-sdk#377` | -| `tx-sequence-zero-sighash` | `ts-sdk#371` | -| `script-writebin-empty` | `ts-sdk#336` | -| `script-fromasm-numeric-token` | `ts-sdk#42` | -| `fee-model-mismatch` | `go-sdk#267` | -| `bip276-hex-decode` | `go-sdk#286` | -| `beef-isvalid-hydration` | `go-sdk#167` | +| Regression | Source Issue | +| ------------------------------ | ------------ | +| `beef-v2-txid-panic` | `go-sdk#306` | +| `privatekey-modular-reduction` | `ts-sdk#31` | +| `merkle-path-odd-node` | `go-sdk#298` | +| `uhrp-url-parity` | `go-sdk#310` | +| `script-lshift-truncation` | `ts-sdk#493` | +| `script-shift-endianness` | `ts-sdk#377` | +| `tx-sequence-zero-sighash` | `ts-sdk#371` | +| `script-writebin-empty` | `ts-sdk#336` | +| `script-fromasm-numeric-token` | `ts-sdk#42` | +| `fee-model-mismatch` | `go-sdk#267` | +| `bip276-hex-decode` | `go-sdk#286` | +| `beef-isvalid-hydration` | `go-sdk#167` | ## Running Vectors @@ -146,7 +149,8 @@ pnpm conformance --report conformance/runner/reports/results.xml ## Porting To Another Implementation -1. Read `conformance/META.json` to confirm the corpus version and current vector list. +1. Read `conformance/META.json` and `conformance/PARITY_MATRIX.json` to confirm + corpus totals and file-level parity status. 2. Start with deterministic SDK vectors before stateful wallet vectors. 3. Treat `wallet/brc100` as method-level fixtures, not as a complete wallet behavior test suite yet. 4. Preserve vector IDs and expected error semantics when adding a runner for another language. diff --git a/docs/get-started/choose-your-stack.md b/docs/get-started/choose-your-stack.md index 08847b1ac..00666be26 100644 --- a/docs/get-started/choose-your-stack.md +++ b/docs/get-started/choose-your-stack.md @@ -2,12 +2,12 @@ id: choose-your-stack title: Choose Your Stack kind: meta -version: "n/a" -last_updated: "2026-04-30" -last_verified: "2026-04-30" +version: 'n/a' +last_updated: '2026-04-30' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable -tags: ["decision-guide"] +tags: ['decision-guide'] --- # Choose Your Stack @@ -120,28 +120,28 @@ The SDK provides secp256k1/r1 cryptography, hashing, scripts, transactions, BEEF Use the infrastructure docs when you need shared services rather than npm packages. -| Service | First page | -|---------|------------| -| Wallet state and UTXO storage | [Wallet Infra](../infrastructure/wallet-infra.md) | +| Service | First page | +| ------------------------------------ | ------------------------------------------------------------- | +| Wallet state and UTXO storage | [Wallet Infra](../infrastructure/wallet-infra.md) | | Store-and-forward encrypted messages | [Message Box Server](../infrastructure/message-box-server.md) | -| Shared on-chain topic lookup | [Overlay Server](../infrastructure/overlay-server.md) | -| Content-addressed files | [UHRP servers](../infrastructure/uhrp-server-basic.md) | -| Wallet authentication backend | [WAB](../infrastructure/wab.md) | -| Block headers and Merkle roots | [Chaintracks Server](../infrastructure/chaintracks-server.md) | +| Shared on-chain topic lookup | [Overlay Server](../infrastructure/overlay-server.md) | +| Content-addressed files | [UHRP servers](../infrastructure/uhrp-server-basic.md) | +| Wallet authentication backend | [WAB](../infrastructure/wab.md) | +| Block headers and Merkle roots | [Chaintracks Server](../infrastructure/chaintracks-server.md) | ## Decision Matrix -| What you're building | Start with | Usually adds | -|----------------------|------------|--------------| -| Browser app | `@bsv/simple/browser` | `@bsv/message-box-client`, overlays | -| Transaction-building app | `@bsv/wallet-helper` | `@bsv/templates`, BRC-100 method reference | -| Server agent | `@bsv/simple/server` | `@bsv/402-pay`, Message Box | -| BRC-100 wallet | `@bsv/wallet-toolbox` | Wallet Infra, WAB, Chaintracks | -| Protocol library | `@bsv/sdk` | Conformance vectors | -| Overlay node | `@bsv/overlay`, `@bsv/overlay-express` | `@bsv/overlay-topics`, GASP | -| Token system | `@bsv/btms`, `@bsv/btms-permission-module` | Overlay topics, wallet permissions | -| Authenticated API | `@bsv/auth-express-middleware` | BRC-100 wallet | -| Payment-gated API | `@bsv/402-pay` | `@bsv/payment-express-middleware` | -| File storage | `@bsv/overlay-topics` | UHRP server | +| What you're building | Start with | Usually adds | +| ------------------------ | ------------------------------------------ | ------------------------------------------ | +| Browser app | `@bsv/simple/browser` | `@bsv/message-box-client`, overlays | +| Transaction-building app | `@bsv/wallet-helper` | `@bsv/templates`, BRC-100 method reference | +| Server agent | `@bsv/simple/server` | `@bsv/402-pay`, Message Box | +| BRC-100 wallet | `@bsv/wallet-toolbox` | Wallet Infra, WAB, Chaintracks | +| Protocol library | `@bsv/sdk` | Conformance vectors | +| Overlay node | `@bsv/overlay`, `@bsv/overlay-express` | `@bsv/overlay-topics`, GASP | +| Token system | `@bsv/btms`, `@bsv/btms-permission-module` | Overlay topics, wallet permissions | +| Authenticated API | `@bsv/auth-express-middleware` | BRC-100 wallet | +| Payment-gated API | `@bsv/402-pay` | `@bsv/payment-express-middleware` | +| File storage | `@bsv/overlay-topics` | UHRP server | See [Packages](../packages/index.md) for the complete package list. diff --git a/docs/get-started/concepts.md b/docs/get-started/concepts.md index 707c92f1e..4b90d7050 100644 --- a/docs/get-started/concepts.md +++ b/docs/get-started/concepts.md @@ -2,12 +2,12 @@ id: concepts title: Key Concepts kind: meta -version: "n/a" -last_updated: "2026-04-30" -last_verified: "2026-04-30" +version: 'n/a' +last_updated: '2026-04-30' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable -tags: ["concepts", "protocol"] +tags: ['concepts', 'protocol'] --- # Key Concepts diff --git a/docs/get-started/index.md b/docs/get-started/index.md index 07e609a31..ca8b6c902 100644 --- a/docs/get-started/index.md +++ b/docs/get-started/index.md @@ -2,12 +2,12 @@ id: get-started title: Get Started kind: meta -version: "n/a" -last_updated: "2026-04-30" -last_verified: "2026-04-30" +version: 'n/a' +last_updated: '2026-04-30' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable -tags: ["onboarding"] +tags: ['onboarding'] --- # Get Started @@ -99,11 +99,11 @@ Do not generate and discard a production private key at runtime. Persist it in y ## What to Read Next -| Need | Read | -|------|------| -| Pick packages by use case | [Choose Your Stack](./choose-your-stack.md) | -| Build explicit transactions with a wallet | [@bsv/wallet-helper](../packages/helpers/wallet-helper.md) | -| Understand BEEF, wallets, overlays, and BRC-100 | [Key Concepts](./concepts.md) | -| See every BRC-100 method shape | [BRC-100 Wallet Interface](../specs/brc-100-wallet.md) | -| Build a wallet or wallet-like implementation | [@bsv/wallet-toolbox](../packages/wallet/wallet-toolbox.md) | -| Test another implementation against this repo | [Conformance](../conformance/index.md) | +| Need | Read | +| ----------------------------------------------- | ----------------------------------------------------------- | +| Pick packages by use case | [Choose Your Stack](./choose-your-stack.md) | +| Build explicit transactions with a wallet | [@bsv/wallet-helper](../packages/helpers/wallet-helper.md) | +| Understand BEEF, wallets, overlays, and BRC-100 | [Key Concepts](./concepts.md) | +| See every BRC-100 method shape | [BRC-100 Wallet Interface](../specs/brc-100-wallet.md) | +| Build a wallet or wallet-like implementation | [@bsv/wallet-toolbox](../packages/wallet/wallet-toolbox.md) | +| Test another implementation against this repo | [Conformance](../conformance/index.md) | diff --git a/docs/get-started/install.md b/docs/get-started/install.md index bb5e86547..ef362e21b 100644 --- a/docs/get-started/install.md +++ b/docs/get-started/install.md @@ -2,12 +2,12 @@ id: install title: Install kind: meta -version: "n/a" -last_updated: "2026-04-29" -last_verified: "2026-04-29" +version: 'n/a' +last_updated: '2026-04-29' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable -tags: ["installation", "setup"] +tags: ['installation', 'setup'] --- # Install @@ -30,10 +30,10 @@ npm install @bsv/simple @bsv/sdk ## Entry Points -| Import path | Environment | Use case | -|-------------|-------------|----------| -| `@bsv/simple/browser` | Browser | Connect to user's wallet extension | -| `@bsv/simple/server` | Node.js | Self-custodial server wallet | +| Import path | Environment | Use case | +| --------------------- | ----------- | ---------------------------------- | +| `@bsv/simple/browser` | Browser | Connect to user's wallet extension | +| `@bsv/simple/server` | Node.js | Self-custodial server wallet | ### Browser @@ -71,7 +71,7 @@ Turbopack requires extra config to prevent server-only packages from being bundl ```typescript const nextConfig = { - serverExternalPackages: ['@bsv/wallet-toolbox', '@bsv/simple'], + serverExternalPackages: ['@bsv/wallet-toolbox', '@bsv/simple'] } export default nextConfig ``` diff --git a/docs/guides/compiled-package-examples.md b/docs/guides/compiled-package-examples.md new file mode 100644 index 000000000..6efcb4cbb --- /dev/null +++ b/docs/guides/compiled-package-examples.md @@ -0,0 +1,180 @@ +--- +id: compiled-package-examples +title: 'Compiled Package Boundary Examples' +kind: guide +version: '1.0.0' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 +status: stable +tags: [guide, typescript, packages, consumers, examples] +--- + +# Compiled Package Boundary Examples + +These examples are deliberately small. Their purpose is to prove that public +entry points across the stack remain usable together from clean, packed npm +artifacts. `pnpm docs:examples` extracts every fence marked `compile`, packs the +referenced packages and their first-party dependency closure, installs those +tarballs in a temporary consumer with lifecycle scripts disabled, and runs the +native TypeScript compiler. + +They validate package names, exports, declarations, module resolution, and +cross-package type identity. They do not replace behavioral examples, package +tests, browser/mobile bundles, or live-service integration tests. + +## SDK and high-level helpers + +```ts compile +// example-id: sdk-and-simple +import { PrivateKey } from '@bsv/sdk' +import { createWallet, type BrowserWallet } from '@bsv/simple/browser' + +const exampleIdentityKey: string = PrivateKey.fromRandom().toPublicKey().toString() +const connectExampleWallet: () => Promise = createWallet + +void exampleIdentityKey +void connectExampleWallet +``` + +## Credentials and identity + +```ts compile +// example-id: credentials-and-identity +import { BsvDid, type DidDocument } from '@bsv/did' +import type { DIDQuery } from '@bsv/overlay-topics' + +const exampleDidDocument: DidDocument = BsvDid.toDidDocument( + BsvDid.fromPublicKey(PrivateKey.fromRandom().toPublicKey().toDER() as number[]) +) +const acceptDidLookup = (query: DIDQuery): DIDQuery => query + +void exampleDidDocument +void acceptDidLookup +``` + +The compiler combines all marked fences into one consumer module, so imports +from earlier examples are available here just as they would be in one +application. + +## Messaging + +```ts compile +// example-id: messaging +import type { MessageBoxClientOptions } from '@bsv/message-box-client' +import type { PublicProfile } from '@bsv/paymail' + +const exampleMessageBoxOptions: MessageBoxClientOptions = { + host: 'https://messagebox.example' +} +const exampleProfileConsumer = (profile: PublicProfile): string => profile.name + +void exampleMessageBoxOptions +void exampleProfileConsumer +``` + +Public Message Box deployments may serve previously unknown application +origins. An operator allowlist is optional deployment configuration; it does +not replace BRC authentication, permissions, signatures, replay protection, or +request bounds. + +## Authentication and HTTP payments + +```ts compile +// example-id: middleware +import { AuthProofClient, type AuthProofOptions } from '@bsv/auth' +import { create402Fetch, type Payment402Options } from '@bsv/402-pay' +import type { AuthRequest } from '@bsv/auth-express-middleware' +import type { PaymentRequest } from '@bsv/payment-express-middleware' + +const exampleAuthOptions: AuthProofOptions = { + protocol: [2, 'compiled docs example'] +} +const exampleAuthClient = new AuthProofClient(exampleAuthOptions) +const buildPaidFetch = (options: Payment402Options) => create402Fetch(options) +const acceptAuthRequest = (request: AuthRequest): AuthRequest => request +const acceptPaymentRequest = (request: PaymentRequest): PaymentRequest => request + +void exampleAuthClient +void buildPaidFetch +void acceptAuthRequest +void acceptPaymentRequest +``` + +## Overlay and synchronization + +```ts compile +// example-id: overlay-and-gasp +import type { TopicBlockAnchor } from '@bsv/overlay' +import type { GASPStorage } from '@bsv/gasp' +import type { AnyQuery } from '@bsv/overlay-topics' +import type OverlayExpress from '@bsv/overlay-express' + +const exampleAnchorConsumer = (anchor: TopicBlockAnchor): number => anchor.blockHeight +const exampleStorageConsumer = (storage: GASPStorage): GASPStorage => storage +const exampleAnyQuery: AnyQuery = {} +const acceptOverlayServer = (server: OverlayExpress): OverlayExpress => server + +void exampleAnchorConsumer +void exampleStorageConsumer +void exampleAnyQuery +void acceptOverlayServer +``` + +## Wallet storage clients + +```ts compile +// example-id: wallet-storage +import type { SetupWalletArgs } from '@bsv/wallet-toolbox' +import { StorageClient } from '@bsv/wallet-toolbox-client' +import type { WalletRelayServiceOptions } from '@bsv/wallet-relay' + +const exampleWalletSetup = (args: SetupWalletArgs): SetupWalletArgs => args +type ExampleStorageOptions = ConstructorParameters[2] +const acceptStorageOptions = (options: ExampleStorageOptions): ExampleStorageOptions => options +const acceptRelayOptions = (options: WalletRelayServiceOptions): WalletRelayServiceOptions => + options + +void exampleWalletSetup +void acceptStorageOptions +void acceptRelayOptions +``` + +Remote Wallet Storage is a public service in many deployments. Keep its +cross-domain default configurable and public unless an operator explicitly +enables an origin allowlist; enforce authorization and identity isolation +regardless of CORS mode. + +## Network messages + +```ts compile +// example-id: network +import { tryDecodeMessage, type DecodedMessage } from '@bsv/teranode-listener' + +const decodeNetworkMessage = (bytes: Uint8Array): DecodedMessage | null => tryDecodeMessage(bytes) + +void decodeNetworkMessage +``` + +## WASM verification + +```ts compile +// example-id: verifast +import { BdkVerifier, type BdkVerifierOptions } from '@bsv/verifast' + +const exampleVerifierOptions: BdkVerifierOptions = { mode: 'auto' } +const exampleVerifier = new BdkVerifier(exampleVerifierOptions) + +void exampleVerifier +``` + +Run: + +```bash +pnpm build +pnpm docs:examples +``` + +The command requires built package outputs and network access only when the +clean temporary consumer's external dependencies are not already present in +the pnpm store. It never publishes or deploys an artifact. diff --git a/docs/guides/index.md b/docs/guides/index.md index cc74842d8..2ecdf819b 100644 --- a/docs/guides/index.md +++ b/docs/guides/index.md @@ -1,10 +1,10 @@ --- id: guides-overview -title: "Guides" +title: 'Guides' kind: meta -version: "1.0.0" -last_updated: "2026-04-28" -last_verified: "2026-04-28" +version: '1.0.0' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable tags: [guides, tutorials, how-to] @@ -12,30 +12,44 @@ tags: [guides, tutorials, how-to] # Guides -Comprehensive step-by-step walkthroughs for building production applications with the ts-stack. Each guide includes real code from CLAUDE.md files, runnable examples, and troubleshooting tips. +Comprehensive step-by-step walkthroughs for building production applications +with the ts-stack. Guides use current public APIs, runnable examples, and +explicit operational assumptions. ## Available Guides ### 1. [Build a Wallet-Aware App](./wallet-aware-app.md) + Create a TypeScript application that integrates BRC-100 wallets for transaction creation, signing, and broadcasting. Learn wallet initialization, UTXO management, transaction monitoring, and SDK integration. **Time:** ~20 minutes | **Level:** Intermediate ### 2. [Run an Overlay Node](./run-overlay-node.md) + Deploy a production-ready overlay service that indexes and queries PushDrop data. Configure topic managers, set up MongoDB storage, enable GASP sync, and advertise via SHIP/SLAP for peer discovery. **Time:** ~30 minutes | **Level:** Intermediate ### 3. [Peer-to-Peer Messaging](./peer-to-peer-messaging.md) + Build authenticated, encrypted messaging between peers using BRC-103 mutual authentication. Choose between store-and-forward HTTP (MessageBox) or real-time WebSocket (Authsocket) transport. **Time:** ~25 minutes | **Level:** Intermediate ### 4. [HTTP 402 Payment Gating](./http-402-payments.md) + Monetize your API with Bitcoin SV micropayments using HTTP 402 Payment Required. Build a payment-gated Express server and an auto-paying client that transparently handles payment challenges. **Time:** ~25 minutes | **Level:** Intermediate +### 5. [Compiled Package Boundary Examples](./compiled-package-examples.md) + +See how SDK, identity, messaging, middleware, Overlay, wallet, network, and +WASM packages compose in strict TypeScript. CI compiles these examples against +the exact packed workspace artifacts. + +**Time:** ~10 minutes | **Level:** Intermediate + ## Recommended Learning Path 1. Start with **Wallet-Aware App** if you're new to wallets and transactions diff --git a/docs/index.md b/docs/index.md index 0957094c5..1d81af333 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,10 +2,10 @@ id: home title: ts-stack kind: meta -version: "n/a" -last_updated: "2026-05-01" -last_verified: "2026-05-01" -review_cadence_days: 7 +version: 'n/a' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 status: stable tags: [] --- @@ -25,14 +25,14 @@ This repository is the TypeScript reference stack for BSV application developmen ## Start Here -| You are | Use first | Why | -|---------|-----------|-----| -| Web application developer | [`@bsv/simple/browser`](./get-started/index.md) | Connects to a local BRC-100 wallet without putting keys in app code. | -| Developer coming from another chain | [`@bsv/wallet-helper`](./packages/helpers/wallet-helper.md) | Builds explicit transactions with a fluent builder while the wallet keeps keys and signing. | -| Backend or automation developer | [`@bsv/simple/server`](./get-started/choose-your-stack.md#server-agent-automated-self-custodial) | Runs a self-custodial server wallet from a private key and storage endpoint. | -| Wallet developer | [`@bsv/wallet-toolbox`](./packages/wallet/wallet-toolbox.md) | Reference components for building a BRC-100 wallet. | -| Protocol engineer | [`@bsv/sdk`](./packages/sdk/bsv-sdk.md) | Core crypto, scripts, transactions, BEEF, BUMP, and wallet interface types. | -| Technical evaluator | [Architecture](./architecture/index.md) and [Conformance](./conformance/index.md) | Shows boundaries, current coverage, and what other implementations must match. | +| You are | Use first | Why | +| ----------------------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------- | +| Web application developer | [`@bsv/simple/browser`](./get-started/index.md) | Connects to a local BRC-100 wallet without putting keys in app code. | +| Developer coming from another chain | [`@bsv/wallet-helper`](./packages/helpers/wallet-helper.md) | Builds explicit transactions with a fluent builder while the wallet keeps keys and signing. | +| Backend or automation developer | [`@bsv/simple/server`](./get-started/choose-your-stack.md#server-agent-automated-self-custodial) | Runs a self-custodial server wallet from a private key and storage endpoint. | +| Wallet developer | [`@bsv/wallet-toolbox`](./packages/wallet/wallet-toolbox.md) | Reference components for building a BRC-100 wallet. | +| Protocol engineer | [`@bsv/sdk`](./packages/sdk/bsv-sdk.md) | Core crypto, scripts, transactions, BEEF, BUMP, and wallet interface types. | +| Technical evaluator | [Architecture](./architecture/index.md) and [Conformance](./conformance/index.md) | Shows boundaries, current coverage, and what other implementations must match. | ## Minimal App Example @@ -53,14 +53,14 @@ For raw BRC-100 work, use `WalletClient` from `@bsv/sdk` and call methods such a ## Package Domains -| Domain | Packages | What they cover | -|--------|----------|-----------------| -| SDK | `@bsv/sdk` | Crypto, scripts, transactions, BEEF/BUMP, BRC-100 types, wallet substrates. | -| Wallet | `@bsv/wallet-toolbox`, BTMS, permission module, wallet relay | Wallet implementation, storage, signing, permissions, token flows, mobile pairing. | -| Overlays | `@bsv/overlay`, `@bsv/overlay-express`, topics, discovery, GASP | Shared on-chain context, topic validation, lookup services, sync. | -| Messaging | Message Box, Authsocket, Paymail | Store-and-forward messages, live authenticated channels, identity-based addressing. | -| Middleware | Auth, HTTP 402, payment express | Express middleware for identity and payment-gated APIs. | -| Helpers | `@bsv/simple`, `@bsv/wallet-helper`, templates, DID, amount utilities | Higher-level developer ergonomics, including wallet-aware app helpers and fluent transaction building. | +| Domain | Packages | What they cover | +| ---------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | +| SDK | `@bsv/sdk` | Crypto, scripts, transactions, BEEF/BUMP, BRC-100 types, wallet substrates. | +| Wallet | `@bsv/wallet-toolbox`, BTMS, permission module, wallet relay | Wallet implementation, storage, signing, permissions, token flows, mobile pairing. | +| Overlays | `@bsv/overlay`, `@bsv/overlay-express`, topics, discovery, GASP | Shared on-chain context, topic validation, lookup services, sync. | +| Messaging | Message Box, Authsocket, Paymail | Store-and-forward messages, live authenticated channels, identity-based addressing. | +| Middleware | Auth, HTTP 402, payment express | Express middleware for identity and payment-gated APIs. | +| Helpers | `@bsv/simple`, `@bsv/wallet-helper`, templates, DID, amount utilities | Higher-level developer ergonomics, including wallet-aware app helpers and fluent transaction building. | ## Important References @@ -69,6 +69,8 @@ For raw BRC-100 work, use `WalletClient` from `@bsv/sdk` and call methods such a - [Stack Layers](./architecture/layers.md) - how packages and infrastructure fit together. - [Infrastructure](./infrastructure/index.md) - service status and deployed endpoint names. - [Vector Catalog](./conformance/vectors.md) - current conformance coverage and file paths. +- [Generated Stack Facts](./reference/stack-facts.md) - source versions, runtime profiles, release routes, infrastructure manifests, and conformance totals. +- [Release and Operations Guide](./reference/release-operations.md) - reviewed publication, deployment, failure handling, and rollback. ## Source Discipline diff --git a/docs/infrastructure/index.md b/docs/infrastructure/index.md index 9bb6e6d7c..bb13bd1c7 100644 --- a/docs/infrastructure/index.md +++ b/docs/infrastructure/index.md @@ -1,10 +1,10 @@ --- id: infra-overview -title: "Infrastructure" +title: 'Infrastructure' kind: meta -version: "1.0.0" -last_updated: "2026-04-30" -last_verified: "2026-04-30" +version: '1.0.0' +last_updated: '2026-04-30' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable tags: [infrastructure, deployment, reference-implementations, ts-stack] @@ -16,36 +16,41 @@ Infrastructure components are deployed services — not npm packages, but applic ## Components Overview -| Component | Purpose | Database | Status | Deploy target | -|-----------|---------|----------|--------|----------------| -| [Chaintracks Server](chaintracks-server.md) | Block header chain + Merkle root validation (SPV) over REST (v1 + v2) | In-memory / CDN bulk files | stable | Docker / Kubernetes | -| [Message Box Server](message-box-server.md) | Secure peer-to-peer messaging with real-time WebSocket delivery | MySQL 8.0 | stable | Docker / Kubernetes | -| [Overlay Server](overlay-server.md) | Topic managers and lookup services for overlay network | MongoDB + MySQL/Knex | stable | Docker / Kubernetes | -| [UHRP Server (Basic)](uhrp-server-basic.md) | Lightweight file storage via local filesystem (dev/test) | None (filesystem) | beta | Local Docker | -| [UHRP Server (Cloud Bucket)](uhrp-server-cloud-bucket.md) | Production UHRP storage via Google Cloud Storage | Optional Cloud SQL | stable | Google Cloud Run | -| [Wallet Abstraction Backend (WAB)](wab.md) | Multi-factor user authentication (SMS, ID verification, OTP) | SQLite (dev) / MySQL (prod) | stable | Docker / Kubernetes / Cloud Run | -| [Wallet Infrastructure](wallet-infra.md) | JSON-RPC wallet UTXO storage and management | MySQL 8.0 | stable | Docker / Kubernetes | +| Component | Purpose | Database | Status | Deploy target | +| --------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------- | ------ | ------------------------------- | +| [Chaintracks Server](chaintracks-server.md) | Block header chain + Merkle root validation (SPV) over REST (v1 + v2) | In-memory / CDN bulk files | stable | Docker / Kubernetes | +| [Message Box Server](message-box-server.md) | Secure peer-to-peer messaging with real-time WebSocket delivery | MySQL 8.0 | stable | Docker / Kubernetes | +| [Overlay Server](overlay-server.md) | Topic managers and lookup services for overlay network | MongoDB + MySQL/Knex | stable | Docker / Kubernetes | +| [UHRP Server (Basic)](uhrp-server-basic.md) | Lightweight file storage via local filesystem (dev/test) | None (filesystem) | beta | Local Docker | +| [UHRP Server (Cloud Bucket)](uhrp-server-cloud-bucket.md) | Production UHRP storage via Google Cloud Storage | Optional Cloud SQL | stable | Google Cloud Run | +| [Wallet Abstraction Backend (WAB)](wab.md) | Multi-factor user authentication (SMS, ID verification, OTP) | SQLite (dev) / MySQL (prod) | stable | Docker / Kubernetes / Cloud Run | +| [Wallet Infrastructure](wallet-infra.md) | JSON-RPC wallet UTXO storage and management | MySQL 8.0 | stable | Docker / Kubernetes | ## Decision Matrix: Which Services to Deploy **Building a messaging app?** + - Deploy Message Box Server (MySQL backend, WebSocket support) - Pair with Wallet Infrastructure for UTXO management if handling payments **Building an overlay node?** + - Deploy Overlay Server (MongoDB + MySQL/Knex) - Implement custom topic managers and lookup services, or use reference implementations (ProtoMap, CertMap, UHRP, Identity, etc.) **Hosting UHRP files?** + - Development: UHRP Server (Basic) with local filesystem storage - Production: UHRP Server (Cloud Bucket) on Google Cloud Run with Cloud Storage **Providing wallet services?** + - Deploy WAB for user authentication and key recovery (presentation keys via SMS/ID verification) - Deploy Wallet Infrastructure for UTXO storage (JSON-RPC endpoint) - Combined, these enable wallet-aware applications with key backup/recovery **Building BSV applications?** + - Deploy Message Box Server + Wallet Infrastructure for messaging + wallet capabilities - Deploy WAB if you need multi-factor user authentication - Deploy Overlay Server if you want to operate overlay services or coordinate with other overlay nodes @@ -53,18 +58,21 @@ Infrastructure components are deployed services — not npm packages, but applic ## Deployment Models ### Local Development + - Docker Compose with single-instance services - SQLite or in-memory stores - All services on localhost - See each service's docker-compose.yml for example ### Docker/Kubernetes Production + - Digest-pinned Alpine-based container images with Node 24 - Persistent volumes for databases - Health checks and readiness probes configured - Horizontal scaling via stateless design (except local in-memory state, e.g., WebSocket rooms) ### Cloud-Native (Google Cloud Run) + - UHRP Server (Cloud Bucket) designed for Cloud Run - Stateless HTTP service with cloud bucket storage - Optional Cloud SQL for metadata @@ -74,17 +82,17 @@ Infrastructure components are deployed services — not npm packages, but applic The public BSVA deployment names are driven by the cluster `app_suffix`. For the `us-1` cluster, use these examples in docs, demos, and test configuration: -| Component | Pattern | `us-1` Endpoint | -|---|---|---| -| Wallet Infrastructure | `store-${app_suffix}.bsvb.tech` | `https://store-us-1.bsvb.tech` | -| Message Box | `message-box-${app_suffix}.bsvb.tech` | `https://message-box-us-1.bsvb.tech` | -| Overlay | `overlay-${app_suffix}.bsvb.tech` | `https://overlay-us-1.bsvb.tech` | -| UHRP | `uhrp-${app_suffix}.bsvb.tech` | `https://uhrp-us-1.bsvb.tech` | -| WAB | `wab-${app_suffix}.bsvb.tech` | `https://wab-us-1.bsvb.tech` | -| Chaintracks | `chaintracks-${app_suffix}.bsvb.tech` | `https://chaintracks-us-1.bsvb.tech` | -| Chaintracks CDN | `chaintracks-cdn-${app_suffix}.bsvb.tech` | `https://chaintracks-cdn-us-1.bsvb.tech` | -| Merkle Service | `merkle-service-${app_suffix}.bsvb.tech` | `https://merkle-service-us-1.bsvb.tech` | -| Arcade | `arcade-${app_suffix}.bsvb.tech` | `https://arcade-us-1.bsvb.tech` | +| Component | Pattern | `us-1` Endpoint | +| --------------------- | ----------------------------------------- | ---------------------------------------- | +| Wallet Infrastructure | `store-${app_suffix}.bsvb.tech` | `https://store-us-1.bsvb.tech` | +| Message Box | `message-box-${app_suffix}.bsvb.tech` | `https://message-box-us-1.bsvb.tech` | +| Overlay | `overlay-${app_suffix}.bsvb.tech` | `https://overlay-us-1.bsvb.tech` | +| UHRP | `uhrp-${app_suffix}.bsvb.tech` | `https://uhrp-us-1.bsvb.tech` | +| WAB | `wab-${app_suffix}.bsvb.tech` | `https://wab-us-1.bsvb.tech` | +| Chaintracks | `chaintracks-${app_suffix}.bsvb.tech` | `https://chaintracks-us-1.bsvb.tech` | +| Chaintracks CDN | `chaintracks-cdn-${app_suffix}.bsvb.tech` | `https://chaintracks-cdn-us-1.bsvb.tech` | +| Merkle Service | `merkle-service-${app_suffix}.bsvb.tech` | `https://merkle-service-us-1.bsvb.tech` | +| Arcade | `arcade-${app_suffix}.bsvb.tech` | `https://arcade-us-1.bsvb.tech` | ## Common Requirements @@ -93,6 +101,7 @@ controls, threat model, and release retest checklist are maintained in [Public Service Edge Security](service-edge-security.md). All infrastructure services: + - **Node.js 24** – Runtime environment (`>=24 <25` for every image component) - **Docker & docker-compose** – Local development and containerization - **Environment variables** – Configuration (see each service's Configuration section) diff --git a/docs/infrastructure/overlay-server.md b/docs/infrastructure/overlay-server.md index c6d08e141..e300717ab 100644 --- a/docs/infrastructure/overlay-server.md +++ b/docs/infrastructure/overlay-server.md @@ -1,10 +1,10 @@ --- id: infra-overlay-server -title: "Overlay Server" +title: 'Overlay Server' kind: infra -version: "2.1.6" -last_updated: "2026-06-27" -last_verified: "2026-06-27" +version: '2.1.6' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable tags: [overlay, topic-manager, lookup-service, transaction-routing] @@ -29,30 +29,30 @@ Clients submit transaction outputs via HTTP, the server routes valid outputs thr ## Dependencies -| Type | Requirement | -|------|-------------| -| Database | MongoDB (lookup data), MySQL/Knex (overlay tracking) | +| Type | Requirement | +| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| Database | MongoDB (lookup data), MySQL/Knex (overlay tracking) | | External services | Wallet Storage (service advertisement), Arcade and/or Arc (transaction propagation), Chaintracks/go-chaintracks-compatible headers and reorg stream | -| ts-stack packages | @bsv/sdk, @bsv/overlay-express, @bsv/auth-express-middleware | +| ts-stack packages | @bsv/sdk, @bsv/overlay-express, @bsv/auth-express-middleware | ## HTTP endpoints -| Method | Path | Purpose | -|--------|------|---------| -| POST | /submit | Submit a tagged BEEF transaction for topic admission and network propagation | -| POST | /lookup | Query a lookup service | -| POST | /arc-ingest | Receive Arc/Arcade provider callbacks and Merkle proofs | -| GET | /health/live | Process liveness | -| GET | /health/ready | Readiness for critical dependencies | -| GET | /health | Full health report with provider/BASM context | -| POST | /admin/syncAdvertisements | Refresh SHIP/SLAP advertisements | -| POST | /admin/startGASPSync | Run GASP sync | -| POST | /admin/startBASMSync | Run BASM sync | -| POST | /admin/refreshUnprovenProofs | Try proof providers for old unproven transactions | -| POST | /admin/evictUnproven | Evict old unproven transactions without proof refresh | -| POST | /admin/maintainUnproven | Refresh proofs, then evict remaining old unproven transactions | -| POST | /admin/evictOutpoint | Remove an outpoint from lookup service indexes | -| POST | /admin/janitor | Run SHIP/SLAP host health checks and cleanup | +| Method | Path | Purpose | +| ------ | ---------------------------- | ---------------------------------------------------------------------------- | +| POST | /submit | Submit a tagged BEEF transaction for topic admission and network propagation | +| POST | /lookup | Query a lookup service | +| POST | /arc-ingest | Receive Arc/Arcade provider callbacks and Merkle proofs | +| GET | /health/live | Process liveness | +| GET | /health/ready | Readiness for critical dependencies | +| GET | /health | Full health report with provider/BASM context | +| POST | /admin/syncAdvertisements | Refresh SHIP/SLAP advertisements | +| POST | /admin/startGASPSync | Run GASP sync | +| POST | /admin/startBASMSync | Run BASM sync | +| POST | /admin/refreshUnprovenProofs | Try proof providers for old unproven transactions | +| POST | /admin/evictUnproven | Evict old unproven transactions without proof refresh | +| POST | /admin/maintainUnproven | Refresh proofs, then evict remaining old unproven transactions | +| POST | /admin/evictOutpoint | Remove an outpoint from lookup service indexes | +| POST | /admin/janitor | Run SHIP/SLAP host health checks and cleanup | Additional endpoints exposed by configured topic managers and lookup services (see src/services/ for ProtoMap, CertMap, BasketMap, UHRP, Identity, MessageBox, UMP, etc.). @@ -62,34 +62,34 @@ None (HTTP-only OverlayExpress endpoints). ## Configuration (env vars) -| Variable | Required | Description | -|----------|----------|-------------| -| NODE_NAME | Yes | One-word, lowercase overlay service node identifier | -| SERVER_PRIVATE_KEY | Yes | 32-byte hex root private key for server wallet | -| HOSTING_URL | Yes | Public URL where the node is reachable | -| ADMIN_TOKEN | Yes | Token for admin API access | -| WALLET_STORAGE_URL | Yes | BSV wallet storage endpoint (e.g., `https://store-us-1.bsvb.tech`) | -| NETWORK | Yes | `main` or `test` (BSV blockchain network) | -| ARC_API_KEY | Conditionally | Arc key for fallback transaction broadcasting. Required only when `ARCADE_URL` is unset. | -| ARC_CALLBACK_TOKEN | No | Shared secret expected on `/arc-ingest` callbacks. Recommended for public deployments. | -| ARCADE_URL | Conditionally | Arcade endpoint used as the first-choice broadcaster and proof lookup provider. Required only when `ARC_API_KEY` is unset. | -| ARCADE_API_KEY | No | Arcade API key, when the deployment requires one. | -| ARCADE_DEPLOYMENT_ID | No | Stable Arcade deployment identifier used for callback/proof routing. | -| CHAINTRACKS_URL | No | Explicit go-chaintracks compatible endpoint for headers and reorg SSE. If unset, Arcade can be reused when `USE_ARCADE_CHAINTRACKS=true`. | -| CHAINTRACKS_API_PREFIX | No | Chaintracks API prefix. Defaults to `/chaintracks/v2` for Arcade-mounted Chaintracks. | -| USE_ARCADE_CHAINTRACKS | No | Reuse `ARCADE_URL` for Chaintracks when `CHAINTRACKS_URL` is unset. Defaults to true when `ARCADE_URL` is set. | -| THROW_ON_BROADCAST_FAIL | No | Reject overlay admission if no broadcast provider accepts the transaction. Defaults to `true`. | -| MONGO_URL | Yes | MongoDB connection string | -| KNEX_URL | Yes | MySQL connection string for Knex | -| GASP_ENABLED | No | `true` or `false` (Graph Aware Sync Protocol for overlay sync) | -| BASM_ENABLED | No | Enable BRC-136 BASM synchronization. Defaults to `false`. | -| BASM_REORG_STREAM_ENABLED | No | Subscribe to Chaintracks reorg SSE when Chaintracks is configured. Defaults to `true`. | -| BASM_REORG_SCAN_DEPTH | No | Number of recent blocks to revalidate on reorg reconnect/poll. | -| BASM_BLOCK_POLL_INTERVAL_MS | No | Interval for BASM anchor/header polling. Set to `0` to disable periodic polling. | -| UNPROVEN_EVICTION_BLOCKS | No | Block-age threshold for unproven transaction eviction. | -| UNPROVEN_MAINTENANCE_INTERVAL_MS | No | Periodic refresh-then-evict cadence for unproven transactions. `0` disables periodic maintenance. | -| LOG_LEVEL | No | pino log level. Defaults to `info`. | -| OTEL_* | No | OpenTelemetry exporter/resource configuration. See `infra/OBSERVABILITY.md`. | +| Variable | Required | Description | +| -------------------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| NODE_NAME | Yes | One-word, lowercase overlay service node identifier | +| SERVER_PRIVATE_KEY | Yes | 32-byte hex root private key for server wallet | +| HOSTING_URL | Yes | Public URL where the node is reachable | +| ADMIN_TOKEN | Yes | Token for admin API access | +| WALLET_STORAGE_URL | Yes | BSV wallet storage endpoint (e.g., `https://store-us-1.bsvb.tech`) | +| NETWORK | Yes | `main` or `test` (BSV blockchain network) | +| ARC_API_KEY | Conditionally | Arc key for fallback transaction broadcasting. Required only when `ARCADE_URL` is unset. | +| ARC_CALLBACK_TOKEN | No | Shared secret expected on `/arc-ingest` callbacks. Recommended for public deployments. | +| ARCADE_URL | Conditionally | Arcade endpoint used as the first-choice broadcaster and proof lookup provider. Required only when `ARC_API_KEY` is unset. | +| ARCADE_API_KEY | No | Arcade API key, when the deployment requires one. | +| ARCADE_DEPLOYMENT_ID | No | Stable Arcade deployment identifier used for callback/proof routing. | +| CHAINTRACKS_URL | No | Explicit go-chaintracks compatible endpoint for headers and reorg SSE. If unset, Arcade can be reused when `USE_ARCADE_CHAINTRACKS=true`. | +| CHAINTRACKS_API_PREFIX | No | Chaintracks API prefix. Defaults to `/chaintracks/v2` for Arcade-mounted Chaintracks. | +| USE_ARCADE_CHAINTRACKS | No | Reuse `ARCADE_URL` for Chaintracks when `CHAINTRACKS_URL` is unset. Defaults to true when `ARCADE_URL` is set. | +| THROW_ON_BROADCAST_FAIL | No | Reject overlay admission if no broadcast provider accepts the transaction. Defaults to `true`. | +| MONGO_URL | Yes | MongoDB connection string | +| KNEX_URL | Yes | MySQL connection string for Knex | +| GASP_ENABLED | No | `true` or `false` (Graph Aware Sync Protocol for overlay sync) | +| BASM_ENABLED | No | Enable BRC-136 BASM synchronization. Defaults to `false`. | +| BASM_REORG_STREAM_ENABLED | No | Subscribe to Chaintracks reorg SSE when Chaintracks is configured. Defaults to `true`. | +| BASM_REORG_SCAN_DEPTH | No | Number of recent blocks to revalidate on reorg reconnect/poll. | +| BASM_BLOCK_POLL_INTERVAL_MS | No | Interval for BASM anchor/header polling. Set to `0` to disable periodic polling. | +| UNPROVEN_EVICTION_BLOCKS | No | Block-age threshold for unproven transaction eviction. | +| UNPROVEN_MAINTENANCE_INTERVAL_MS | No | Periodic refresh-then-evict cadence for unproven transactions. `0` disables periodic maintenance. | +| LOG_LEVEL | No | pino log level. Defaults to `info`. | +| OTEL_* | No | OpenTelemetry exporter/resource configuration. See `infra/OBSERVABILITY.md`. | At least one transaction propagation provider must be configured: `ARCADE_URL` or `ARC_API_KEY`. Production deployments should prefer @@ -225,5 +225,5 @@ counts. ## Source -- [GitHub](https://github.com/bsv-blockchain/ts-stack/tree/master/infra/overlay-server) +- [GitHub](https://github.com/bsv-blockchain/ts-stack/tree/main/infra/overlay-server) - [npm package](https://npmjs.com/package/@bsv/overlay-express) diff --git a/docs/packages/helpers/amountinator.md b/docs/packages/helpers/amountinator.md index be6392d05..37e5f50cf 100644 --- a/docs/packages/helpers/amountinator.md +++ b/docs/packages/helpers/amountinator.md @@ -1,16 +1,15 @@ --- id: pkg-amountinator -title: "@bsv/amountinator" +title: '@bsv/amountinator' kind: package domain: helpers -version: "2.1.1" -source_repo: "bsv-blockchain/ts-stack" -source_commit: "unknown" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +version: '2.1.1' +source_repo: 'bsv-blockchain/ts-stack' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 -npm: "https://www.npmjs.com/package/@bsv/amountinator" -repo: "https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/amountinator" +npm: 'https://www.npmjs.com/package/@bsv/amountinator' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/amountinator' status: stable tags: [helpers, amounts, satoshis] --- @@ -30,13 +29,13 @@ npm install @bsv/amountinator ```typescript import { CurrencyConverter } from '@bsv/amountinator' -const converter = new CurrencyConverter() // 5-min auto-refresh +const converter = new CurrencyConverter() // 5-min auto-refresh await converter.initialize() // Auto-detect input currency, convert to user's preference const formatted = await converter.convertAmount('5000') console.log(formatted.formattedAmount) // e.g. "5,000 satoshis" -console.log(formatted.hoverText) // present for very small displayed values +console.log(formatted.hoverText) // present for very small displayed values // Cleanup (stop auto-refresh) converter.dispose() @@ -63,37 +62,43 @@ require both public exports. Node.js 22 or newer is supported. ## Common patterns ### Initialize with auto-refresh + ```typescript -const converter = new CurrencyConverter() // 5-min interval +const converter = new CurrencyConverter() // 5-min interval await converter.initialize() ``` ### Convert with auto-detection + ```typescript -const formatted = await converter.convertAmount('5000') // "5000" or "0.1" or "10 USD" +const formatted = await converter.convertAmount('5000') // "5000" or "0.1" or "10 USD" console.log(formatted.formattedAmount) // formatted for display -console.log(formatted.hoverText) // optional full value for tiny amounts +console.log(formatted.hoverText) // optional full value for tiny amounts ``` ### Convert between specific currencies + ```typescript -const usdAmount = converter.convertCurrency(0.1, 'BSV', 'USD') // 6.2 (if rate = 62) +const usdAmount = converter.convertCurrency(0.1, 'BSV', 'USD') // 6.2 (if rate = 62) ``` ### Get preferred currency symbol + ```typescript -const symbol = converter.getCurrencySymbol() // "$" if USD, "€" if EUR +const symbol = converter.getCurrencySymbol() // "$" if USD, "€" if EUR ``` ### Convert user currency to satoshis + ```typescript -const sats = await converter.convertToSatoshis(10) // If preferred = 'USD', USD→SATS -console.log(sats) // e.g. 1610000 (rounded up) +const sats = await converter.convertToSatoshis(10) // If preferred = 'USD', USD→SATS +console.log(sats) // e.g. 1610000 (rounded up) ``` ### Static converter (no auto-refresh) + ```typescript -const staticConverter = new CurrencyConverter(0) // refreshInterval = 0 +const staticConverter = new CurrencyConverter(0) // refreshInterval = 0 await staticConverter.initialize() const amount = await staticConverter.convertAmount('100') // Rates will not auto-update @@ -142,7 +147,7 @@ const amount = await staticConverter.convertAmount('100') - [@bsv/simple](simple.md) — Wallet with payment operations - [@bsv/fund-wallet](fund-wallet.md) — Faucet that may display amounts -- [@bsv/sdk](https://github.com/bsv-blockchain/sdk-ts) — Transaction building with satoshis +- [@bsv/sdk](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/sdk) — Transaction building with satoshis ## Reference diff --git a/docs/packages/helpers/create-bsv-app.md b/docs/packages/helpers/create-bsv-app.md new file mode 100644 index 000000000..159973798 --- /dev/null +++ b/docs/packages/helpers/create-bsv-app.md @@ -0,0 +1,48 @@ +--- +id: pkg-create-bsv-app +title: 'create-bsv-app' +kind: package +domain: helpers +version: '1.0.2' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 +npm: 'https://www.npmjs.com/package/create-bsv-app' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/create-bsv-app' +status: stable +tags: [helpers, cli, scaffolding, starters] +--- + +# create-bsv-app + +`create-bsv-app` is the supported CLI and starter catalogue for new BSV +applications. It generates React, Express, and full-stack projects, copies +governed complete examples, and can add wallet capabilities to an existing +project. + +## Run + +```bash +npx create-bsv-app new my-app --starter full-stack --yes +cd my-app +npm run dev +``` + +The CLI can also create `react`, `express`, or catalogue starters and supports +interactive, flag, JSON configuration, and local browser-UI inputs. Generated +projects record the resolved starter and layout in `bsv-scaffold.json`. + +Use `--skip-install` when CI or another tool owns dependency installation. +Review generated authentication and nonce-store configuration before +production; multi-process services need a shared atomic replay store. + +The package publishes an installed `create-bsv-app` executable for Node.js 22 +or newer. Package checks validate the packed CLI in a clean consumer with +lifecycle scripts disabled. See the +[package README](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/create-bsv-app#readme) +for the starter catalogue, modes, flags, merge rules, and security boundaries. + +## License + +Open BSV License Version 6. See the +[package license](https://github.com/bsv-blockchain/ts-stack/blob/main/packages/helpers/create-bsv-app/LICENSE.txt). diff --git a/docs/packages/helpers/did-client.md b/docs/packages/helpers/did-client.md index 696b91077..185a552be 100644 --- a/docs/packages/helpers/did-client.md +++ b/docs/packages/helpers/did-client.md @@ -1,16 +1,15 @@ --- id: pkg-did-client -title: "@bsv/did-client" +title: '@bsv/did-client' kind: package domain: helpers -version: "1.2.1" -source_repo: "bsv-blockchain/did-client" -source_commit: "unknown" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +version: '1.2.1' +source_repo: 'bsv-blockchain/ts-stack' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 -npm: "https://www.npmjs.com/package/@bsv/did-client" -repo: "https://github.com/bsv-blockchain/did-client" +npm: 'https://www.npmjs.com/package/@bsv/did-client' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/did-client' status: stable tags: [did, identity, helpers] --- @@ -43,10 +42,7 @@ const didClient = new DIDClient({ // Create a DID token const subjectPublicKey = '025706528f0f6894b2ba505007267ccff1133e004452a1f6b72ac716f246216366' const serialNumber = Utils.toBase64(Utils.toArray('sn-12345-abc', 'utf8')) -const createResult = await didClient.createDID( - serialNumber, - subjectPublicKey -) +const createResult = await didClient.createDID(serialNumber, subjectPublicKey) if (createResult.status === 'success') { console.log(`DID created: ${createResult.txid}`) @@ -66,6 +62,7 @@ if (createResult.status === 'success') { ## Common patterns ### Create a DID token + ```typescript const createResult = await didClient.createDID( Utils.toBase64(Utils.toArray('sn-12345-abc', 'utf8')), @@ -80,6 +77,7 @@ if (createResult.status === 'success') { ``` ### Find DID tokens on overlay + ```typescript const foundDIDs = await didClient.findDID( { @@ -96,6 +94,7 @@ foundDIDs.forEach(did => { ``` ### Query by outpoint + ```typescript const byOutpoint = await didClient.findDID({ outpoint: 'abc123def456.0' @@ -103,6 +102,7 @@ const byOutpoint = await didClient.findDID({ ``` ### Revoke DID by serial number + ```typescript const revokeResult = await didClient.revokeDID({ serialNumber: Utils.toBase64(Utils.toArray('sn-12345-abc', 'utf8')) @@ -114,6 +114,7 @@ if (revokeResult.status === 'success') { ``` ### Pagination and filtering + ```typescript const page1 = await didClient.findDID({ limit: 50, @@ -170,10 +171,10 @@ const page1 = await didClient.findDID({ - [@bsv/simple](simple.md) — High-level wallet with DID support - [@bsv/templates](templates.md) — PushDrop script implementation -- [@bsv/sdk](https://github.com/bsv-blockchain/sdk-ts) — Core transaction and wallet utilities +- [@bsv/sdk](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/sdk) — Core transaction and wallet utilities ## Reference - [API reference (TypeDoc)](https://bsv-blockchain.github.io/ts-stack/api/did-client/) -- [Source on GitHub](https://github.com/bsv-blockchain/did-client) +- [Source on GitHub](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/did-client) - [npm](https://www.npmjs.com/package/@bsv/did-client) diff --git a/docs/packages/helpers/did.md b/docs/packages/helpers/did.md index 379593431..8af056834 100644 --- a/docs/packages/helpers/did.md +++ b/docs/packages/helpers/did.md @@ -1,16 +1,15 @@ --- id: pkg-did -title: "@bsv/did" +title: '@bsv/did' kind: package domain: helpers -version: "0.2.1" -source_repo: "bsv-blockchain/ts-stack" -source_commit: "unknown" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +version: '0.2.1' +source_repo: 'bsv-blockchain/ts-stack' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 -npm: "https://www.npmjs.com/package/@bsv/did" -repo: "https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/did" +npm: 'https://www.npmjs.com/package/@bsv/did' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/did' status: beta tags: [did, sd-jwt, credentials, identity, helpers] --- diff --git a/docs/packages/helpers/fund-wallet.md b/docs/packages/helpers/fund-wallet.md index 002228983..9d8e087f6 100644 --- a/docs/packages/helpers/fund-wallet.md +++ b/docs/packages/helpers/fund-wallet.md @@ -1,16 +1,15 @@ --- id: pkg-fund-wallet -title: "@bsv/fund-wallet" +title: '@bsv/fund-wallet' kind: package domain: helpers -version: "1.4.1" -source_repo: "bsv-blockchain/fund-wallet" -source_commit: "unknown" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +version: '1.4.1' +source_repo: 'bsv-blockchain/ts-stack' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 -npm: "https://www.npmjs.com/package/@bsv/fund-wallet" -repo: "https://github.com/bsv-blockchain/fund-wallet" +npm: 'https://www.npmjs.com/package/@bsv/fund-wallet' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/fund-wallet' status: stable tags: [helpers, testing, faucet, development] --- @@ -65,6 +64,7 @@ npx fund-metanet ## Common patterns ### Check balance only (no Metanet Desktop needed) + ```bash npx fund-metanet \ --chain main \ @@ -72,6 +72,7 @@ npx fund-metanet \ ``` ### Fund wallet (Metanet Desktop must be running) + ```bash npx fund-metanet \ --chain test \ @@ -80,6 +81,7 @@ npx fund-metanet \ ``` ### Using custom storage provider + ```bash npx fund-metanet \ --chain main \ @@ -89,6 +91,7 @@ npx fund-metanet \ ``` ### Interactive mode + ```bash npx fund-metanet # Answer prompts for chain, key, satoshis, etc. @@ -137,10 +140,10 @@ npx fund-metanet - [@bsv/amountinator](amountinator.md) — Could enhance output with currency conversion - [@bsv/simple](simple.md) — Wallet that may use funded address -- [@bsv/sdk](https://github.com/bsv-blockchain/sdk-ts) — Private key and transaction utilities +- [@bsv/sdk](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/sdk) — Private key and transaction utilities ## Reference - [API reference (TypeDoc)](https://bsv-blockchain.github.io/ts-stack/api/fund-wallet/) -- [Source on GitHub](https://github.com/bsv-blockchain/fund-wallet) +- [Source on GitHub](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/fund-wallet) - [npm](https://www.npmjs.com/package/@bsv/fund-wallet) diff --git a/docs/packages/helpers/index.md b/docs/packages/helpers/index.md index 6b84a072c..e9c3a3ebd 100644 --- a/docs/packages/helpers/index.md +++ b/docs/packages/helpers/index.md @@ -2,9 +2,9 @@ id: domain-helpers title: Helpers kind: reference -last_updated: "2026-04-30" -version: "n/a" -last_verified: "2026-04-28" +last_updated: '2026-07-27' +version: 'n/a' +last_verified: '2026-07-27' review_cadence_days: 90 status: stable tags: [packages, helpers] @@ -16,12 +16,13 @@ Utility libraries and helper tools for common BSV operations. Includes high-leve ## Packages -| Package | Purpose | -|---------|---------| -| [@bsv/simple](simple.md) | High-level wallet API for browser and server — manage payments, tokens, inscriptions, DIDs, and credentials | -| [@bsv/wallet-helper](wallet-helper.md) | Fluent transaction builder for explicit wallet-backed transactions, BRC-29 derivation, and ordinal support | -| [@bsv/templates](templates.md) | Predefined ScriptTemplate examples for protocol engineers, including OpReturn, MultiPushDrop, and P2MSKH lock/unlock patterns | -| [@bsv/did](did.md) | SD-JWT VC and optional `did:key` helpers for BSV SDK identity keys | -| [@bsv/did-client](did-client.md) | DID client for creating, revoking, and querying on-chain DIDs with overlay broadcast | -| [@bsv/amountinator](amountinator.md) | Multi-currency converter (SATS↔BSV↔15+ fiat) with exchange rate caching | -| [@bsv/fund-wallet](fund-wallet.md) | CLI faucet for funding wallets from Metanet Desktop during development and testing | +| Package | Purpose | +| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | +| [@bsv/simple](simple.md) | High-level wallet API for browser and server — manage payments, tokens, inscriptions, DIDs, and credentials | +| [@bsv/wallet-helper](wallet-helper.md) | Fluent transaction builder for explicit wallet-backed transactions, BRC-29 derivation, and ordinal support | +| [@bsv/templates](templates.md) | Predefined ScriptTemplate examples for protocol engineers, including OpReturn, MultiPushDrop, and P2MSKH lock/unlock patterns | +| [@bsv/did](did.md) | SD-JWT VC and optional `did:key` helpers for BSV SDK identity keys | +| [@bsv/did-client](did-client.md) | DID client for creating, revoking, and querying on-chain DIDs with overlay broadcast | +| [@bsv/amountinator](amountinator.md) | Multi-currency converter (SATS↔BSV↔15+ fiat) with exchange rate caching | +| [@bsv/fund-wallet](fund-wallet.md) | CLI faucet for funding wallets from Metanet Desktop during development and testing | +| [create-bsv-app](create-bsv-app.md) | CLI and starter catalogue for React, Express, full-stack, and maintained example applications | diff --git a/docs/packages/helpers/simple.md b/docs/packages/helpers/simple.md index 9036e179e..89fdb1677 100644 --- a/docs/packages/helpers/simple.md +++ b/docs/packages/helpers/simple.md @@ -1,16 +1,15 @@ --- id: pkg-simple -title: "@bsv/simple" +title: '@bsv/simple' kind: package domain: helpers -version: "0.4.1" -source_repo: "bsv-blockchain/simple" -source_commit: "unknown" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +version: '0.4.1' +source_repo: 'bsv-blockchain/ts-stack' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 -npm: "https://www.npmjs.com/package/@bsv/simple" -repo: "https://github.com/bsv-blockchain/simple" +npm: 'https://www.npmjs.com/package/@bsv/simple' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/simple' status: stable tags: [helpers, simple, payments] --- @@ -57,6 +56,7 @@ console.log('Paid:', result.txid) ## Common patterns ### Check wallet balance + ```typescript const balance = await wallet.getBalance() console.log(`Balance: ${balance.totalSatoshis} satoshis`) @@ -67,6 +67,7 @@ console.log(`Spendable: ${tokenBalance.spendableSatoshis}`) ``` ### Register for MessageBox and send payment + ```typescript // Register identity handle await wallet.certifyForMessageBox('@alice', '/api/identity-registry') @@ -77,6 +78,7 @@ await wallet.sendMessageBoxPayment(results[0].identityKey, 1000) ``` ### Create and transfer tokens + ```typescript const recipientIdentityKey = '025706528f0f6894b2ba505007267ccff1133e004452a1f6b72ac716f246216366' @@ -98,6 +100,7 @@ await wallet.sendToken({ ``` ### Direct payments (BRC-29 derivation) + ```typescript // Server generates payment request const request = serverWallet.createPaymentRequest({ satoshis: 2000 }) @@ -158,10 +161,10 @@ await serverWallet.receiveDirectPayment({ - [@bsv/wallet-helper](wallet-helper.md) — Fluent transaction builder - [@bsv/templates](templates.md) — Low-level script templates -- [@bsv/sdk](https://github.com/bsv-blockchain/sdk-ts) — Core transaction building +- [@bsv/sdk](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/sdk) — Core transaction building ## Reference - [API reference (TypeDoc)](https://bsv-blockchain.github.io/ts-stack/api/simple/) -- [Source on GitHub](https://github.com/bsv-blockchain/simple) +- [Source on GitHub](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/simple) - [npm](https://www.npmjs.com/package/@bsv/simple) diff --git a/docs/packages/helpers/templates.md b/docs/packages/helpers/templates.md index 1d87e40c4..eb1c7e146 100644 --- a/docs/packages/helpers/templates.md +++ b/docs/packages/helpers/templates.md @@ -1,16 +1,15 @@ --- id: pkg-templates -title: "@bsv/templates" +title: '@bsv/templates' kind: package domain: helpers -version: "1.9.1" -source_repo: "bsv-blockchain/templates" -source_commit: "unknown" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +version: '1.9.1' +source_repo: 'bsv-blockchain/ts-stack' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 -npm: "https://www.npmjs.com/package/@bsv/templates" -repo: "https://github.com/bsv-blockchain/templates" +npm: 'https://www.npmjs.com/package/@bsv/templates' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/ts-templates' status: stable tags: [templates, scripts, locking, unlocking] --- @@ -36,7 +35,7 @@ const lockingScript = opReturn.lock(['APP', JSON.stringify({ action: 'vote' })]) console.log(lockingScript.toHex()) const decodedData = OpReturn.decode(lockingScript) -console.log(decodedData) // ['APP', '{"action":"vote"}'] +console.log(decodedData) // ['APP', '{"action":"vote"}'] ``` ## What it provides @@ -50,6 +49,7 @@ console.log(decodedData) // ['APP', '{"action":"vote"}'] ## Common patterns ### Create and decode an OP_RETURN script + ```typescript import { OpReturn } from '@bsv/templates' @@ -60,6 +60,7 @@ console.log(fields) // ['my-app', 'invoice-paid'] ``` ### Create MultiPushDrop token with 2 trusted owners + ```typescript import { SecurityLevel, Utils, type WalletInterface } from '@bsv/sdk' import { MultiPushDrop } from '@bsv/templates' @@ -87,14 +88,11 @@ console.log(decoded.lockingPublicKeys.length) // 2 // The first owner can build the unlock template for a spending transaction. const { publicKey: creatorIdentityKey } = await creatorWallet.getPublicKey({ identityKey: true }) -const unlocker = new MultiPushDrop(ownerWallet).unlock( - protocolID, - keyID, - creatorIdentityKey -) +const unlocker = new MultiPushDrop(ownerWallet).unlock(protocolID, keyID, creatorIdentityKey) ``` ### Create 2-of-3 multisig + ```typescript import { PublicKey, type WalletInterface } from '@bsv/sdk' import { P2MSKH } from '@bsv/templates' @@ -169,10 +167,10 @@ const unlocker = new P2MSKH().unlock(wallet, customInstructions) - [@bsv/wallet-helper](wallet-helper.md) — Higher-level abstraction over these templates - [@bsv/simple](simple.md) — Wallet-level operations -- [@bsv/sdk](https://github.com/bsv-blockchain/sdk-ts) — Core transaction building and script execution +- [@bsv/sdk](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/sdk) — Core transaction building and script execution ## Reference - [API reference (TypeDoc)](https://bsv-blockchain.github.io/ts-stack/api/templates/) -- [Source on GitHub](https://github.com/bsv-blockchain/templates) +- [Source on GitHub](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/ts-templates) - [npm](https://www.npmjs.com/package/@bsv/templates) diff --git a/docs/packages/helpers/wallet-helper.md b/docs/packages/helpers/wallet-helper.md index 23d5abb58..46faab144 100644 --- a/docs/packages/helpers/wallet-helper.md +++ b/docs/packages/helpers/wallet-helper.md @@ -1,16 +1,15 @@ --- id: pkg-wallet-helper -title: "@bsv/wallet-helper" +title: '@bsv/wallet-helper' kind: package domain: helpers -version: "0.1.1" -source_repo: "bsv-blockchain/wallet-helper" -source_commit: "unknown" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +version: '0.1.1' +source_repo: 'bsv-blockchain/ts-stack' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 -npm: "https://www.npmjs.com/package/@bsv/wallet-helper" -repo: "https://github.com/bsv-blockchain/wallet-helper" +npm: 'https://www.npmjs.com/package/@bsv/wallet-helper' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/bsv-wallet-helper' status: beta tags: [helpers, wallet, transaction-builder] --- @@ -36,14 +35,14 @@ import { TransactionBuilder } from '@bsv/wallet-helper' const recipientAddress = '1EvmsbpAY7nESLkN4ajLTMbvsaQ1HpJPGX' -const result = await new TransactionBuilder(wallet, "Payment with metadata") +const result = await new TransactionBuilder(wallet, 'Payment with metadata') .addP2PKHOutput({ address: recipientAddress, satoshis: 5000, - description: "Payment to Bob" + description: 'Payment to Bob' }) - // Appends data to this output's locking script; it is not a separate output. - .addOpReturn(['APP_ID', JSON.stringify({ memo: 'Thanks!' })]) + // Appends data to this output's locking script; it is not a separate output. + .addOpReturn(['APP_ID', JSON.stringify({ memo: 'Thanks!' })]) .build() console.log(`Sent: ${result.txid}`) @@ -64,11 +63,12 @@ console.log(`Sent: ${result.txid}`) ## Common patterns ### Multi-output payment with wallet-managed change + ```typescript const aliceAddress = '1EvmsbpAY7nESLkN4ajLTMbvsaQ1HpJPGX' const bobAddress = '1BoatSLRHtKNngkdXEeobR76b53LETtpyT' -await new TransactionBuilder(wallet, "Multi-output payment") +await new TransactionBuilder(wallet, 'Multi-output payment') .addP2PKHOutput({ address: aliceAddress, satoshis: 1000 }) .addP2PKHOutput({ address: bobAddress, satoshis: 2000 }) .build() @@ -77,29 +77,32 @@ await new TransactionBuilder(wallet, "Multi-output payment") The wallet still calculates funding and normal change through `createAction` / `signAction`. Use `addChangeOutput` only when you need to specify the change locking script yourself. ### Self-controlled output with BRC-29 automatic derivation + Omitting `address`, `publicKey`, and `walletParams` derives with counterparty `self`. Use this for outputs the same wallet should unlock later, not for sending to another user. ```typescript -await new TransactionBuilder(wallet, "Self-controlled output") - .addP2PKHOutput({ satoshis: 1000, description: "Output for this wallet" }) - .basket("my-basket") - .customInstructions("app-data") +await new TransactionBuilder(wallet, 'Self-controlled output') + .addP2PKHOutput({ satoshis: 1000, description: 'Output for this wallet' }) + .basket('my-basket') + .customInstructions('app-data') .build() ``` ### Spend UTXOs and send to recipient + ```typescript const recipientAddress = '1EvmsbpAY7nESLkN4ajLTMbvsaQ1HpJPGX' -await new TransactionBuilder(wallet, "Spend UTXO") - .addP2PKHInput({ sourceTransaction, sourceOutputIndex: 0, description: "UTXO" }) +await new TransactionBuilder(wallet, 'Spend UTXO') + .addP2PKHInput({ sourceTransaction, sourceOutputIndex: 0, description: 'UTXO' }) .addP2PKHOutput({ address: recipientAddress, satoshis: 500 }) .build() ``` ### Create 1-sat ordinal with inscription and metadata + ```typescript -const ordResult = await new TransactionBuilder(wallet, "Mint ordinal") +const ordResult = await new TransactionBuilder(wallet, 'Mint ordinal') .addOrdinalP2PKHOutput({ walletParams: { protocolID: [2, 'p2pkh'], keyID: '0', counterparty: 'self' }, satoshis: 1, @@ -167,5 +170,5 @@ const ordResult = await new TransactionBuilder(wallet, "Mint ordinal") ## Reference - [API reference (TypeDoc)](https://bsv-blockchain.github.io/ts-stack/api/wallet-helper/) -- [Source on GitHub](https://github.com/bsv-blockchain/wallet-helper) +- [Source on GitHub](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/bsv-wallet-helper) - [npm](https://www.npmjs.com/package/@bsv/wallet-helper) diff --git a/docs/packages/index.md b/docs/packages/index.md index 1a2bb8a10..276d9a407 100644 --- a/docs/packages/index.md +++ b/docs/packages/index.md @@ -2,12 +2,12 @@ id: packages-index title: Packages kind: meta -version: "n/a" -last_updated: "2026-05-01" -last_verified: "2026-05-01" +version: 'n/a' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable -tags: ["packages"] +tags: ['packages'] --- # Packages @@ -21,12 +21,15 @@ ts-stack contains packages organized into 7 domains. Each domain serves a specif **Core cryptographic and transaction primitives.** Every application starts here. - [@bsv/sdk](./sdk/bsv-sdk.md) — Keys, signatures, transactions, BEEF, SPV +- [@bsv/verifast](./sdk/verifast.md) — Optional WASM script verification ### Wallet **Key management, balance tracking, signing — local or via wallet service.** - [@bsv/wallet-toolbox](./wallet/wallet-toolbox.md) — BRC-100 wallet client library +- [@bsv/wallet-toolbox-client](./wallet/wallet-toolbox-client.md) — Browser and IndexedDB distribution +- [@bsv/wallet-toolbox-mobile](./wallet/wallet-toolbox-mobile.md) — React Native and mobile distribution - [@bsv/btms](./wallet/btms.md) — Basic Token Management System for token issuance, transfer, receiving, burning, and ownership proofs - [@bsv/btms-permission-module](./wallet/btms-permission-module.md) — Token permission checking - [@bsv/wallet-relay](./wallet/wallet-relay.md) — Mobile-to-desktop wallet pairing via QR codes + encrypted WebSocket relay @@ -63,6 +66,7 @@ ts-stack contains packages organized into 7 domains. Each domain serves a specif Authenticated Express middleware stack: +- [@bsv/auth](./middleware/auth.md) — Framework-neutral single-use wallet authentication proofs - [@bsv/auth-express-middleware](./middleware/auth-express-middleware.md) — Verify identity signatures in Express - [@bsv/payment-express-middleware](./middleware/payment-express-middleware.md) — Gate authenticated Express routes behind payment requirements; requires `@bsv/auth-express-middleware` @@ -81,6 +85,7 @@ Independent HTTP 402 flow: - [@bsv/wallet-helper](./helpers/wallet-helper.md) — Wallet utility functions - [@bsv/amountinator](./helpers/amountinator.md) — Satoshi/BSV conversion and formatting - [@bsv/fund-wallet](./helpers/fund-wallet.md) — Faucet integration for testnet/devnet +- [create-bsv-app](./helpers/create-bsv-app.md) — CLI and starter catalogue for new applications ## Package Relationships @@ -108,7 +113,11 @@ For monorepo development, see [Install](../get-started/install.md#using-ts-stack ## Package Stability -All packages in ts-stack are production-ready and versioned according to [Semantic Versioning](../about/versioning.md). +Public packages are versioned according to +[Semantic Versioning](../about/versioning.md), but their maturity and runtime +profiles differ. Use each package page and +[Generated Stack Facts](../reference/stack-facts.md) rather than assuming every +workspace project is a production npm package. - **Stable** — API is locked, no breaking changes - **Beta** — API may change, breaking changes possible diff --git a/docs/packages/messaging/authsocket-client.md b/docs/packages/messaging/authsocket-client.md index 2a4a16e33..e7449e128 100644 --- a/docs/packages/messaging/authsocket-client.md +++ b/docs/packages/messaging/authsocket-client.md @@ -1,16 +1,15 @@ --- id: pkg-authsocket-client -title: "@bsv/authsocket-client" +title: '@bsv/authsocket-client' kind: package domain: messaging -version: "2.1.1" -source_repo: "bsv-blockchain/authsocket-client" -source_commit: "unknown" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +version: '2.1.1' +source_repo: 'bsv-blockchain/ts-stack' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 -npm: "https://www.npmjs.com/package/@bsv/authsocket-client" -repo: "https://github.com/bsv-blockchain/authsocket-client" +npm: 'https://www.npmjs.com/package/@bsv/authsocket-client' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/messaging/authsocket-client' status: stable tags: [messaging, websocket, brc-31, auth] --- @@ -31,7 +30,9 @@ npm install @bsv/authsocket-client import { AuthSocketClient } from '@bsv/authsocket-client' import { PrivateKey, ProtoWallet } from '@bsv/sdk' -const clientWallet = new ProtoWallet(PrivateKey.fromHex('0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')) +const clientWallet = new ProtoWallet( + PrivateKey.fromHex('0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef') +) const socket = AuthSocketClient('http://localhost:3000', { wallet: clientWallet }) socket.on('connect', () => { @@ -39,7 +40,7 @@ socket.on('connect', () => { socket.emit('chatMessage', { text: 'Hello from client!' }) }) -socket.on('chatMessage', (msg) => { +socket.on('chatMessage', msg => { console.log('Server says:', msg) }) @@ -66,7 +67,9 @@ socket.on('disconnect', () => { import { AuthSocketClient } from '@bsv/authsocket-client' import { PrivateKey, ProtoWallet } from '@bsv/sdk' -const wallet = new ProtoWallet(PrivateKey.fromHex('0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')) +const wallet = new ProtoWallet( + PrivateKey.fromHex('0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef') +) const socket = AuthSocketClient('http://localhost:3000', { wallet }) socket.on('connect', () => { @@ -74,7 +77,7 @@ socket.on('connect', () => { socket.emit('joinRoom', 'general') }) -socket.on('message', (data) => { +socket.on('message', data => { console.log('Received:', data) }) ``` @@ -140,5 +143,5 @@ const socket = AuthSocketClient('http://localhost:3000', { ## Reference - [API reference (TypeDoc)](https://bsv-blockchain.github.io/ts-stack/api/authsocket-client/) -- [Source on GitHub](https://github.com/bsv-blockchain/authsocket-client) +- [Source on GitHub](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/messaging/authsocket-client) - [npm](https://www.npmjs.com/package/@bsv/authsocket-client) diff --git a/docs/packages/messaging/authsocket.md b/docs/packages/messaging/authsocket.md index 44674023f..e6b9c0204 100644 --- a/docs/packages/messaging/authsocket.md +++ b/docs/packages/messaging/authsocket.md @@ -1,16 +1,15 @@ --- id: pkg-authsocket -title: "@bsv/authsocket" +title: '@bsv/authsocket' kind: package domain: messaging -version: "2.1.1" -source_repo: "bsv-blockchain/authsocket" -source_commit: "unknown" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +version: '2.1.1' +source_repo: 'bsv-blockchain/ts-stack' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 -npm: "https://www.npmjs.com/package/@bsv/authsocket" -repo: "https://github.com/bsv-blockchain/authsocket" +npm: 'https://www.npmjs.com/package/@bsv/authsocket' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/messaging/authsocket' status: stable tags: [messaging, websocket, brc-31, auth] --- @@ -33,13 +32,15 @@ import { PrivateKey, ProtoWallet } from '@bsv/sdk' import http from 'http' const server = http.createServer() -const serverWallet = new ProtoWallet(PrivateKey.fromHex('0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')) +const serverWallet = new ProtoWallet( + PrivateKey.fromHex('0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef') +) const io = new AuthSocketServer(server, { wallet: serverWallet, cors: { origin: '*' } }) -io.on('connection', async (socket) => { +io.on('connection', async socket => { console.log('Authenticated socket:', socket.id) - socket.on('chatMessage', (msg) => { + socket.on('chatMessage', msg => { console.log('Verified message:', msg) }) @@ -79,8 +80,8 @@ const io = new AuthSocketServer(server, { } }) -io.on('connection', async (socket) => { - socket.on('message', (data) => { +io.on('connection', async socket => { + socket.on('message', data => { // All messages already verified }) await socket.emit('response', { authenticated: true }) @@ -90,9 +91,9 @@ io.on('connection', async (socket) => { ### Receiving authenticated messages ```typescript -io.on('connection', async (socket) => { +io.on('connection', async socket => { // Messages are automatically verified before reaching here - socket.on('userAction', (action) => { + socket.on('userAction', action => { console.log('Verified action from', socket.id, ':', action) }) @@ -147,5 +148,5 @@ io.on('connection', async (socket) => { ## Reference - [API reference (TypeDoc)](https://bsv-blockchain.github.io/ts-stack/api/authsocket/) -- [Source on GitHub](https://github.com/bsv-blockchain/authsocket) +- [Source on GitHub](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/messaging/authsocket) - [npm](https://www.npmjs.com/package/@bsv/authsocket) diff --git a/docs/packages/messaging/message-box-client.md b/docs/packages/messaging/message-box-client.md index 5bc863479..d47cc0860 100644 --- a/docs/packages/messaging/message-box-client.md +++ b/docs/packages/messaging/message-box-client.md @@ -1,16 +1,15 @@ --- id: pkg-message-box-client -title: "@bsv/message-box-client" +title: '@bsv/message-box-client' kind: package domain: messaging -version: "2.2.2" -source_repo: "bsv-blockchain/ts-stack" -source_commit: "d4c98d06ca24d5e03722079b9e5b31df32ee9b68" -last_updated: "2026-07-26" -last_verified: "2026-07-26" +version: '2.2.2' +source_repo: 'bsv-blockchain/ts-stack' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 -npm: "https://www.npmjs.com/package/@bsv/message-box-client" -repo: "https://github.com/bsv-blockchain/ts-stack/tree/main/packages/messaging/message-box-client" +npm: 'https://www.npmjs.com/package/@bsv/message-box-client' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/messaging/message-box-client' status: stable tags: [messaging, message-box, brc-103, brc-29] --- diff --git a/docs/packages/messaging/paymail.md b/docs/packages/messaging/paymail.md index 0d02e0987..4415e7b39 100644 --- a/docs/packages/messaging/paymail.md +++ b/docs/packages/messaging/paymail.md @@ -1,16 +1,15 @@ --- id: pkg-paymail -title: "@bsv/paymail" +title: '@bsv/paymail' kind: package domain: messaging -version: "2.4.2" -source_repo: "bsv-blockchain/paymail" -source_commit: "unknown" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +version: '2.4.3' +source_repo: 'bsv-blockchain/ts-stack' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 -npm: "https://www.npmjs.com/package/@bsv/paymail" -repo: "https://github.com/bsv-blockchain/paymail" +npm: 'https://www.npmjs.com/package/@bsv/paymail' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/messaging/ts-paymail' status: stable tags: [paymail, messaging, brc-29, identity] --- @@ -68,7 +67,7 @@ const app = express() const baseUrl = 'https://myDomain.com' const publicProfileRoute = new PublicProfileRoute({ - domainLogicHandler: async (params) => { + domainLogicHandler: async params => { const { name, domain } = PublicProfileRoute.getNameAndDomain(params) const user = await fetchUser(name, domain) return { @@ -80,7 +79,7 @@ const publicProfileRoute = new PublicProfileRoute({ }) const pkiRoute = new PublicKeyInfrastructureRoute({ - domainLogicHandler: async (params) => { + domainLogicHandler: async params => { const { name, domain } = PublicKeyInfrastructureRoute.getNameAndDomain(params) const user = await fetchUser(name, domain) return { @@ -173,5 +172,5 @@ const p2pDest = await client.getP2pPaymentDestination('alice@example.com', 10000 ## Reference - [API reference (TypeDoc)](https://bsv-blockchain.github.io/ts-stack/api/paymail/) -- [Source on GitHub](https://github.com/bsv-blockchain/paymail) +- [Source on GitHub](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/messaging/ts-paymail) - [npm](https://www.npmjs.com/package/@bsv/paymail) diff --git a/docs/packages/middleware/402-pay.md b/docs/packages/middleware/402-pay.md index cda2d2816..825645eab 100644 --- a/docs/packages/middleware/402-pay.md +++ b/docs/packages/middleware/402-pay.md @@ -1,18 +1,17 @@ --- id: pkg-402-pay -title: "@bsv/402-pay" +title: '@bsv/402-pay' kind: package domain: middleware -version: "0.2.1" -source_repo: "bsv-blockchain/402-pay" -source_commit: "unknown" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +version: '0.2.1' +source_repo: 'bsv-blockchain/ts-stack' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 -npm: "https://www.npmjs.com/package/@bsv/402-pay" -repo: "https://github.com/bsv-blockchain/402-pay" +npm: 'https://www.npmjs.com/package/@bsv/402-pay' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/middleware/402-pay' status: beta -tags: [middleware, payment, "402", client] +tags: [middleware, payment, '402', client] --- # @bsv/402-pay @@ -34,13 +33,16 @@ import { createPaymentMiddleware } from '@bsv/402-pay/server' const app = express() -app.use('/articles/:slug', createPaymentMiddleware({ - wallet, - calculatePrice: (path) => { - if (path.includes('/premium/')) return 1000 - return undefined - } -})) +app.use( + '/articles/:slug', + createPaymentMiddleware({ + wallet, + calculatePrice: path => { + if (path.includes('/premium/')) return 1000 + return undefined + } + }) +) app.get('/articles/:slug', (req, res) => { if (req.payment) { @@ -66,16 +68,19 @@ console.log(article) ## What it provides ### Server + - **createPaymentMiddleware** — Express middleware for automatic 402 handling - **validatePayment** — Validate incoming payment headers - **send402** — Send 402 response with payment request headers ### Client + - **create402Fetch** — Fetch wrapper that auto-handles 402 responses - **constructPaymentHeaders** — Build payment headers manually - **clearCache** — Clear cached paid content ### Types & Constants + - **PaymentMiddlewareOptions** — Middleware configuration - **PaymentResult** — Parsed payment with `satoshisPaid`, `senderIdentityKey`, and `txid` - **PaymentHeaders** — Five required headers (BEEF, SENDER, NONCE, TIME, VOUT) @@ -115,7 +120,7 @@ import { constructPaymentHeaders } from '@bsv/402-pay/client' const headers = await constructPaymentHeaders( wallet, 'https://example.com/articles/foo', - 100, // 100 sats + 100, // 100 sats serverPublicKey ) @@ -127,7 +132,7 @@ const res = await fetch('https://example.com/articles/foo', { headers }) ```typescript const fetch402 = create402Fetch({ wallet, - cacheTimeoutMs: 30 * 60 * 1000 // Cache for 30 minutes + cacheTimeoutMs: 30 * 60 * 1000 // Cache for 30 minutes }) // Make requests — auto-pays 402s with caching @@ -193,5 +198,5 @@ fetch402.clearCache() ## Reference - [API reference (TypeDoc)](https://bsv-blockchain.github.io/ts-stack/api/402-pay/) -- [Source on GitHub](https://github.com/bsv-blockchain/402-pay) +- [Source on GitHub](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/middleware/402-pay) - [npm](https://www.npmjs.com/package/@bsv/402-pay) diff --git a/docs/packages/middleware/auth-express-middleware.md b/docs/packages/middleware/auth-express-middleware.md index 70358c79d..5050e7fe4 100644 --- a/docs/packages/middleware/auth-express-middleware.md +++ b/docs/packages/middleware/auth-express-middleware.md @@ -3,11 +3,10 @@ id: pkg-auth-express-middleware title: '@bsv/auth-express-middleware' kind: package domain: middleware -version: '2.1.2' +version: '2.1.3' source_repo: 'bsv-blockchain/ts-stack' -source_commit: 'unreleased' -last_updated: '2026-07-26' -last_verified: '2026-07-26' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 npm: 'https://www.npmjs.com/package/@bsv/auth-express-middleware' repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/middleware/auth-express-middleware' diff --git a/docs/packages/middleware/auth.md b/docs/packages/middleware/auth.md new file mode 100644 index 000000000..4e6c313db --- /dev/null +++ b/docs/packages/middleware/auth.md @@ -0,0 +1,60 @@ +--- +id: pkg-auth +title: '@bsv/auth' +kind: package +domain: middleware +version: '0.1.1' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 +npm: 'https://www.npmjs.com/package/@bsv/auth' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/middleware/auth' +status: beta +tags: [middleware, authentication, wallet, replay] +--- + +# @bsv/auth + +`@bsv/auth` provides framework-neutral, expiry-bound, single-use wallet +authentication proofs. It separates proof creation and verification from HTTP, +Express, and database choices. + +## Install + +Install the SDK peer dependency with the package: + +```bash +npm install @bsv/auth @bsv/sdk +``` + +## Public API + +- `AuthProofClient` and `createAuthProof` create an action-bound proof with a + wallet. +- `AuthProofServer` and `verifyAuthProof` verify the signature, identity, + action, expiry, and nonce. +- `checkAuthSigData`, `createAuthSigData`, and `serializeAuthSigData` expose + the lower-level proof data contract. + +```ts +import { AuthProofClient, AuthProofServer } from '@bsv/auth' + +const options = { protocol: [2, 'example auth'] as [2, string] } +const client = new AuthProofClient(options) +const server = new AuthProofServer(options) +``` + +Client and server must use the same protocol. Production verification must +inject an atomic `consumeNonce` implementation. A process-local map is suitable +only for one process; replicated or restarting services need a shared store +with uniqueness and expiry. + +The package publishes strict ESM and CommonJS entry points and supports Node.js +22 or newer. See the +[package README](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/middleware/auth#readme) +for a complete client/server example and store guidance. + +## License + +Open BSV License Version 6. See the +[package license](https://github.com/bsv-blockchain/ts-stack/blob/main/packages/middleware/auth/LICENSE.txt). diff --git a/docs/packages/middleware/index.md b/docs/packages/middleware/index.md index 830491dee..afc9b1d77 100644 --- a/docs/packages/middleware/index.md +++ b/docs/packages/middleware/index.md @@ -2,9 +2,9 @@ id: domain-middleware title: Middleware kind: reference -last_updated: "2026-04-30" -version: "n/a" -last_verified: "2026-04-28" +last_updated: '2026-07-27' +version: 'n/a' +last_verified: '2026-07-27' review_cadence_days: 90 status: stable tags: [packages, middleware] @@ -16,8 +16,9 @@ Express.js middleware and client utilities for adding cryptographic authenticati ## Packages -| Package | Purpose | -|---------|---------| -| **@bsv/auth-express-middleware** | Express middleware implementing BRC-103 peer-to-peer mutual authentication via BRC-104 HTTP transport. Verify request signatures, attach verified identity to req.auth, and optionally exchange verifiable certificates. | -| **@bsv/payment-express-middleware** | Express middleware for HTTP 402 Payment Required micropayment gating. Requires `@bsv/auth-express-middleware` first, then derives payment requirements from the authenticated identity context. | -| **@bsv/402-pay** | Independent client-side and server-side HTTP 402 payment handler. Auto-pay 402 responses on the client; validate and accept payments on the server with caching and replay protection, without requiring auth middleware. | +| Package | Purpose | +| ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | +| [@bsv/auth](auth.md) | Framework-neutral signed, expiry-bound, single-use wallet proofs with an injected replay store. | +| [@bsv/auth-express-middleware](auth-express-middleware.md) | Express middleware implementing BRC-103 peer-to-peer mutual authentication via BRC-104 HTTP transport. | +| [@bsv/payment-express-middleware](payment-express-middleware.md) | Authenticated legacy `x-bsv-payment` middleware with replay-safe payment acceptance. | +| [@bsv/402-pay](402-pay.md) | Independent BRC-121 client and server HTTP 402 flow that does not require auth middleware. | diff --git a/docs/packages/middleware/payment-express-middleware.md b/docs/packages/middleware/payment-express-middleware.md index d7d62aa4c..8d7b05510 100644 --- a/docs/packages/middleware/payment-express-middleware.md +++ b/docs/packages/middleware/payment-express-middleware.md @@ -3,11 +3,10 @@ id: pkg-payment-express-middleware title: '@bsv/payment-express-middleware' kind: package domain: middleware -version: '2.1.1' +version: '2.1.2' source_repo: 'bsv-blockchain/ts-stack' -source_commit: 'unreleased' -last_updated: '2026-07-26' -last_verified: '2026-07-26' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 npm: 'https://www.npmjs.com/package/@bsv/payment-express-middleware' repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/middleware/payment-express-middleware' diff --git a/docs/packages/network/index.md b/docs/packages/network/index.md index 9a887c971..6ac80fdf9 100644 --- a/docs/packages/network/index.md +++ b/docs/packages/network/index.md @@ -3,12 +3,12 @@ id: network-domain title: Network kind: meta domain: network -version: "n/a" -last_updated: "2026-04-28" -last_verified: "2026-04-28" +version: 'n/a' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable -tags: ["domain", "network"] +tags: ['domain', 'network'] --- # Network @@ -17,8 +17,8 @@ Connect to Teranode via private DHT and subscribe to real-time blockchain events ## Packages in this Domain -| Package | Purpose | -|---------|---------| +| Package | Purpose | +| ------------------------------------------------ | ---------------------------------------------------------------------------------------- | | [@bsv/teranode-listener](./teranode-listener.md) | Subscribe to Teranode P2P topics via libp2p private DHT with gossipsub pub/sub messaging | ## What You Can Do @@ -65,18 +65,18 @@ Use network packages when you need to: ## Topics Available -| Topic | Event | -|-------|-------| -| `bitcoin/mainnet-bestblock` | Best block message | -| `bitcoin/mainnet-block` | Block solution found | -| `bitcoin/mainnet-subtree` | Subtree created | -| `bitcoin/mainnet-mining_on` | Mining enabled | -| `bitcoin/mainnet-handshake` | Peer connects | +| Topic | Event | +| ----------------------------- | -------------------- | +| `bitcoin/mainnet-bestblock` | Best block message | +| `bitcoin/mainnet-block` | Block solution found | +| `bitcoin/mainnet-subtree` | Subtree created | +| `bitcoin/mainnet-mining_on` | Mining enabled | +| `bitcoin/mainnet-handshake` | Peer connects | | `bitcoin/mainnet-rejected_tx` | Transaction rejected | -| `bitcoin/testnet-*` | Testnet equivalents | +| `bitcoin/testnet-*` | Testnet equivalents | ## Next Steps - **[@bsv/teranode-listener](./teranode-listener.md)** — Real-time blockchain event subscription - **[@bsv/overlay](../overlays/overlay.md)** — Indexing service integration -- **[@bsv/sdk](https://github.com/bsv-blockchain/ts-sdk)** — Transaction/block deserialization +- **[@bsv/sdk](../sdk/bsv-sdk.md)** — Transaction/block deserialization diff --git a/docs/packages/network/teranode-listener.md b/docs/packages/network/teranode-listener.md index 2e56bfd15..b94c9d312 100644 --- a/docs/packages/network/teranode-listener.md +++ b/docs/packages/network/teranode-listener.md @@ -1,14 +1,16 @@ --- id: teranode-listener -title: "@bsv/teranode-listener" +title: '@bsv/teranode-listener' kind: package domain: network -npm: "@bsv/teranode-listener" -version: "1.1.1" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +npm: '@bsv/teranode-listener' +version: '1.1.1' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/network/ts-p2p' status: stable -tags: ["network", "broadcast", "teranode", "p2p", "libp2p"] +tags: ['network', 'broadcast', 'teranode', 'p2p', 'libp2p'] --- # @bsv/teranode-listener @@ -177,12 +179,12 @@ await listener.stop() ## Related packages - [@bsv/overlay](../overlays/overlay.md) — Can use TeranodeListener for transaction submission -- [@bsv/sdk](https://github.com/bsv-blockchain/ts-sdk) — Transaction and block deserialization +- [@bsv/sdk](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/sdk) — Transaction and block deserialization - [@bsv/overlay-express](../overlays/overlay-express.md) — Overlay services can integrate with network ## Reference - [API reference (TypeDoc)](https://bsv-blockchain.github.io/ts-stack/api/ts-p2p/) -- [Source on GitHub](https://github.com/bsv-blockchain/ts-p2p) +- [Source on GitHub](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/network/ts-p2p) - [npm](https://www.npmjs.com/package/@bsv/teranode-listener) - [libp2p documentation](https://docs.libp2p.io/) diff --git a/docs/packages/overlays/btms-backend.md b/docs/packages/overlays/btms-backend.md index 04e09d005..774d3475a 100644 --- a/docs/packages/overlays/btms-backend.md +++ b/docs/packages/overlays/btms-backend.md @@ -1,16 +1,14 @@ --- id: pkg-btms-backend -title: "@bsv/btms-backend" +title: '@bsv/btms-backend' kind: package domain: overlays -version: "0.1.0" -source_repo: "bsv-blockchain/btms-backend" -source_commit: "unknown" -last_updated: "2026-04-28" -last_verified: "2026-04-28" +version: '0.1.1' +source_repo: 'bsv-blockchain/ts-stack' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 -npm: "https://www.npmjs.com/package/@bsv/btms-backend" -repo: "https://github.com/bsv-blockchain/btms-backend" +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/btms-backend' status: experimental tags: [tokens, btms, backend, mongodb] --- @@ -74,9 +72,7 @@ import { BTMSTopicManager, BTMSLookupServiceFactory } from '@bsv/btms-backend' const server = new OverlayExpress('mynode', privateKey, 'example.com') server.configureTopicManager('tm_btms', new BTMSTopicManager()) -await server.configureLookupServiceWithMongo('ls_btms', db => - BTMSLookupServiceFactory(db) -) +await server.configureLookupServiceWithMongo('ls_btms', db => BTMSLookupServiceFactory(db)) await server.configureEngine() await server.start() @@ -150,5 +146,5 @@ const metadata = await manager.getMetaData() ## Reference - [API reference (TypeDoc)](https://bsv-blockchain.github.io/ts-stack/api/btms-backend/) -- [Source on GitHub](https://github.com/bsv-blockchain/btms-backend) +- [Source on GitHub](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/btms-backend) - [npm](https://www.npmjs.com/package/@bsv/btms-backend) diff --git a/docs/packages/overlays/gasp.md b/docs/packages/overlays/gasp.md index a03947828..4cd5867b5 100644 --- a/docs/packages/overlays/gasp.md +++ b/docs/packages/overlays/gasp.md @@ -1,16 +1,15 @@ --- id: pkg-gasp -title: "@bsv/gasp" +title: '@bsv/gasp' kind: package domain: overlays -version: "1.3.1" -source_repo: "bsv-blockchain/gasp" -source_commit: "unknown" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +version: '1.3.1' +source_repo: 'bsv-blockchain/ts-stack' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 -npm: "https://www.npmjs.com/package/@bsv/gasp" -repo: "https://github.com/bsv-blockchain/gasp" +npm: 'https://www.npmjs.com/package/@bsv/gasp' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/gasp-core' status: stable tags: [overlay, sync, gasp, graph] --- @@ -86,16 +85,7 @@ class MyStorage implements GASPStorage { declare const remote: GASPRemote // Initialize and sync -const gasp = new GASP( - new MyStorage(), - remote, - 0, - '[GASP] ', - false, - false, - LogLevel.INFO, - false -) +const gasp = new GASP(new MyStorage(), remote, 0, '[GASP] ', false, false, LogLevel.INFO, false) await gasp.sync('https://peer.example.com') ``` @@ -172,7 +162,7 @@ const gaspPullOnly = new GASP( 0, '[GASP-Pull] ', false, - true, // unidirectional = true + true, // unidirectional = true LogLevel.DEBUG, false ) @@ -192,7 +182,7 @@ const gaspSequential = new GASP( false, false, LogLevel.WARN, - true // sequential = true + true // sequential = true ) await gaspSequential.sync('https://peer.example.com') @@ -248,10 +238,10 @@ await gaspSequential.sync('https://peer.example.com') - [@bsv/overlay](./overlay.md) — Uses OverlayGASPStorage and OverlayGASPRemote adapters for GASP integration - [@bsv/overlay-express](./overlay-express.md) — Configure GASP sync via `configureEnableGASPSync()` - [@bsv/overlay-discovery-services](./overlay-discovery-services.md) — Can discover remote GASP peers via SHIP/SLAP -- [@bsv/sdk](https://github.com/bsv-blockchain/ts-sdk) — Transaction encoding/decoding +- [@bsv/sdk](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/sdk) — Transaction encoding/decoding ## Reference - [API reference (TypeDoc)](https://bsv-blockchain.github.io/ts-stack/api/gasp/) -- [Source on GitHub](https://github.com/bsv-blockchain/gasp) +- [Source on GitHub](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/gasp-core) - [npm](https://www.npmjs.com/package/@bsv/gasp) diff --git a/docs/packages/overlays/index.md b/docs/packages/overlays/index.md index d751282cf..6c6036c24 100644 --- a/docs/packages/overlays/index.md +++ b/docs/packages/overlays/index.md @@ -3,12 +3,12 @@ id: overlays-domain title: Overlays kind: meta domain: overlays -version: "n/a" -last_updated: "2026-04-28" -last_verified: "2026-04-28" +version: 'n/a' +last_updated: '2026-04-28' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable -tags: ["domain", "overlays"] +tags: ['domain', 'overlays'] --- # Overlays @@ -17,14 +17,14 @@ Build and operate overlay services that index, validate, and serve on-chain data ## Packages in this Domain -| Package | Purpose | -|---------|---------| -| [@bsv/overlay](./overlay.md) | Core Engine orchestrating topic managers, lookup services, and storage with BEEF/STEAK encoding | -| [@bsv/overlay-express](./overlay-express.md) | Opinionated Express.js HTTP server with configuration, health checks, and admin endpoints | -| [@bsv/overlay-topics](./overlay-topics.md) | 20+ pre-built topic managers and lookup services (BTMS, DID, KVStore, UHRP, UMP, Supply Chain, etc.) | -| [@bsv/overlay-discovery-services](./overlay-discovery-services.md) | SHIP/SLAP peer discovery and WalletAdvertiser for certificate-based advertisements | -| [@bsv/gasp](./gasp.md) | Graph Aware Sync Protocol for incremental transaction graph synchronization with SPV validation | -| [@bsv/btms-backend](./btms-backend.md) | BTMS token validation and indexing (legacy; core moved to @bsv/overlay-topics) | +| Package | Purpose | +| ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | +| [@bsv/overlay](./overlay.md) | Core Engine orchestrating topic managers, lookup services, and storage with BEEF/STEAK encoding | +| [@bsv/overlay-express](./overlay-express.md) | Opinionated Express.js HTTP server with configuration, health checks, and admin endpoints | +| [@bsv/overlay-topics](./overlay-topics.md) | 20+ pre-built topic managers and lookup services (BTMS, DID, KVStore, UHRP, UMP, Supply Chain, etc.) | +| [@bsv/overlay-discovery-services](./overlay-discovery-services.md) | SHIP/SLAP peer discovery and WalletAdvertiser for certificate-based advertisements | +| [@bsv/gasp](./gasp.md) | Graph Aware Sync Protocol for incremental transaction graph synchronization with SPV validation | +| [@bsv/btms-backend](./btms-backend.md) | BTMS token validation and indexing (legacy; core moved to @bsv/overlay-topics) | ## What You Can Do diff --git a/docs/packages/overlays/overlay-discovery-services.md b/docs/packages/overlays/overlay-discovery-services.md index f1da329f2..f15228bb9 100644 --- a/docs/packages/overlays/overlay-discovery-services.md +++ b/docs/packages/overlays/overlay-discovery-services.md @@ -1,14 +1,16 @@ --- id: overlay-discovery -title: "@bsv/overlay-discovery-services" +title: '@bsv/overlay-discovery-services' kind: package domain: overlays -npm: "@bsv/overlay-discovery-services" -version: "2.1.1" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +npm: '@bsv/overlay-discovery-services' +version: '2.1.1' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/overlay-discovery-services' status: stable -tags: ["overlay", "discovery"] +tags: ['overlay', 'discovery'] --- # @bsv/overlay-discovery-services @@ -62,8 +64,8 @@ const engine = new Engine( storage, new WhatsOnChain('main'), 'https://mynode.example.com', - ['https://ship.example.com'], // SHIP trackers - ['https://slap.example.com'] // SLAP trackers + ['https://ship.example.com'], // SHIP trackers + ['https://slap.example.com'] // SLAP trackers ) // Query SHIP for topic hosts @@ -198,5 +200,5 @@ const serviceDiscovery = await engine.lookup({ ## Reference - [API reference (TypeDoc)](https://bsv-blockchain.github.io/ts-stack/api/overlay-discovery-services/) -- [Source on GitHub](https://github.com/bsv-blockchain/overlay-discovery-services) +- [Source on GitHub](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/overlay-discovery-services) - [npm](https://www.npmjs.com/package/@bsv/overlay-discovery-services) diff --git a/docs/packages/overlays/overlay-express.md b/docs/packages/overlays/overlay-express.md index 54e4887ca..2d25a515b 100644 --- a/docs/packages/overlays/overlay-express.md +++ b/docs/packages/overlays/overlay-express.md @@ -1,14 +1,16 @@ --- id: overlay-express -title: "@bsv/overlay-express" +title: '@bsv/overlay-express' kind: package domain: overlays -npm: "@bsv/overlay-express" -version: "2.4.2" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +npm: '@bsv/overlay-express' +version: '2.4.3' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/overlay-express' status: stable -tags: ["overlay", "express", "http"] +tags: ['overlay', 'express', 'http'] --- # @bsv/overlay-express @@ -26,11 +28,7 @@ npm install @bsv/overlay-express ```typescript import OverlayExpress from '@bsv/overlay-express' -const server = new OverlayExpress( - 'testnode', - process.env.SERVER_PRIVATE_KEY!, - 'example.com' -) +const server = new OverlayExpress('testnode', process.env.SERVER_PRIVATE_KEY!, 'example.com') server.configurePort(8080) await server.configureKnex(process.env.KNEX_URL!) @@ -63,11 +61,7 @@ await server.start() ### Basic server setup ```typescript -const server = new OverlayExpress( - 'mynode', - privateKey, - 'mynode.example.com' -) +const server = new OverlayExpress('mynode', privateKey, 'mynode.example.com') server.configurePort(3000) await server.configureKnex('postgresql://user:pass@localhost/db') @@ -80,7 +74,9 @@ server.configureTopicManager('tm_helloworld', new HelloWorldTopicManager()) server.configureTopicManager('tm_kvstore', new KVStoreTopicManager()) server.configureTopicManager('tm_did', new DIDTopicManager()) -await server.configureLookupServiceWithMongo('ls_helloworld', db => createHelloWorldLookupService(db)) +await server.configureLookupServiceWithMongo('ls_helloworld', db => + createHelloWorldLookupService(db) +) await server.configureLookupServiceWithMongo('ls_kvstore', db => createKVStoreLookupService(db)) await server.configureLookupServiceWithMongo('ls_did', db => createDIDLookupService(db)) @@ -146,22 +142,26 @@ import { OverlayMonitor } from '@bsv/overlay-express' const monitor = new OverlayMonitor({ intervalMs: 60 * 60 * 1000, - targets: [{ - name: 'production-overlay', - baseUrl: 'https://overlay.example', - adminToken: process.env.ADMIN_TOKEN, - probes: [{ - name: 'protomap', - service: 'ls_protomap', - query: { topic: 'tm_protomap' }, - maxOutputs: 50 - }], - maintenance: { - startBASMSync: true, - maintainUnproven: { thresholdBlocks: 144 }, - janitor: true + targets: [ + { + name: 'production-overlay', + baseUrl: 'https://overlay.example', + adminToken: process.env.ADMIN_TOKEN, + probes: [ + { + name: 'protomap', + service: 'ls_protomap', + query: { topic: 'tm_protomap' }, + maxOutputs: 50 + } + ], + maintenance: { + startBASMSync: true, + maintainUnproven: { thresholdBlocks: 144 }, + janitor: true + } } - }] + ] }) monitor.start() @@ -225,5 +225,5 @@ monitor.start() ## Reference - [API reference (TypeDoc)](https://bsv-blockchain.github.io/ts-stack/api/overlay-express/) -- [Source on GitHub](https://github.com/bsv-blockchain/overlay-express) +- [Source on GitHub](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/overlay-express) - [npm](https://www.npmjs.com/package/@bsv/overlay-express) diff --git a/docs/packages/overlays/overlay-topics.md b/docs/packages/overlays/overlay-topics.md index d99bb6dc1..99184112b 100644 --- a/docs/packages/overlays/overlay-topics.md +++ b/docs/packages/overlays/overlay-topics.md @@ -1,14 +1,16 @@ --- id: overlay-topics -title: "@bsv/overlay-topics" +title: '@bsv/overlay-topics' kind: package domain: overlays -npm: "@bsv/overlay-topics" -version: "1.6.1" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +npm: '@bsv/overlay-topics' +version: '1.6.1' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/topics' status: stable -tags: ["overlay", "topics", "uhrp"] +tags: ['overlay', 'topics', 'uhrp'] --- # @bsv/overlay-topics @@ -55,10 +57,14 @@ const results = await btmsService.lookup({ ```typescript import OverlayExpress from '@bsv/overlay-express' import { - HelloWorldTopicManager, createHelloWorldLookupService, - DIDTopicManager, createDIDLookupService, - KVStoreTopicManager, createKVStoreLookupService, - BTMSTopicManager, createBTMSLookupService + HelloWorldTopicManager, + createHelloWorldLookupService, + DIDTopicManager, + createDIDLookupService, + KVStoreTopicManager, + createKVStoreLookupService, + BTMSTopicManager, + createBTMSLookupService } from '@bsv/overlay-topics' const server = new OverlayExpress('mynode', privateKey, 'example.com') @@ -68,7 +74,9 @@ server.configureTopicManager('tm_did', new DIDTopicManager()) server.configureTopicManager('tm_kvstore', new KVStoreTopicManager()) server.configureTopicManager('tm_btms', new BTMSTopicManager()) -await server.configureLookupServiceWithMongo('ls_helloworld', db => createHelloWorldLookupService(db)) +await server.configureLookupServiceWithMongo('ls_helloworld', db => + createHelloWorldLookupService(db) +) await server.configureLookupServiceWithMongo('ls_did', db => createDIDLookupService(db)) await server.configureLookupServiceWithMongo('ls_kvstore', db => createKVStoreLookupService(db)) await server.configureLookupServiceWithMongo('ls_btms', db => createBTMSLookupService(db)) @@ -186,5 +194,5 @@ const admittance = await manager.identifyAdmissibleOutputs(beef, []) ## Reference - [API reference (TypeDoc)](https://bsv-blockchain.github.io/ts-stack/api/overlay-topics/) -- [Source on GitHub](https://github.com/bsv-blockchain/overlay-topics) +- [Source on GitHub](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/topics) - [npm](https://www.npmjs.com/package/@bsv/overlay-topics) diff --git a/docs/packages/overlays/overlay.md b/docs/packages/overlays/overlay.md index 5b3ae1758..90cd116a1 100644 --- a/docs/packages/overlays/overlay.md +++ b/docs/packages/overlays/overlay.md @@ -1,14 +1,16 @@ --- id: overlay -title: "@bsv/overlay" +title: '@bsv/overlay' kind: package domain: overlays -npm: "@bsv/overlay" -version: "2.2.1" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +npm: '@bsv/overlay' +version: '2.2.1' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/overlay' status: stable -tags: ["overlay", "framework"] +tags: ['overlay', 'framework'] --- # @bsv/overlay @@ -33,7 +35,7 @@ import type { Db } from 'mongodb' declare const knex: Knex declare const mongoDb: Db -declare const req: { headers: { 'x-topics'?: string }, body: number[] } +declare const req: { headers: { 'x-topics'?: string }; body: number[] } declare const res: { status: (code: number) => { json: (body: unknown) => void } } const lookupService = await createHelloWorldLookupService(mongoDb) @@ -53,7 +55,7 @@ const topics = topicsHeader.trim().startsWith('[') ? JSON.parse(topicsHeader) : topicsHeader.split(',').map(topic => topic.trim()) const taggedBEEF = { beef: Array.from(req.body), topics } -await engine.submit(taggedBEEF, (steak) => res.status(200).json(steak)) +await engine.submit(taggedBEEF, steak => res.status(200).json(steak)) // Perform lookups const result = await engine.lookup({ @@ -87,16 +89,16 @@ class CustomTopicManager implements TopicManager { const tx = Transaction.fromBEEF(beef) return { outputsToAdmit: [0], coinsToRetain: [] } } - - async getDocumentation() { - return 'Custom topic documentation' + + async getDocumentation() { + return 'Custom topic documentation' } - - async getMetaData() { - return { - name: 'custom', - shortDescription: 'A custom topic' - } + + async getMetaData() { + return { + name: 'custom', + shortDescription: 'A custom topic' + } } } ``` @@ -109,13 +111,13 @@ import type { LookupService } from '@bsv/overlay' class CustomLookupService implements LookupService { readonly admissionMode = 'locking-script' as const readonly spendNotificationMode = 'none' as const - + async outputAdmittedByTopic(payload) { if (payload.mode === 'locking-script') { // Index the output } } - + async lookup(question) { // Return a LookupFormula: outpoints that the Engine should hydrate. return [] @@ -225,5 +227,5 @@ invalid transactions stop appearing in lookup results immediately. ## Reference - [API reference (TypeDoc)](https://bsv-blockchain.github.io/ts-stack/api/overlay/) -- [Source on GitHub](https://github.com/bsv-blockchain/overlay) +- [Source on GitHub](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/overlay) - [npm](https://www.npmjs.com/package/@bsv/overlay) diff --git a/docs/packages/sdk/bsv-sdk.md b/docs/packages/sdk/bsv-sdk.md index 6a92f90c3..3eb3e7612 100644 --- a/docs/packages/sdk/bsv-sdk.md +++ b/docs/packages/sdk/bsv-sdk.md @@ -1,16 +1,16 @@ --- id: bsv-sdk -title: "@bsv/sdk" +title: '@bsv/sdk' kind: package domain: sdk -version: "2.2.0" -npm: "@bsv/sdk" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +version: '2.2.1' +npm: '@bsv/sdk' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable -tags: ["sdk", "crypto", "transactions"] -github_repo: "https://github.com/bsv-blockchain/ts-stack" +tags: ['sdk', 'crypto', 'transactions'] +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/sdk' --- # @bsv/sdk @@ -31,25 +31,29 @@ npm install @bsv/sdk import { PrivateKey, P2PKH, Transaction } from '@bsv/sdk' const privKey = PrivateKey.fromWif('L5EY1SbTvvPNSdCYQe1EJHfXCBBT4PmnF6CDbzCm9iifZptUvDGB') -const sourceTransaction = Transaction.fromHex('0200000001...') // Previous tx hex +const sourceTransaction = Transaction.fromHex('0200000001...') // Previous tx hex const recipientAddress = '1EvmsbpAY7nESLkN4ajLTMbvsaQ1HpJPGX' -const tx = new Transaction(1, [ - { - sourceTransaction, - sourceOutputIndex: 0, - unlockingScriptTemplate: new P2PKH().unlock(privKey) - } -], [ - { - lockingScript: new P2PKH().lock(recipientAddress), - satoshis: 5000 - }, - { - lockingScript: new P2PKH().lock(privKey.toAddress()), - change: true - } -]) +const tx = new Transaction( + 1, + [ + { + sourceTransaction, + sourceOutputIndex: 0, + unlockingScriptTemplate: new P2PKH().unlock(privKey) + } + ], + [ + { + lockingScript: new P2PKH().lock(recipientAddress), + satoshis: 5000 + }, + { + lockingScript: new P2PKH().lock(privKey.toAddress()), + change: true + } + ] +) await tx.fee() await tx.sign() @@ -84,22 +88,26 @@ const privKey = PrivateKey.fromWif('L5EY1SbTvvPNSdCYQe1EJHfXCBBT4PmnF6CDbzCm9iif const sourceTransaction = Transaction.fromHex('0200000001...') const recipientAddress = '1EvmsbpAY7nESLkN4ajLTMbvsaQ1HpJPGX' -const tx = new Transaction(1, [ - { - sourceTransaction, - sourceOutputIndex: 0, - unlockingScriptTemplate: new P2PKH().unlock(privKey) - } -], [ - { - lockingScript: new P2PKH().lock(recipientAddress), - satoshis: 5000, - }, - { - lockingScript: new P2PKH().lock(privKey.toAddress()), - change: true - } -]) +const tx = new Transaction( + 1, + [ + { + sourceTransaction, + sourceOutputIndex: 0, + unlockingScriptTemplate: new P2PKH().unlock(privKey) + } + ], + [ + { + lockingScript: new P2PKH().lock(recipientAddress), + satoshis: 5000 + }, + { + lockingScript: new P2PKH().lock(privKey.toAddress()), + change: true + } + ] +) await tx.fee() await tx.sign() @@ -112,9 +120,7 @@ import { P2PKH, WalletClient } from '@bsv/sdk' const wallet = new WalletClient('auto', 'example.com') const recipientAddress = '1EvmsbpAY7nESLkN4ajLTMbvsaQ1HpJPGX' -const lockingScript = new P2PKH() - .lock(recipientAddress) - .toHex() +const lockingScript = new P2PKH().lock(recipientAddress).toHex() const { publicKey } = await wallet.getPublicKey({ identityKey: true @@ -122,11 +128,13 @@ const { publicKey } = await wallet.getPublicKey({ const action = await wallet.createAction({ description: 'Create payment', - outputs: [{ - lockingScript, - satoshis: 1000, - outputDescription: 'Payment output' - }] + outputs: [ + { + lockingScript, + satoshis: 1000, + outputDescription: 'Payment output' + } + ] }) console.log(publicKey, action.txid) diff --git a/docs/packages/sdk/index.md b/docs/packages/sdk/index.md index 8ae252b13..dd288d757 100644 --- a/docs/packages/sdk/index.md +++ b/docs/packages/sdk/index.md @@ -3,41 +3,50 @@ id: sdk-domain title: SDK kind: meta domain: sdk -version: "n/a" -last_updated: "2026-04-28" -last_verified: "2026-04-28" +version: 'n/a' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable -tags: ["domain", "sdk"] +tags: ['domain', 'sdk'] --- # SDK Domain The foundation of ts-stack. Contains core cryptographic primitives, Bitcoin Script execution, transaction building and signing, network broadcasting, and lightweight SPV verification. This is the base layer that all other ts-stack packages build on top of. -The SDK is intentionally standalone with zero runtime dependencies — it works in both Node.js and modern browsers using native crypto APIs. It provides both low-level primitives (for fine-grained control) and high-level helpers (for common workflows). +The core SDK is intentionally standalone with zero runtime dependencies — it +works in both Node.js and modern browsers. The optional VeriFast package adds a +validated WebAssembly verification backend without changing the SDK's default +interpreter. ## Packages in this Domain -| Package | Purpose | -|---------|---------| -| [@bsv/sdk](./bsv-sdk.md) | Cryptographic primitives, script building, transactions, BEEF, SPV, wallet interface types, broadcasting, and overlay tools | +| Package | Purpose | +| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------- | +| [@bsv/sdk](./bsv-sdk.md) | Cryptographic primitives, script building, transactions, BEEF, SPV, wallet interface types, broadcasting, and overlay tools | +| [@bsv/verifast](./verifast.md) | Optional BSV BDK WebAssembly script-verification backend for Node, browser, workers, and classic scripts | ## Common Use Cases ### I'm building an application that needs to handle Bitcoin transactions + Start with [@bsv/sdk](./bsv-sdk.md) for transaction building, signing, and broadcasting. If you need persistent state and balance tracking, layer [@bsv/wallet-toolbox](../wallet/wallet-toolbox.md) on top. ### I'm building a wallet application + Use [@bsv/sdk](./bsv-sdk.md) for cryptographic operations and [@bsv/wallet-toolbox](../wallet/wallet-toolbox.md) for the full BRC-100 wallet implementation with storage and signing. ### I'm working with tokens + Use [@bsv/sdk](./bsv-sdk.md) for low-level script control, or [@bsv/btms](../wallet/btms.md) for higher-level token abstraction. ### I need to verify a transaction (SPV) + [@bsv/sdk](./bsv-sdk.md) provides full SPV support with `MerklePath` for merkle proof verification without downloading full blocks. ### I need to encode data on-chain + [@bsv/sdk](./bsv-sdk.md)'s `PushDrop` class encodes multi-field data in locking scripts, used by overlay protocols like BTMS. ## Key Concepts @@ -63,22 +72,26 @@ const key = PrivateKey.fromRandom() const recipientAddress = '1EvmsbpAY7nESLkN4ajLTMbvsaQ1HpJPGX' // Build and sign a transaction -const tx = new Transaction(1, [ - { - sourceTransaction: Transaction.fromHex('...'), - sourceOutputIndex: 0, - unlockingScriptTemplate: new P2PKH().unlock(key) - } -], [ - { - lockingScript: new P2PKH().lock(recipientAddress), - satoshis: 5000 - }, - { - lockingScript: new P2PKH().lock(key.toAddress()), - change: true - } -]) +const tx = new Transaction( + 1, + [ + { + sourceTransaction: Transaction.fromHex('...'), + sourceOutputIndex: 0, + unlockingScriptTemplate: new P2PKH().unlock(key) + } + ], + [ + { + lockingScript: new P2PKH().lock(recipientAddress), + satoshis: 5000 + }, + { + lockingScript: new P2PKH().lock(key.toAddress()), + change: true + } + ] +) // Sign and broadcast await tx.fee() @@ -90,6 +103,7 @@ console.log('Broadcasted:', response.txid) ## What Each Package Provides ### @bsv/sdk + - Elliptic curve cryptography (secp256k1), ECDSA signatures, key derivation (BRC-42/43) - 20+ script templates and Bitcoin Script interpreter - Transaction builder with fee estimation and broadcasting @@ -110,5 +124,6 @@ console.log('Broadcasted:', response.txid) ## Next Steps - **[@bsv/sdk](./bsv-sdk.md)** — Full API reference and code examples +- **[@bsv/verifast](./verifast.md)** — Optional WASM verification backend - **[Wallet Domain](../wallet/index.md)** — Higher-layer packages for persistence and key management -- **Guides** — Hands-on examples (coming soon) +- **[Guides](../../guides/index.md)** — Hands-on application and package-boundary examples diff --git a/docs/packages/sdk/verifast.md b/docs/packages/sdk/verifast.md new file mode 100644 index 000000000..9707792dd --- /dev/null +++ b/docs/packages/sdk/verifast.md @@ -0,0 +1,57 @@ +--- +id: pkg-verifast +title: '@bsv/verifast' +kind: package +domain: sdk +version: '0.3.0' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 +npm: 'https://www.npmjs.com/package/@bsv/verifast' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/verifast' +status: beta +tags: [sdk, verification, wasm, browser, worker] +--- + +# @bsv/verifast + +`@bsv/verifast` is the optional BSV BDK WebAssembly verification backend for +`@bsv/sdk`. It supports Node ESM and CommonJS, browser and worker ESM, and a +classic-script/UMD integration. + +## Install + +```bash +npm install @bsv/verifast @bsv/sdk +``` + +The validated WASM assets ship inside the package. Consumers do not run a +native compiler or post-install build. + +## Use + +```ts +import { Transaction } from '@bsv/sdk' +import { BdkVerifier } from '@bsv/verifast' + +const verifier = new BdkVerifier() +await verifier.preload() + +const transaction = Transaction.fromEF(extendedFormatBytes) +const valid = await transaction.verify('scripts only', undefined, undefined, verifier) +``` + +The default adaptive mode uses the SDK interpreter while a cold WASM module +warms and routes eligible verification work to WASM afterward. Use explicit +consensus or policy context when establishing transaction validity. Batch and +worker APIs are bounded and can be preloaded for latency-sensitive workloads. + +Build and package checks exercise real WASM verification in Node, browser +bundlers, workers, CommonJS, and the classic browser payload. See the +[package README](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/verifast#readme) +for routing, network, batch, resource, and UMD details. + +## License + +Open BSV License Version 6. See the +[package license](https://github.com/bsv-blockchain/ts-stack/blob/main/packages/verifast/LICENSE.txt). diff --git a/docs/packages/wallet/btms-permission-module.md b/docs/packages/wallet/btms-permission-module.md index b22c5d47e..ca5cd0acd 100644 --- a/docs/packages/wallet/btms-permission-module.md +++ b/docs/packages/wallet/btms-permission-module.md @@ -1,15 +1,16 @@ --- id: btms-permission-module -title: "@bsv/btms-permission-module" +title: '@bsv/btms-permission-module' kind: package domain: wallet -npm: "@bsv/btms-permission-module" -version: "1.1.1" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +npm: '@bsv/btms-permission-module' +version: '1.1.1' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 status: stable -tags: ["tokens", "permissions"] -github_repo: "https://github.com/bsv-blockchain/ts-stack" +tags: ['tokens', 'permissions'] +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/btms-permission-module' --- # @bsv/btms-permission-module @@ -36,11 +37,11 @@ const wallet = await createWallet() const requestTokenAccess = async (app: string, message: string): Promise => { const details = JSON.parse(message) - + const approved = confirm( `${app} wants to ${details.operation} ${details.sendAmount || details.burnAmount} of "${details.tokenName}"` ) - + return approved } @@ -70,11 +71,11 @@ const wallet = await createWallet() const requestTokenAccess = async (app: string, message: string): Promise => { const details = JSON.parse(message) - + const approved = confirm( `${app} wants to ${details.operation} ${details.sendAmount || details.burnAmount} of "${details.tokenName}"` ) - + return approved } @@ -91,7 +92,7 @@ import { createBtmsModule } from '@bsv/btms-permission-module' // Create module with no prompt handler — all requests denied const module = createBtmsModule({ - wallet, + wallet // No promptHandler → defaults to deny all }) @@ -111,7 +112,7 @@ const tokenModule = createBtmsModule({ const permissionsManager = new WalletPermissionsManager(wallet, appOrigin, { permissionModules: { - btms: tokenModule // Register under 'btms' key + btms: tokenModule // Register under 'btms' key } }) diff --git a/docs/packages/wallet/btms.md b/docs/packages/wallet/btms.md index c378698c9..b4aacc31e 100644 --- a/docs/packages/wallet/btms.md +++ b/docs/packages/wallet/btms.md @@ -1,15 +1,16 @@ --- id: btms -title: "@bsv/btms" +title: '@bsv/btms' kind: package domain: wallet -npm: "@bsv/btms" -version: "1.1.1" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +npm: '@bsv/btms' +version: '1.1.1' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 status: stable -tags: ["tokens", "protocol"] -github_repo: "https://github.com/bsv-blockchain/ts-stack" +tags: ['tokens', 'protocol'] +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/btms' --- # @bsv/btms @@ -54,7 +55,7 @@ const result = await btms.issue(1000000, { iconURL: 'https://example.com/gold.png' }) -console.log('Asset ID:', result.assetId) // 'abc123...def.0' +console.log('Asset ID:', result.assetId) // 'abc123...def.0' // Check balance const balance = await btms.getBalance(result.assetId) @@ -83,9 +84,9 @@ for (const asset of assets) { ```typescript const recipientIdentityKey = '025706528f0f6894b2ba505007267ccff1133e004452a1f6b72ac716f246216366' const sendResult = await btms.send( - 'abc123...def.0', // Asset ID from issuance + 'abc123...def.0', // Asset ID from issuance recipientIdentityKey, - 100 // Amount + 100 // Amount ) console.log('Txid:', sendResult.txid) @@ -120,7 +121,7 @@ const resultAll = await btms.burn('abc123...def.0') const verifierKey = '02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5' const proofResult = await btms.proveOwnership( 'abc123...def.0', - 500, // Amount to prove + 500, // Amount to prove verifierKey ) if (!proofResult.success || !proofResult.proof) { diff --git a/docs/packages/wallet/index.md b/docs/packages/wallet/index.md index 4e4f5f00c..8626578b6 100644 --- a/docs/packages/wallet/index.md +++ b/docs/packages/wallet/index.md @@ -3,12 +3,12 @@ id: wallet-domain title: Wallet kind: meta domain: wallet -version: "n/a" -last_updated: "2026-04-28" -last_verified: "2026-04-28" +version: 'n/a' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable -tags: ["domain", "wallet"] +tags: ['domain', 'wallet'] --- # Wallet Domain @@ -19,31 +19,39 @@ The wallet domain builds on top of [@bsv/sdk](../sdk/bsv-sdk.md). If you only ne ## Packages in this Domain -| Package | Purpose | -|---------|---------| -| [@bsv/wallet-toolbox](./wallet-toolbox.md) | Reference BRC-100 wallet implementation with SQLite/MySQL/IndexedDB storage, background monitoring, Shamir key sharing, and permission management | -| [@bsv/btms](./btms.md) | UTXO-based token issuance, transfer, burning, and ownership proof validation | -| [@bsv/btms-permission-module](./btms-permission-module.md) | Framework-agnostic BRC-98/99 permission hooks for BTMS token spending with custom UI callback | -| [@bsv/wallet-relay](./wallet-relay.md) | Mobile-to-desktop wallet pairing via QR codes and encrypted WebSocket relay with React components | +| Package | Purpose | +| ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| [@bsv/wallet-toolbox](./wallet-toolbox.md) | Node BRC-100 wallet implementation with SQLite/MySQL storage, background monitoring, Shamir key sharing, and permission management | +| [@bsv/wallet-toolbox-client](./wallet-toolbox-client.md) | Browser-safe wallet, IndexedDB, and remote storage distribution | +| [@bsv/wallet-toolbox-mobile](./wallet-toolbox-mobile.md) | React Native/mobile-safe wallet and remote storage distribution | +| [@bsv/btms](./btms.md) | UTXO-based token issuance, transfer, burning, and ownership proof validation | +| [@bsv/btms-permission-module](./btms-permission-module.md) | Framework-agnostic BRC-98/99 permission hooks for BTMS token spending with custom UI callback | +| [@bsv/wallet-relay](./wallet-relay.md) | Mobile-to-desktop wallet pairing via QR codes and encrypted WebSocket relay with React components | ## Common Use Cases ### I'm building an app and need user signatures + Use [@bsv/wallet-toolbox](./wallet-toolbox.md) to create a full wallet with persistent storage and signing, or integrate with user-installed wallets via the BRC-100 interface. ### I'm building a web app that integrates with user wallets + Use [@bsv/wallet-toolbox](./wallet-toolbox.md) for local wallet, or [@bsv/wallet-relay](./wallet-relay.md) for mobile wallet pairing via QR code. ### I need to issue and manage tokens + Use [@bsv/btms](./btms.md) for token operations (issue, send, accept, burn). Integrate with [@bsv/wallet-toolbox](./wallet-toolbox.md) for wallet signing and [@bsv/btms-permission-module](./btms-permission-module.md) for permission control. ### I'm building a wallet application myself + Use [@bsv/wallet-toolbox](./wallet-toolbox.md) as reference implementation. It demonstrates BRC-100 compliance, storage abstraction, key management, and background monitoring patterns. ### I need mobile-to-desktop signing without downloading wallet software + Use [@bsv/wallet-relay](./wallet-relay.md) for QR pairing. Desktop shows QR, mobile scans, then mobile wallet signs and relays responses back encrypted. ### I want fine-grained permission control over token operations + Use [@bsv/btms-permission-module](./btms-permission-module.md) with your custom permission handler (modal, alert, web component, etc.). ## Key Concepts @@ -65,16 +73,19 @@ Use [@bsv/btms-permission-module](./btms-permission-module.md) with your custom ## Storage & Platform Support -| Package | Node.js | Browser | Mobile | -|---------|---------|---------|--------| -| **wallet-toolbox** | SQLite, MySQL | IndexedDB, Remote | IndexedDB, Remote | -| **btms** | ✓ | ✓ | ✓ | -| **btms-permission-module** | ✓ | ✓ | ✓ | -| **wallet-relay** | Server | React components | Supported via relay | +| Package | Node.js | Browser | Mobile | +| -------------------------- | ------------- | ----------------- | ------------------------ | +| **wallet-toolbox** | SQLite, MySQL | — | — | +| **wallet-toolbox-client** | Build tooling | IndexedDB, Remote | Hybrid/WebView dependent | +| **wallet-toolbox-mobile** | Build tooling | — | Remote | +| **btms** | ✓ | ✓ | ✓ | +| **btms-permission-module** | ✓ | ✓ | ✓ | +| **wallet-relay** | Server | React components | Supported via relay | ## When to Use Each Package ### Wallet Toolbox + - You're building a wallet application - You need persistent transaction history and UTXO state - You want BRC-100 compliance @@ -83,30 +94,36 @@ Use [@bsv/btms-permission-module](./btms-permission-module.md) with your custom - You need different storage for different platforms ### BTMS + - You're building token issuance/transfer system - You need UTXO-based tokens with on-chain metadata - You want automated PushDrop encoding/decoding - You need ownership proofs for collateral/escrow ### BTMS Permission Module + - You want user approval for token operations - You need framework-agnostic permission callbacks - You're building a wallet with permission control - You want custom UI for permission prompts ### Wallet Relay + - You're building a web app needing mobile signatures - You want QR-based pairing (no software download) - You need encrypted communication over untrusted networks - You want stateless session management ### NOT for these + - Don't use wallet packages if you only need transaction building — use [@bsv/sdk](../sdk/bsv-sdk.md) directly - Don't use wallet-toolbox if you only need BRC-100 interface types — import from SDK instead ## Next Steps - **[@bsv/wallet-toolbox](./wallet-toolbox.md)** — Full wallet implementation +- **[@bsv/wallet-toolbox-client](./wallet-toolbox-client.md)** — Browser distribution +- **[@bsv/wallet-toolbox-mobile](./wallet-toolbox-mobile.md)** — Mobile distribution - **[@bsv/btms](./btms.md)** — Token protocol - **[@bsv/wallet-relay](./wallet-relay.md)** — Mobile pairing - **[@bsv/btms-permission-module](./btms-permission-module.md)** — Token permissions diff --git a/docs/packages/wallet/wallet-relay.md b/docs/packages/wallet/wallet-relay.md index db4ad7e2c..455d61b8a 100644 --- a/docs/packages/wallet/wallet-relay.md +++ b/docs/packages/wallet/wallet-relay.md @@ -1,15 +1,16 @@ --- id: wallet-relay -title: "@bsv/wallet-relay" +title: '@bsv/wallet-relay' kind: package domain: wallet -npm: "@bsv/wallet-relay" -version: "0.2.2" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +npm: '@bsv/wallet-relay' +version: '0.2.3' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 status: stable -tags: ["wallet", "relay"] -github_repo: "https://github.com/bsv-blockchain/ts-stack" +tags: ['wallet', 'relay'] +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/ts-wallet-relay' --- # @bsv/wallet-relay @@ -34,18 +35,20 @@ import { WalletRelayService } from '@bsv/wallet-relay' import { ProtoWallet, PrivateKey } from '@bsv/sdk' const app = express() -app.use(cors({ - origin: process.env.ORIGIN, - allowedHeaders: ['Content-Type', 'Authorization', 'X-Desktop-Token'] -})) +app.use( + cors({ + origin: process.env.ORIGIN, + allowedHeaders: ['Content-Type', 'Authorization', 'X-Desktop-Token'] + }) +) app.use(express.json()) const server = createServer(app) const wallet = new ProtoWallet(PrivateKey.fromHex(process.env.WALLET_PRIVATE_KEY!)) -new WalletRelayService({ - app, - server, +new WalletRelayService({ + app, + server, wallet, relayUrl: process.env.RELAY_URL, origin: process.env.ORIGIN @@ -72,7 +75,7 @@ function WalletConnection() { const setup = async () => { const session = await createSession() setSessionId(session.sessionId) - setQrData(session.qrDataUrl) // Base64 PNG + setQrData(session.qrDataUrl) // Base64 PNG } setup() }, []) @@ -128,8 +131,8 @@ function App() { return ( <> - { + { console.log('Local wallet connected') // Use WalletClient directly. }} @@ -148,19 +151,19 @@ import { WalletRelayClient } from '@bsv/wallet-relay/client' import { P2PKH } from '@bsv/sdk' async function sendPayment(client: WalletRelayClient) { - const lockingScript = new P2PKH() - .lock('1EvmsbpAY7nESLkN4ajLTMbvsaQ1HpJPGX') - .toHex() + const lockingScript = new P2PKH().lock('1EvmsbpAY7nESLkN4ajLTMbvsaQ1HpJPGX').toHex() const response = await client.sendRequest('createAction', { description: 'Send payment', - outputs: [{ - satoshis: 5000, - lockingScript, - outputDescription: 'payment output' - }] + outputs: [ + { + satoshis: 5000, + lockingScript, + outputDescription: 'payment output' + } + ] }) - + if (response.error) { console.error('Mobile rejected:', response.error) } else { diff --git a/docs/packages/wallet/wallet-toolbox-client.md b/docs/packages/wallet/wallet-toolbox-client.md new file mode 100644 index 000000000..f921ca578 --- /dev/null +++ b/docs/packages/wallet/wallet-toolbox-client.md @@ -0,0 +1,58 @@ +--- +id: pkg-wallet-toolbox-client +title: '@bsv/wallet-toolbox-client' +kind: package +domain: wallet +version: '2.4.5' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 +npm: 'https://www.npmjs.com/package/@bsv/wallet-toolbox-client' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/wallet-toolbox/client' +status: stable +tags: [wallet, browser, indexeddb, storage, brc-100] +--- + +# @bsv/wallet-toolbox-client + +`@bsv/wallet-toolbox-client` is the browser-safe Wallet Toolbox distribution. +It includes the BRC-100 wallet, signer, services, IndexedDB storage, and remote +storage client without Node-only Knex, SQLite, MySQL, or filesystem adapters. + +## Install + +```bash +npm install @bsv/wallet-toolbox-client @bsv/sdk +``` + +## Use + +```ts +import { + Services, + StorageClient, + Wallet, + WalletSigner, + WalletStorageManager +} from '@bsv/wallet-toolbox-client' +``` + +The package publishes browser/import ESM and CommonJS conditions with matching +declarations. Its installed-consumer gate bundles the exact tarball with Vite +and esbuild, rejects Node-only modules, validates source maps, and enforces +compressed and uncompressed size budgets. + +Remote Wallet Storage often serves public web, extension, WUI, and mobile +clients from origins unknown at build time. The client imposes no origin +allowlist. Operators may explicitly configure one at the service edge, but +CORS is not authentication; storage authorization and identity isolation +remain mandatory in either mode. + +See the +[package README](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/wallet-toolbox/client#readme) +for complete remote and IndexedDB setup. + +## License + +Open BSV License Version 6. See the +[package license](https://github.com/bsv-blockchain/ts-stack/blob/main/packages/wallet/wallet-toolbox/client/LICENSE.txt). diff --git a/docs/packages/wallet/wallet-toolbox-examples.md b/docs/packages/wallet/wallet-toolbox-examples.md index de62dfa5c..c7eccd510 100644 --- a/docs/packages/wallet/wallet-toolbox-examples.md +++ b/docs/packages/wallet/wallet-toolbox-examples.md @@ -1,15 +1,15 @@ --- id: pkg-wallet-toolbox-examples -title: "@bsv/wallet-toolbox-examples" +title: '@bsv/wallet-toolbox-examples' kind: package domain: wallet -npm: "@bsv/wallet-toolbox-examples" -version: "1.1.156" -last_updated: "2026-04-29" -last_verified: "2026-04-29" +version: '1.1.157' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/wallet-toolbox-examples' status: stable -tags: ["wallet", "examples", "reference"] +tags: ['wallet', 'examples', 'reference'] --- # @bsv/wallet-toolbox-examples diff --git a/docs/packages/wallet/wallet-toolbox-mobile.md b/docs/packages/wallet/wallet-toolbox-mobile.md new file mode 100644 index 000000000..78c39d631 --- /dev/null +++ b/docs/packages/wallet/wallet-toolbox-mobile.md @@ -0,0 +1,57 @@ +--- +id: pkg-wallet-toolbox-mobile +title: '@bsv/wallet-toolbox-mobile' +kind: package +domain: wallet +version: '2.4.5' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 +npm: 'https://www.npmjs.com/package/@bsv/wallet-toolbox-mobile' +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/wallet-toolbox/mobile' +status: stable +tags: [wallet, react-native, mobile, storage, brc-100] +--- + +# @bsv/wallet-toolbox-mobile + +`@bsv/wallet-toolbox-mobile` is the React Native and mobile-safe Wallet +Toolbox distribution. It includes wallet, signer, services, monitoring, and +remote storage surfaces without Knex, SQLite/MySQL, IndexedDB, or Node-only IO. + +## Install + +```bash +npm install @bsv/wallet-toolbox-mobile @bsv/sdk +``` + +## Use + +```ts +import { + Services, + StorageClient, + Wallet, + WalletSigner, + WalletStorageManager +} from '@bsv/wallet-toolbox-mobile' +``` + +The package publishes `react-native`, import ESM, and CommonJS conditions with +matching declarations. Its installed-consumer gate bundles the exact tarball +with Metro, checks the mobile-safe module boundary, compiles optimized Hermes +bytecode, validates source maps, and enforces size budgets. + +Native requests are not governed by browser CORS, while WebView and hybrid +clients can be. Remote Storage should remain reachable by intended public +clients unless an operator explicitly configures an allowlist. Authentication +and authorization remain service-layer controls. + +See the +[package README](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/wallet-toolbox/mobile#readme) +for remote storage setup and supported runtime assumptions. + +## License + +Open BSV License Version 6. See the +[package license](https://github.com/bsv-blockchain/ts-stack/blob/main/packages/wallet/wallet-toolbox/mobile/LICENSE.txt). diff --git a/docs/packages/wallet/wallet-toolbox.md b/docs/packages/wallet/wallet-toolbox.md index 0b675c49d..b300eb2ee 100644 --- a/docs/packages/wallet/wallet-toolbox.md +++ b/docs/packages/wallet/wallet-toolbox.md @@ -1,15 +1,16 @@ --- id: wallet-toolbox -title: "@bsv/wallet-toolbox" +title: '@bsv/wallet-toolbox' kind: package domain: wallet -npm: "@bsv/wallet-toolbox" -version: "2.4.4" -last_updated: "2026-07-24" -last_verified: "2026-07-24" +npm: '@bsv/wallet-toolbox' +version: '2.4.5' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 status: stable -tags: ["wallet", "brc100"] -github_repo: "https://github.com/bsv-blockchain/ts-stack" +tags: ['wallet', 'brc100'] +repo: 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/wallet-toolbox' --- # @bsv/wallet-toolbox @@ -33,17 +34,17 @@ npm install @bsv/wallet-toolbox-mobile ## What It Provides -| Component | Purpose | -|-----------|---------| -| `Wallet` | Main BRC-100 implementation. | -| `WalletStorageManager` | Coordinates active and backup storage providers. | -| Storage providers | SQL/Knex, IndexedDB, and remote storage over HTTP. | -| `WalletSigner` | Bridges wallet-controlled keys into SDK transaction signing flows. | -| `Services` | Network service container for broadcast, chain tracking, and proof services. | -| `Monitor` | Background wallet maintenance tasks. | -| Key managers | BRC-42/43 derivation, privileged key management, Shamir-based recovery flows. | -| `WalletPermissionsManager` | Permission gating around wallet methods and reserved protocols/baskets. | -| `MockChain` | Test chain utilities for wallet behavior without a live network. | +| Component | Purpose | +| -------------------------- | ----------------------------------------------------------------------------- | +| `Wallet` | Main BRC-100 implementation. | +| `WalletStorageManager` | Coordinates active and backup storage providers. | +| Storage providers | SQL/Knex, IndexedDB, and remote storage over HTTP. | +| `WalletSigner` | Bridges wallet-controlled keys into SDK transaction signing flows. | +| `Services` | Network service container for broadcast, chain tracking, and proof services. | +| `Monitor` | Background wallet maintenance tasks. | +| Key managers | BRC-42/43 derivation, privileged key management, Shamir-based recovery flows. | +| `WalletPermissionsManager` | Permission gating around wallet methods and reserved protocols/baskets. | +| `MockChain` | Test chain utilities for wallet behavior without a live network. | ## Source-Backed Setup Pattern @@ -73,18 +74,18 @@ When every input can be signed by the wallet, `createAction` can return a comple ```typescript export async function createP2pkhOutput(recipientAddress: string) { - const lockingScript = Setup - .getLockP2PKH(recipientAddress) - .toHex() + const lockingScript = Setup.getLockP2PKH(recipientAddress).toHex() const result = await setup.wallet.createAction({ description: 'Create payment', labels: ['payment'], - outputs: [{ - lockingScript, - satoshis: 1000, - outputDescription: 'Payment output' - }], + outputs: [ + { + lockingScript, + satoshis: 1000, + outputDescription: 'Payment output' + } + ], options: { randomizeOutputs: false, acceptDelayedBroadcast: false @@ -109,16 +110,20 @@ export async function finishCustomSpend(args: { const created = await setup.wallet.createAction({ description: 'Spend custom input', inputBEEF: args.inputBEEF, - inputs: [{ - outpoint: args.outpoint, - unlockingScriptLength: 108, - inputDescription: 'Custom input' - }], - outputs: [{ - lockingScript: args.lockingScript, - satoshis: 1000, - outputDescription: 'Payment output' - }] + inputs: [ + { + outpoint: args.outpoint, + unlockingScriptLength: 108, + inputDescription: 'Custom input' + } + ], + outputs: [ + { + lockingScript: args.lockingScript, + satoshis: 1000, + outputDescription: 'Payment output' + } + ] }) await setup.wallet.signAction({ @@ -135,10 +140,10 @@ See `packages/wallet/wallet-toolbox-examples/src/p2pkh.ts`, `brc29.ts`, `pushdro ## Storage Models -| Model | Use | -|-------|-----| -| SQL/Knex | Node.js wallets and servers with SQLite, MySQL, or another Knex-supported database. | -| IndexedDB | Browser and mobile wallets that keep state on-device. | +| Model | Use | +| -------------- | ------------------------------------------------------------------------------------------------------- | +| SQL/Knex | Node.js wallets and servers with SQLite, MySQL, or another Knex-supported database. | +| IndexedDB | Browser and mobile wallets that keep state on-device. | | Remote storage | Wallet clients that delegate storage to a Wallet Infra endpoint such as `https://store-us-1.bsvb.tech`. | ## When to Use This diff --git a/docs/reference/brc-index.md b/docs/reference/brc-index.md index e75b73a0b..c1517a520 100644 --- a/docs/reference/brc-index.md +++ b/docs/reference/brc-index.md @@ -3,8 +3,8 @@ id: brc-index title: 'BRC Standards Index' kind: reference version: 'n/a' -last_updated: '2026-05-14' -last_verified: '2026-05-14' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable tags: [reference, brc, standards] @@ -18,14 +18,12 @@ All Bitcoin Request for Comments (BRC) standards referenced in ts-stack source, | BRC | Title | Domain | Spec | Key Packages | | ------- | -------------------------------------------- | ------------ | --------------------------------------- | -------------------------------------------------------------------------------------------- | -| BRC-14 | Script Evaluation & Sighash | Scripts | — | `@bsv/sdk` (5,116 conformance vectors) | +| BRC-14 | Script Evaluation & Sighash | Scripts | — | `@bsv/sdk` | | BRC-29 | Peer-to-Peer Payment Protocol | Payments | [spec](../specs/brc-29-peer-payment.md) | `@bsv/paymail`, `@bsv/message-box-client` | | BRC-31 | HTTP Mutual Authentication Handshake | Auth | [spec](../specs/brc-31-auth.md) | `@bsv/auth-express-middleware`, `@bsv/authsocket` | | BRC-42 | Key Derivation Scheme (BKDS) | Crypto | — | `@bsv/sdk`, `@bsv/wallet-toolbox` (heavy BRC-42 vector coverage in sdk/keys + wallet/brc100) | | BRC-43 | Security Levels for BKDS | Crypto | — | `@bsv/sdk` | | BRC-48 | PushDrop Token Protocol | Tokens | — | `@bsv/overlay-topics`, `@bsv/btms` | -| BRC-62 | BEEF — Background Evaluation Extended Format | Transactions | — | `@bsv/sdk` | -| BRC-74 | BUMP — BSV Unified Merkle Path | Transactions | — | `@bsv/sdk` | | BRC-95 | BEEF V2 | Transactions | — | `@bsv/sdk` | | BRC-62 | BEEF — Background Evaluation Extended Format | Transactions | — | `@bsv/sdk` (conformance vectors) | | BRC-74 | BUMP — BSV Unified Merkle Path | Transactions | — | `@bsv/sdk` (conformance vectors) | @@ -35,6 +33,7 @@ All Bitcoin Request for Comments (BRC) standards referenced in ts-stack source, | BRC-103 | Peer Mutual Authentication Framework | Auth | — | `@bsv/authsocket`, `@bsv/auth-express-middleware` | | BRC-104 | Message-Layer Transport | Auth | — | `@bsv/authsocket` | | BRC-121 | HTTP 402 Payment Protocol | Payments | [spec](../specs/brc-121-402.md) | `@bsv/402-pay` | +| BRC-136 | Block-Anchored Set Mapping (BASM) | Overlay | — | `@bsv/overlay`, `@bsv/overlay-express` | ## Additional Referenced Standards @@ -47,7 +46,9 @@ These BRCs appear in the codebase, specs, or conformance vectors: | BRC-3 | Address format | | BRC-10 | Script templates | | BRC-18 | Message signing (BSM) | -| BRC-22 | Output description | +| BRC-20 | ARC transaction broadcast behavior | +| BRC-21 | Graph-aware synchronization | +| BRC-22 | Overlay lookup and topic management | | BRC-24 | Derivation path metadata | | BRC-26 | UHRP — Universal Hash Resolution Protocol | | BRC-30 | Output script hash | @@ -144,6 +145,16 @@ Implementation: `@bsv/402-pay` (client and server). The separate Spec: `specs/payments/brc121.yaml` +### BRC-136: Block-Anchored Set Mapping + +BRC-136 records per-topic block anchors and cumulative Topic Anchor Chain +values so Overlay peers can compare admitted-set completeness and recover +across reorgs. + +Implementations: `@bsv/overlay`, `@bsv/overlay-express` + +Conformance vectors: `conformance/vectors/sync/brc136-basm.json` + ## Finding Implementations ```bash @@ -158,12 +169,13 @@ ls conformance/vectors/sdk/keys/ Each core BRC is validated against JSON test vectors in `conformance/vectors/`. The TypeScript implementation generates these vectors; Go, Python, and Rust implementations validate against them. -| BRC | Vector path | -| ------- | --------------------------------------- | -| BRC-42 | `conformance/vectors/sdk/keys/` | -| BRC-74 | `conformance/vectors/sdk/transactions/` | -| BRC-29 | `conformance/vectors/wallet/brc29/` | -| BRC-31 | `conformance/vectors/messaging/brc31/` | -| BRC-100 | `conformance/vectors/wallet/brc100/` | +| BRC | Vector path | +| ------- | ------------------------------------------- | +| BRC-42 | `conformance/vectors/sdk/keys/` | +| BRC-74 | `conformance/vectors/sdk/transactions/` | +| BRC-29 | `conformance/vectors/wallet/brc29/` | +| BRC-31 | `conformance/vectors/messaging/brc31/` | +| BRC-100 | `conformance/vectors/wallet/brc100/` | +| BRC-136 | `conformance/vectors/sync/brc136-basm.json` | See [Conformance Testing](../conformance/index.md) for how to run the test suite. diff --git a/docs/reference/dependency-policy.md b/docs/reference/dependency-policy.md index 573649bea..52bb46635 100644 --- a/docs/reference/dependency-policy.md +++ b/docs/reference/dependency-policy.md @@ -22,10 +22,9 @@ images on one reviewed dependency baseline. - TypeScript 7.0.2 native compiler, with the official TypeScript 6 compatibility API for API-dependent tools - Oxlint for TypeScript linting -CI, conformance, documentation, and release workflows run on Node.js 24. Package -lint errors fail the build. Existing warnings remain visible and are reduced -progressively; a package may opt into stricter warning enforcement once its -warning baseline reaches zero. +CI, conformance, documentation, and release workflows run on Node.js 24. +Root and package lint are warning-free and use blocking warning denial. A new +warning is a regression, not baseline debt to be accepted or ratcheted later. Every published package declares `engines.node: ">=22"`. Node.js 22 is the consumer runtime floor; Node.js 24.11 is the stricter contributor and release @@ -72,6 +71,13 @@ tracker. GitHub Actions are pinned to immutable commit SHAs with accurate release-version comments; a generated action bump is still reviewed for permissions, runtime changes, and behavior before merge. +Dependabot is a proposal mechanism, not a reviewer or release manager. A +maintainer must establish why each change is needed, inspect changelogs and +runtime/deployment effects, remove obsolete dependencies, and require the same +tests, security analysis, and package checks as human-authored work. Bot noise, +conflicting single-package bumps, and first-party version PRs are consolidated +or closed rather than merged piecemeal. + ## Supply-chain controls `pnpm-workspace.yaml` is the source of truth for installation controls: @@ -90,12 +96,17 @@ then rebuild only the explicitly allowlisted `better-sqlite3` binding they need; the full build lane remains the single place that runs the workspace's approved installation scripts. -The version-consistency gate also rejects public package manifests that place -type declarations, test runners, test clients, linters, documentation -generators, or TypeScript build tools in `dependencies`. This prevents -development-only advisory trees from leaking into clean consumer installs. +The version-consistency gate rejects public package manifests that place test +runners, test clients, linters, documentation generators, or TypeScript build +tools in `dependencies`. Type packages remain development-only unless the +governed project inventory names one as a declaration dependency because the +published `.d.ts` surface imports that external module. A governed declaration +dependency must be shipped in `dependencies`, its corresponding runtime module +must be a dependency or peer, and clean packed consumers must typecheck it. +This keeps build-only advisory trees out of consumer installs without shipping +unresolvable public declarations. -The workspace carries two narrow audited dependency overrides: +The root workspace carries two narrow audited dependency overrides: - Jest 30.4.2 still constrains its reporting and coverage graph to minimatch releases that require `brace-expansion` 1.x/2.x, while @@ -111,6 +122,12 @@ have owners, evidence, review dates, and upstream removal conditions in the repository-health exception registry. Any future temporary override must meet the same standard. +The independently locked OpenAPI generator also carries a narrow Redocly +compatibility override. It is isolated from runtime packages, registered with +the same owner/review/removal fields, and must regenerate identical checked-in +output. These three exceptions are not permanent policy: their review dates +are removal deadlines unless fresh evidence justifies an explicit extension. + The former AsyncAPI generator override was eliminated by replacing that dependency with a deterministic renderer built on the maintained `yaml` parser. This removes the legacy parser, @@ -119,9 +136,9 @@ transitive substitutions. ## Advisory disposition -The verified 2026-07-25 frozen dependency graph has no known audit findings or -accepted advisory holds after applying the single tracked Jest compatibility -substitution. All other advisory paths were removed at their causes: +The verified 2026-07-27 frozen root and infrastructure dependency graphs have +no known audit findings after the registered compatibility substitutions. All +other advisory paths were removed at their causes: - the unused message-box `webpack-dev-server` dependency and its vulnerable `uuid` path were deleted; @@ -150,6 +167,17 @@ consumer and development graphs first. 7. Merge the generated version-sync PR, then release any infra images whose first-party dependency ranges changed. +The generated sync PR may refresh infrastructure lockfiles with +`npm install --package-lock-only --ignore-scripts`. That command names no +package, executes no lifecycle script, and only produces a reviewed committed +lock for later `npm ci` and audit use. OpenSSF Scorecard alerts #200 and #221 +are the same governed false positive after workflow line movement; retain the +check and the exception evidence rather than deleting the deterministic lock +refresh. + Breaking major upgrades are handled as focused migrations with an explicit compatibility and rollback plan. They are not forced into the workspace through transitive overrides. + +See [Release and Operations Guide](./release-operations.md) for the complete +preflight, publication, reconciliation, image, failure, and rollback path. diff --git a/docs/reference/index.md b/docs/reference/index.md index 38f164c8c..91e65e73a 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -3,8 +3,8 @@ id: reference-overview title: 'Reference' kind: meta version: 'n/a' -last_updated: '2026-07-26' -last_verified: '2026-07-26' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable tags: [reference, api, index] @@ -19,7 +19,12 @@ Quick reference material for API details and protocol indices. - **[BRC Standards Index](./brc-index.md)** — All BRC standards with links to implementations - **[Container supply chain](./container-supply-chain.md)** — Immutable images, scanning, SBOMs, signatures, attestations, verification, and rollback - **[Dependency and release policy](./dependency-policy.md)** — Runtime baseline, supply-chain controls, advisory handling, and release rules +- **[Generated stack facts](./stack-facts.md)** — Current source versions, runtime profiles, release routes, infrastructure manifests, and conformance totals - **[Licensing policy](./licensing.md)** — Uniform Open BSV License Version 6 declarations, package files, and drift controls +- **[npm package supply chain](./npm-package-supply-chain.md)** — Pack-once candidates, SBOMs, attestations, OIDC publication, and registry verification +- **[Release and operations guide](./release-operations.md)** — Scope, preflight, publication, deployment, failure handling, and rollback +- **[Repository health controls](./repository-health.md)** — Machine-readable project, package, documentation, test, and exception governance +- **[Test quality governance](./test-quality-governance.md)** — Required, manual, live, property, mutation, and conformance test ownership - **[July 2026 modernization release](./release-2026-07-25.md)** — Package versions, compatibility notes, and verification scope - **[TypeScript compiler and tooling boundary](./typescript-toolchain.md)** — Native TypeScript 7 CLI, compatibility API, enforcement, and upgrade policy - **TypeDoc API docs** — Per-package generated reference (see links below) diff --git a/docs/reference/npm-package-supply-chain.md b/docs/reference/npm-package-supply-chain.md index 76a182e8a..d2b9d5bff 100644 --- a/docs/reference/npm-package-supply-chain.md +++ b/docs/reference/npm-package-supply-chain.md @@ -79,14 +79,15 @@ Download the registry tarball without installing it, then verify its GitHub attestations: ```bash -npm pack @bsv/sdk@2.2.0 +SDK_VERSION="$(npm view @bsv/sdk version)" +npm pack "@bsv/sdk@$SDK_VERSION" -gh attestation verify bsv-sdk-2.2.0.tgz \ +gh attestation verify "bsv-sdk-$SDK_VERSION.tgz" \ --repo bsv-blockchain/ts-stack \ --signer-workflow bsv-blockchain/ts-stack/.github/workflows/release.yaml \ --predicate-type https://slsa.dev/provenance/v1 -gh attestation verify bsv-sdk-2.2.0.tgz \ +gh attestation verify "bsv-sdk-$SDK_VERSION.tgz" \ --repo bsv-blockchain/ts-stack \ --signer-workflow bsv-blockchain/ts-stack/.github/workflows/release.yaml \ --predicate-type https://cyclonedx.org/bom diff --git a/docs/reference/release-operations.md b/docs/reference/release-operations.md new file mode 100644 index 000000000..500707c1a --- /dev/null +++ b/docs/reference/release-operations.md @@ -0,0 +1,195 @@ +--- +id: release-operations +title: 'Release and Operations Guide' +kind: reference +version: '1.0.0' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 +status: stable +tags: [reference, releases, operations, rollback, npm, containers] +--- + +# Release and Operations Guide + +This guide connects source versions, npm publication, post-release dependency +reconciliation, infrastructure images, deployments, and rollback. It does not +authorize a release: publication or deployment starts only when an operator +explicitly requests it. + +## Release invariants + +- Release only a reviewed commit reachable from `main`. +- Never build or publish npm packages from a workstation. +- Never build Linux/amd64 production images on an unverified local macOS + toolchain; use the repository workflow. +- Treat package versions and image tags as immutable. +- Promote the exact packed tarball or image digest that passed its security and + provenance gates. +- Do not bypass a failing audit, package consumer, dependency review, CodeQL, + Sonar finding, image scan, attestation, or registry-integrity check. +- Keep public services reachable by default when that is their product + contract. CORS and CSP are configurable deployment controls, not + authentication or authorization. + +## 1. Decide the release scope + +Use the [Generated Stack Facts](./stack-facts.md) page for current source +versions and the package graph. + +1. Classify each public change as patch, minor, or major. +2. Include every package whose packed bytes or manifest changed. +3. Inspect first-party dependents for declaration, bundle, range, wire, and + runtime effects. +4. For infrastructure consumers, identify which image manifests and locks will + need reconciliation after npm publication. +5. For breaking or persisted-data changes, write migration and rollback steps + before changing versions. + +A broad code change does not justify bumping all packages automatically, and a +small diff does not justify omitting an affected dependent. + +## 2. Source preflight + +Before creating a release tag, require green exact-main evidence for: + +```bash +pnpm install --frozen-lockfile --ignore-scripts +pnpm rebuild esbuild +pnpm rebuild better-sqlite3 +pnpm audit:security +pnpm check-versions +pnpm build +pnpm docs:examples +pnpm typecheck +pnpm lint +pnpm format:check +pnpm test +pnpm conformance --validate-only +pnpm health:check +pnpm docs:facts:check +``` + +Also require the affected package coverage, property, mutation, browser, +mobile, CLI, WASM, clean-consumer, and `pack:check` lanes selected by CI. The +full release workflow repeats artifact-critical checks; local success is not a +substitute. + +Confirm before proceeding: + +- the target versions are absent from npm; +- no draft or unrelated change was pulled into the release; +- package READMEs, examples, API docs, migration notes, and support statements + match the candidate; +- Dependabot changes were reviewed for actual runtime and deployment effects; +- all temporary overrides still have valid evidence and removal dates; and +- open security findings are either fixed or explicitly governed with an + owner, review deadline, and objective removal condition. + +## 3. npm publication + +Use one supported trigger: + +- `packages//vX.Y.Z` for one package; +- `release/vYYYY-MM-DD` for a cascade; +- legacy `vX.Y.Z` for a cascade; or +- protected manual dispatch from `main`. + +The workflow stages immutable tarballs in an uncredentialed job, emits package +and aggregate CycloneDX SBOMs, audits licenses and vulnerabilities, verifies +clean consumers, and then passes only those bytes into the protected +`npm-production` job. That job verifies GitHub attestations, publishes with npm +OIDC provenance and lifecycle scripts disabled, and reconciles registry +integrity. + +Record the source SHA, workflow run, artifact manifest, package names/versions, +attestation results, and registry digests in the release evidence. + +## 4. Post-publication reconciliation + +A successful cascade may open `automation/sync-published-versions`. Review that +PR like source code: + +1. verify every first-party range corresponds to a published version; +2. inspect `pnpm-lock.yaml` and every changed infrastructure lock; +3. confirm lock refreshes name no ad hoc package and run with lifecycle scripts + disabled; +4. rerun audits, build/typecheck, package consumers, infrastructure tests and + images, and repository health; and +5. merge only after required checks and review threads are complete. + +Do not merge an independent Dependabot PR that fights the release-sync graph. +Consolidate it into the reviewed baseline or close it as superseded. + +## 5. Infrastructure images and deployment + +When published first-party versions affect a service: + +1. update and review its manifest and committed lock; +2. let the Linux/amd64 CI matrix build and scan the image; +3. release with an `infra/v*` tag or the protected manual workflow; +4. verify the immutable digest, SPDX SBOM, SLSA provenance, and signature; +5. update deployment manifests to the exact verified digest; +6. deploy through the system's owned GitOps/CI path; and +7. validate health, readiness, authentication, storage/database connectivity, + representative requests, logs, and rollback readiness in the real + environment. + +For Overlay, Wallet Storage, WAB, Message Box, Wallet Relay, and similar public +services, validate both: + +- the public-by-default path from an origin not known at build time; and +- the opt-in allowlist path for operators that require a restricted + deployment. + +An allowlist must be explicit configuration. Setting a hosting URL, fallback QR +origin, or CSP document must not silently turn a public service into a +same-origin-only service. Authentication, authorization, signatures, topic +validation, rate limits, and request bounds remain enforced in both modes. + +## Failure and rollback + +### Before publication + +Fix the source or workflow and rerun from a reviewed commit. Do not weaken a +gate or retag different bytes under the same version. + +### Partial npm publication + +Rerun within the retained candidate window so already-published versions are +accepted only when their registry digests exactly match the staged tarballs. +If the candidate expired or any digest differs, stop, inventory the published +subset, and plan a deliberate recovery release. + +### Defective npm release + +Deprecate the affected immutable version and publish a corrected patch or +explicit forward-fix. Advise consumers which version to pin during recovery. +Do not delete evidence or assume an npm unpublish is an operational rollback. + +### Defective image or deployment + +Roll back the deployment to a previously verified image digest. Preserve the +failing digest, source SHA, workflow URL, deployment transition, validation +results, and incident link. Reconcile any emergency live change back to +upstream source immediately. + +### Security incident + +Treat unexpected lifecycle execution, provenance/attestation failure, registry +digest mismatch, secret exposure, or active exploitation as a security +incident. Stop promotion, preserve evidence, rotate affected credentials, use a +private GitHub advisory, and coordinate disclosure under +[SECURITY.md](https://github.com/bsv-blockchain/ts-stack/security/policy). + +## Completion record + +A release is complete only when source, published artifacts, post-release +dependency state, deployed image digests where applicable, and documentation +agree. Update [tracker #324](https://github.com/bsv-blockchain/ts-stack/issues/324) +with the exact evidence; do not mark package availability or deployed behavior +complete from a local build alone. + +See [npm Package Supply Chain](./npm-package-supply-chain.md), +[Container Supply Chain](./container-supply-chain.md), and +[Versioning Policy](../about/versioning.md) for the underlying contracts. diff --git a/docs/reference/repository-health.md b/docs/reference/repository-health.md index 4cdc67fee..ad7135952 100644 --- a/docs/reference/repository-health.md +++ b/docs/reference/repository-health.md @@ -3,8 +3,8 @@ id: repository-health title: 'Repository Health Controls' kind: reference version: '1.3.0' -last_updated: '2026-07-26' -last_verified: '2026-07-26' +last_updated: '2026-07-27' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable tags: [reference, governance, quality, security, releases] @@ -35,6 +35,14 @@ For every public package, the control also enforces the exact supported Node.js 22 runtime floor, explicit public npm access, and an explicit tree-shaking side-effect declaration. +`governance/documentation-policy.json` owns the public package README and +runtime-support documentation contract. `pnpm docs:facts` generates the exact +package/version/runtime/release and conformance facts, while +`pnpm docs:facts:check` rejects stale generated output, stale parity metadata, +package READMEs that do not identify, install, demonstrate, and license the +registry artifact, and missing, duplicated, version-drifted, or +pre-consolidation public package pages. + `governance/repository-health/baselines.json` records the dated starting measurements for CI, conformance, lint, TypeScript, coverage, security, SonarCloud, governance, and published package versions. Update a measurement @@ -89,6 +97,7 @@ Run the blocking control and its unit tests: ```sh pnpm health:check +pnpm docs:facts:check pnpm test:governance pnpm test:property pnpm test:mutation --all @@ -125,7 +134,9 @@ than its source tree. The shared checker: 4. runs the `@arethetypeswrong/core` analyzer across every strict Node and bundler resolution mode; and 5. installs the tarball into a clean temporary consumer and exercises every - declared runtime module format. + declared runtime module format. The consumer installs exact tarballs for the + package's transitive `workspace:` runtime dependency closure, so coordinated + unpublished version bumps cannot pass by resolving older registry releases. Build before checking an individual package: @@ -159,7 +170,10 @@ checks: 4. published package versions match the recorded baseline; 5. exception records are owned, structurally valid, and unexpired; 6. current package-contract findings exactly match the ratcheted snapshot; and -7. the health implementation’s unit tests pass. +7. generated stack/conformance facts, all 30 public package README contracts, + and one current consolidated package page per public package are current; + and +8. the health implementation’s unit tests pass. Affected package changes also select their matching mutation targets. The parallel mutation lane restores the shared workspace build, executes only the diff --git a/docs/reference/stack-facts.md b/docs/reference/stack-facts.md new file mode 100644 index 000000000..aa840fbf1 --- /dev/null +++ b/docs/reference/stack-facts.md @@ -0,0 +1,130 @@ +--- +id: stack-facts +title: 'Generated Stack Facts' +kind: reference +version: '1.0.0' +last_updated: '2026-07-27' +last_verified: '2026-07-27' +review_cadence_days: 30 +status: stable +tags: [reference, packages, versions, runtimes, conformance, generated] +--- + +# Generated Stack Facts + +This page is generated from committed manifests and governance records. Edit the source +manifests, `governance/repository-health/projects.json`, +`governance/documentation-policy.json`, or conformance metadata, then run +`pnpm docs:facts`. CI runs `pnpm docs:facts:check` and rejects drift. + +## Support and toolchain + +| Profile | Current contract | Authority | +| --- | --- | --- | +| Repository contributors, CI, releases | Node.js >=24.11; pnpm >=10 (pnpm@10.33.2) | root package.json | +| Published npm packages | >=22 for Node consumers; browser/mobile targets remain package-specific | public package manifests | +| Standalone infrastructure | >=24 <25 | service manifests and digest-pinned Dockerfiles | +| TypeScript compiler | npm:typescript@7.0.2 compiler; npm:@typescript/typescript6@6.0.2 tooling API | @bsv/sdk package.json and TypeScript toolchain policy | + +Node engine declarations on browser and React Native packages govern package tooling and +Node consumers; they do not require a browser or mobile device to provide Node APIs. + +## Public package manifest + +The release graph currently contains **30 public packages**. Versions +below are source-manifest versions; registry publication is a separate, explicitly +authorized release action. + +| Area | Package | Source version | Profile | Runtime targets | Node engine | Source | +| --- | --- | --- | --- | --- | --- | --- | +| helpers | `@bsv/amountinator` | `2.1.1` | node-library | node | `>=22` | [packages/helpers/amountinator](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/amountinator) | +| helpers | `@bsv/did` | `0.2.1` | dual-runtime-library | browser, node | `>=22` | [packages/helpers/did](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/did) | +| helpers | `@bsv/did-client` | `1.2.1` | browser-library | browser, node, umd | `>=22` | [packages/helpers/did-client](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/did-client) | +| helpers | `@bsv/fund-wallet` | `1.4.1` | cli | node | `>=22` | [packages/helpers/fund-wallet](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/fund-wallet) | +| helpers | `@bsv/simple` | `0.4.1` | browser-library | browser, node | `>=22` | [packages/helpers/simple](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/simple) | +| helpers | `@bsv/templates` | `1.9.1` | dual-runtime-library | browser, node | `>=22` | [packages/helpers/ts-templates](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/ts-templates) | +| helpers | `@bsv/wallet-helper` | `0.1.1` | node-library | node | `>=22` | [packages/helpers/bsv-wallet-helper](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/bsv-wallet-helper) | +| helpers | `create-bsv-app` | `1.0.2` | cli | node | `>=22` | [packages/helpers/create-bsv-app](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/create-bsv-app) | +| messaging | `@bsv/authsocket` | `2.1.1` | node-library | node | `>=22` | [packages/messaging/authsocket](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/messaging/authsocket) | +| messaging | `@bsv/authsocket-client` | `2.1.1` | browser-library | browser, node, umd | `>=22` | [packages/messaging/authsocket-client](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/messaging/authsocket-client) | +| messaging | `@bsv/message-box-client` | `2.2.2` | dual-runtime-library | browser, node | `>=22` | [packages/messaging/message-box-client](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/messaging/message-box-client) | +| messaging | `@bsv/paymail` | `2.4.3` | dual-runtime-library | browser, node | `>=22` | [packages/messaging/ts-paymail](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/messaging/ts-paymail) | +| middleware | `@bsv/402-pay` | `0.2.1` | dual-runtime-library | browser, node | `>=22` | [packages/middleware/402-pay](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/middleware/402-pay) | +| middleware | `@bsv/auth` | `0.1.1` | node-library | node | `>=22` | [packages/middleware/auth](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/middleware/auth) | +| middleware | `@bsv/auth-express-middleware` | `2.1.3` | node-library | node | `>=22` | [packages/middleware/auth-express-middleware](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/middleware/auth-express-middleware) | +| middleware | `@bsv/payment-express-middleware` | `2.1.2` | node-library | node | `>=22` | [packages/middleware/payment-express-middleware](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/middleware/payment-express-middleware) | +| network | `@bsv/teranode-listener` | `1.1.1` | node-library | node | `>=22` | [packages/network/ts-p2p](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/network/ts-p2p) | +| overlays | `@bsv/gasp` | `1.3.1` | dual-runtime-library | browser, node | `>=22` | [packages/overlays/gasp-core](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/gasp-core) | +| overlays | `@bsv/overlay` | `2.2.1` | node-library | node | `>=22` | [packages/overlays/overlay](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/overlay) | +| overlays | `@bsv/overlay-discovery-services` | `2.1.1` | node-library | node | `>=22` | [packages/overlays/overlay-discovery-services](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/overlay-discovery-services) | +| overlays | `@bsv/overlay-express` | `2.4.3` | node-library | node | `>=22` | [packages/overlays/overlay-express](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/overlay-express) | +| overlays | `@bsv/overlay-topics` | `1.6.1` | node-library | node | `>=22` | [packages/overlays/topics](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/topics) | +| sdk | `@bsv/sdk` | `2.2.1` | browser-library | browser, node, umd | `>=22` | [packages/sdk](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/sdk) | +| sdk | `@bsv/verifast` | `0.3.0` | wasm-library | browser, node, wasm, worker | `>=22` | [packages/verifast](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/verifast) | +| wallet | `@bsv/btms` | `1.1.1` | node-library | node | `>=22` | [packages/wallet/btms](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/btms) | +| wallet | `@bsv/btms-permission-module` | `1.1.1` | node-library | node | `>=22` | [packages/wallet/btms-permission-module](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/btms-permission-module) | +| wallet | `@bsv/wallet-relay` | `0.2.3` | cli-library | node | `>=22` | [packages/wallet/ts-wallet-relay](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/ts-wallet-relay) | +| wallet | `@bsv/wallet-toolbox` | `2.4.5` | node-library | node | `>=22` | [packages/wallet/wallet-toolbox](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/wallet-toolbox) | +| wallet | `@bsv/wallet-toolbox-client` | `2.4.5` | browser-library | browser, node | `>=22` | [packages/wallet/wallet-toolbox/client](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/wallet-toolbox/client) | +| wallet | `@bsv/wallet-toolbox-mobile` | `2.4.5` | react-native-library | react-native | `>=22` | [packages/wallet/wallet-toolbox/mobile](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/wallet-toolbox/mobile) | + +## Standalone infrastructure manifests + +These versions identify the checked-in service manifests; production identity is +the separately released and verified image digest. + +| Service | Package | Manifest version | Node engine | Runtime targets | Release | Source | +| --- | --- | --- | --- | --- | --- | --- | +| BSV Chaintracks Server | `chaintracks-server` | `1.0.10` | `>=24 <25` | node, linux/amd64 | ghcr-keyless | [infra/chaintracks-server](https://github.com/bsv-blockchain/ts-stack/tree/main/infra/chaintracks-server) | +| BSV Message Box Server | `@bsv/messagebox-server` | `1.1.14` | `>=24 <25` | node, linux/amd64 | ghcr-keyless | [infra/message-box-server](https://github.com/bsv-blockchain/ts-stack/tree/main/infra/message-box-server) | +| BSV Overlay Server | `@bsv/overlay-express-examples` | `2.1.18` | `>=24 <25` | node, linux/amd64 | ghcr-keyless | [infra/overlay-server](https://github.com/bsv-blockchain/ts-stack/tree/main/infra/overlay-server) | +| BSV UHRP Basic Server | `@bsv/uhrp-lite` | `0.1.8` | `>=24 <25` | node, linux/amd64 | ghcr-keyless | [infra/uhrp-server-basic](https://github.com/bsv-blockchain/ts-stack/tree/main/infra/uhrp-server-basic) | +| BSV UHRP Cloud Bucket Server | `@bsv/uhrp-storage-server` | `0.2.10` | `>=24 <25` | node, linux/amd64 | ghcr-keyless | [infra/uhrp-server-cloud-bucket](https://github.com/bsv-blockchain/ts-stack/tree/main/infra/uhrp-server-cloud-bucket) | +| Wallet Authentication Backend | `@bsv/wab-server` | `1.4.11` | `>=24 <25` | node, linux/amd64 | ghcr-and-aws-marketplace-keyless | [infra/wab](https://github.com/bsv-blockchain/ts-stack/tree/main/infra/wab) | +| BSV Wallet Infrastructure | `@bsv/wallet-infra` | `2.0.13` | `>=24 <25` | node, linux/amd64 | ghcr-keyless | [infra/wallet-infra](https://github.com/bsv-blockchain/ts-stack/tree/main/infra/wallet-infra) | + +## Governed project and release inventory + +| Metric | Count | +| --- | --- | +| Governed projects | 37 | +| Package-area projects | 33 | +| Public npm packages | 30 | +| Private package-area projects | 3 | +| Standalone infrastructure projects | 7 | + +Public packages use the `npm-oidc` release route. Other workspace projects are +private packages or documentation/conformance tooling. Standalone infrastructure +components are governed separately by `governance/container-images.json` and use their +recorded container release route; they are not published by the public-package job. + +## Conformance corpus + +| Metric | Current value | +| --- | --- | +| Vector files | 74 | +| Vectors | 6650 | +| Structurally passed | 6439 | +| Governed skips | 211 | +| Required parity vectors | 6446 | +| Intended parity vectors | 204 | +| Explicitly skipped vector entries | 7 | +| Corpus metadata revision | 2026-07-27 | + +Structural runner pass/skip results and parity classifications answer different questions: +the former is the current runner outcome, while the latter records cross-language +implementation intent. Neither count may be silently presented as the other. + +## Change procedure + +1. Change source manifests or vector files. +2. Update the governed inventory or `conformance/META.json` when its declared facts change. +3. Run `pnpm docs:facts`. +4. Run `pnpm docs:facts:check`, `pnpm health:check`, and the relevant package, + conformance, documentation, and release checks. +5. Review generated diffs together with the source change. Do not hand-edit this page or + `conformance/PARITY_MATRIX.json`. + +See [Versioning Policy](../about/versioning.md), +[Dependency and Release Policy](./dependency-policy.md), and +[Conformance Testing](../conformance/index.md) for the operational meaning of these facts. diff --git a/docs/specs/index.md b/docs/specs/index.md index b4b41df99..7d44a7a32 100644 --- a/docs/specs/index.md +++ b/docs/specs/index.md @@ -4,7 +4,7 @@ title: Specifications kind: meta version: 'n/a' last_updated: '2026-04-28' -last_verified: '2026-04-28' +last_verified: '2026-07-27' review_cadence_days: 30 status: stable tags: ['specs'] diff --git a/governance/documentation-policy.json b/governance/documentation-policy.json new file mode 100644 index 000000000..5babbaf12 --- /dev/null +++ b/governance/documentation-policy.json @@ -0,0 +1,25 @@ +{ + "schemaVersion": 1, + "owner": "ts-stack-maintainers", + "lastReviewed": "2026-07-27", + "tracker": "https://github.com/bsv-blockchain/ts-stack/issues/324", + "publicPackageReadme": { + "requiredSections": ["installation", "usage", "license"], + "requiredLicenseFile": "LICENSE.txt", + "licenseName": "Open BSV License Version 6", + "rationale": "Every published package must let a registry consumer identify, install, exercise, and license the exact tarball without relying on monorepo-only context." + }, + "packageDocumentation": { + "requiredForEveryPublicPackage": true, + "repositoryAuthority": "https://github.com/bsv-blockchain/ts-stack/tree/main/", + "forbidSourceCommitSnapshots": true, + "privateProjectsAdvertiseNpm": false, + "rationale": "Every public package needs a current, discoverable package page; consolidated source links and generated versions prevent retired repositories or point-in-time commits from becoming current authority." + }, + "support": { + "contributors": "Use the root package.json engines and packageManager fields.", + "publicNodePackages": "Use each published package's engines.node field; the current common floor is Node.js 22.", + "browserAndMobile": "Node engines govern package tooling and Node consumers, not browser or device runtimes.", + "infrastructure": "Use each standalone service package.json and digest-pinned Dockerfile; the current service line is Node.js 24." + } +} diff --git a/governance/repository-health/baselines.json b/governance/repository-health/baselines.json index 436e8e01f..fac924474 100644 --- a/governance/repository-health/baselines.json +++ b/governance/repository-health/baselines.json @@ -284,24 +284,24 @@ "@bsv/authsocket": "2.1.1", "@bsv/authsocket-client": "2.1.1", "@bsv/message-box-client": "2.2.2", - "@bsv/paymail": "2.4.2", + "@bsv/paymail": "2.4.3", "@bsv/402-pay": "0.2.1", "@bsv/auth": "0.1.1", - "@bsv/auth-express-middleware": "2.1.2", - "@bsv/payment-express-middleware": "2.1.1", + "@bsv/auth-express-middleware": "2.1.3", + "@bsv/payment-express-middleware": "2.1.2", "@bsv/teranode-listener": "1.1.1", "@bsv/gasp": "1.3.1", "@bsv/overlay": "2.2.1", "@bsv/overlay-discovery-services": "2.1.1", - "@bsv/overlay-express": "2.4.2", + "@bsv/overlay-express": "2.4.3", "@bsv/overlay-topics": "1.6.1", - "@bsv/sdk": "2.2.0", + "@bsv/sdk": "2.2.1", "@bsv/verifast": "0.3.0", "@bsv/btms": "1.1.1", "@bsv/btms-permission-module": "1.1.1", - "@bsv/wallet-relay": "0.2.2", - "@bsv/wallet-toolbox-client": "2.4.4", - "@bsv/wallet-toolbox-mobile": "2.4.4", - "@bsv/wallet-toolbox": "2.4.4" + "@bsv/wallet-relay": "0.2.3", + "@bsv/wallet-toolbox-client": "2.4.5", + "@bsv/wallet-toolbox-mobile": "2.4.5", + "@bsv/wallet-toolbox": "2.4.5" } } diff --git a/governance/repository-health/exceptions.json b/governance/repository-health/exceptions.json index 6e7b04d18..aeecd8320 100644 --- a/governance/repository-health/exceptions.json +++ b/governance/repository-health/exceptions.json @@ -36,13 +36,14 @@ { "id": "scorecard-release-lockfile-refresh", "category": "toolchain", - "target": "OpenSSF Scorecard PinnedDependenciesID #200 for npm install --package-lock-only", + "target": "OpenSSF Scorecard PinnedDependenciesID #200 and re-fingerprinted duplicate #221 for npm install --package-lock-only", "owner": "ts-stack-maintainers", "reason": "The command installs no named or ad hoc package: it deterministically refreshes each committed infrastructure package-lock from that directory's committed package.json after first-party version synchronization, with lifecycle scripts disabled. Scorecard interprets the lockfile operation as an unpinned package invocation even though dependency resolution is committed and subsequently audited.", "evidence": [ ".github/workflows/release.yaml", "infra/*/package-lock.json", "https://github.com/bsv-blockchain/ts-stack/security/code-scanning/200", + "https://github.com/bsv-blockchain/ts-stack/security/code-scanning/221", "https://github.com/bsv-blockchain/ts-stack/issues/324" ], "created": "2026-07-25", diff --git a/governance/repository-health/projects.json b/governance/repository-health/projects.json index 855f976df..404a333d0 100644 --- a/governance/repository-health/projects.json +++ b/governance/repository-health/projects.json @@ -433,6 +433,7 @@ "profile": "dual-runtime-library", "criticality": "tier-1", "runtimeTargets": ["browser", "node"], + "declarationDependencies": ["@types/express"], "release": "npm-oidc" }, { @@ -473,6 +474,7 @@ "profile": "node-library", "criticality": "tier-1", "runtimeTargets": ["node"], + "declarationDependencies": ["@types/express"], "release": "npm-oidc" }, { @@ -483,6 +485,7 @@ "profile": "node-library", "criticality": "tier-1", "runtimeTargets": ["node"], + "declarationDependencies": ["@types/express"], "release": "npm-oidc" }, { @@ -543,6 +546,7 @@ "profile": "node-library", "criticality": "tier-1", "runtimeTargets": ["node"], + "declarationDependencies": ["@types/express"], "release": "npm-oidc" }, { @@ -603,6 +607,7 @@ "profile": "cli-library", "criticality": "tier-1", "runtimeTargets": ["node"], + "declarationDependencies": ["@types/express"], "release": "npm-oidc" }, { @@ -613,6 +618,7 @@ "profile": "node-library", "criticality": "tier-0", "runtimeTargets": ["node"], + "declarationDependencies": ["@types/express"], "release": "npm-oidc" }, { diff --git a/infra/overlay-server/README.md b/infra/overlay-server/README.md index bedbce89e..e6940d582 100644 --- a/infra/overlay-server/README.md +++ b/infra/overlay-server/README.md @@ -2,7 +2,7 @@ [![BSV License](https://img.shields.io/badge/license-Open%20BSV-blue)](#license) -A set of ready-to-run configuration examples for stand-alone Overlay nodes built with [`@bsv/overlay-express`](https://github.com/bsv-blockchain/overlay-express). Use these examples to spin-up your own overlay infrastructure for distributed applications on Bitcoin SV. +A set of ready-to-run configuration examples for stand-alone Overlay nodes built with [`@bsv/overlay-express`](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays/overlay-express). Use these examples to spin-up your own overlay infrastructure for distributed applications on Bitcoin SV. --- diff --git a/infra/wallet-infra/README.md b/infra/wallet-infra/README.md index 8fdaec305..363eae0b5 100644 --- a/infra/wallet-infra/README.md +++ b/infra/wallet-infra/README.md @@ -2,7 +2,7 @@ This repository serves as a reference implementation for building and deploying BSV Wallet Infrastructure. It contains the configuration and code necessary to build and run a wallet storage server (also referred to as a “UTXO Management Server”). The server securely stores and manages UTXOs, providing a reliable backend for BSV wallet clients, all while never accessing user-held keys. -Built on the [wallet-toolbox](https://github.com/bsv-blockchain/wallet-toolbox), this implementation empowers developers with extensive customization options for authentication, monetization, and database management to name a few. +Built on the [wallet-toolbox](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/wallet/wallet-toolbox), this implementation empowers developers with extensive customization options for authentication, monetization, and database management to name a few. ## Key Features diff --git a/infra/wallet-infra/guides/gcloud_deployment.md b/infra/wallet-infra/guides/gcloud_deployment.md index cb4ca5a55..36c6fc9ae 100644 --- a/infra/wallet-infra/guides/gcloud_deployment.md +++ b/infra/wallet-infra/guides/gcloud_deployment.md @@ -18,26 +18,10 @@ For production or cloud usage, we recommend deploying the Docker container to Go ## 1. Prepare the Dockerfile -This repository includes a sample Dockerfile: - -```dockerfile -FROM node:20-alpine - -# Install nginx (optional) -RUN apk add --no-cache --update nginx && \ - chown -R nginx:www-data /var/lib/nginx - -COPY ./nginx.conf /etc/nginx/nginx.conf -EXPOSE 8080 - -WORKDIR /app -COPY . . -RUN npm i knex -g && \ - npm run build - -# By default, node out/src/index.js. It will conditionally run Nginx if NODE_ENV != development -CMD [ "node", "out/src/index.js"] -``` +Use the repository's checked-in Dockerfile. It uses the governed digest-pinned +Node 24 base, a committed lockfile, an unprivileged runtime user, and the same +image contract scanned by CI. Do not replace it with an unpinned +`node:-alpine` example or install global build tools during a release. Note: If you prefer to skip Nginx in production, you can remove the `RUN apk add ...` line and any references to `nginx`. By default, `index.ts` spawns Nginx only if `NODE_ENV !== 'development'`. @@ -54,11 +38,12 @@ Otherwise, create a new instance: gcloud sql instances create my-wallet-sql-instance \ --database-version=MYSQL_8_0 \ --tier=db-f1-micro \ - --region=us-west1 \ - --authorized-networks=0.0.0.0/0 + --region=us-west1 ``` -Configuring `authorized-networks` like this allows all traffic by default. (This may not be recommended for production, so adjust accordingly.) +Use a private IP or the Cloud SQL connector from Cloud Run. If a public IP is +unavoidable, authorize only the narrow, known egress range and require TLS; +never expose the database to `0.0.0.0/0`. Adjust parameters (machine type, region) as needed. Then set a root password: @@ -323,4 +308,4 @@ You now have a **production-ready** UTXO Management Server running on Cloud Run - Check the [Cloud SQL MySQL docs](https://cloud.google.com/sql/docs/mysql) and [Cloud Run docs](https://cloud.google.com/run/docs). - Review and tweak environment variables, server code, or Nginx configurations as desired. -Enjoy building on the BSV Blockchain with a robust wallet infrastructure! \ No newline at end of file +Enjoy building on the BSV Blockchain with a robust wallet infrastructure! diff --git a/infra/wallet-infra/guides/local_development.md b/infra/wallet-infra/guides/local_development.md index 7b92b263a..e6832b8cb 100644 --- a/infra/wallet-infra/guides/local_development.md +++ b/infra/wallet-infra/guides/local_development.md @@ -8,7 +8,7 @@ This guide explains how to run the UTXO Management Server **locally** using **Do ### Requirements - **Docker** installed (v20+ recommended) -- **Node.js** installed if you plan to run `npm install` locally (v18+ recommended) +- **Node.js 24.11 or newer** if you plan to run `npm ci` locally - **Git** for code management (optional but typical) ### Steps @@ -21,7 +21,7 @@ This guide explains how to run the UTXO Management Server **locally** using **Do 2. **Install and build local dependencies** (optional but helpful if you intend to run build steps outside Docker): ```bash - npm install + npm ci npm run build ``` diff --git a/package.json b/package.json index 5134d8749..fa4611c2e 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "check-versions": "node scripts/check-versions.mjs", "typescript:check": "node scripts/typescript-toolchain.mjs", "health:baseline": "node scripts/repository-health.mjs --update-contract-baseline", - "health:check": "node --test scripts/*.test.mjs && node scripts/typescript-toolchain.mjs && node scripts/package-license-policy.mjs && node scripts/sync-service-rate-limit-policy.mjs --check && node scripts/sync-service-edge-policy.mjs --check && node scripts/repository-health.mjs", + "health:check": "node --test scripts/*.test.mjs && pnpm docs:facts:check && node scripts/typescript-toolchain.mjs && node scripts/package-license-policy.mjs && node scripts/sync-service-rate-limit-policy.mjs --check && node scripts/sync-service-edge-policy.mjs --check && node scripts/repository-health.mjs", "health:report": "node scripts/repository-health.mjs --format markdown", "test:governance": "node scripts/test-governance.mjs", "build:property": "pnpm -r --filter '!@bsv/ts-stack' --filter '!docs-site' --filter '!example-paymail' run build", @@ -30,9 +30,12 @@ "codegen": "node scripts/generate-openapi-types.mjs", "codegen:check": "node scripts/generate-openapi-types.mjs --check", "conformance": "node conformance/runner/src/runner.js", + "docs:facts": "node scripts/generate-parity-matrix.mjs && node scripts/generate-stack-facts.mjs", + "docs:facts:check": "node scripts/generate-parity-matrix.mjs --check && node scripts/generate-stack-facts.mjs --check && node scripts/documentation-policy.mjs", + "docs:examples": "node scripts/check-documentation-examples.mjs", "docs:asyncapi": "node scripts/generate-asyncapi-html.mjs", "docs:dev": "pnpm --filter docs-site dev", - "docs:build": "pnpm --filter docs-site build", + "docs:build": "pnpm docs:facts:check && pnpm --filter docs-site build", "docs:preview": "pnpm --filter docs-site preview" }, "devDependencies": { diff --git a/packages/helpers/bsv-wallet-helper/README.md b/packages/helpers/bsv-wallet-helper/README.md index b067bba2f..d4f0cf9ca 100644 --- a/packages/helpers/bsv-wallet-helper/README.md +++ b/packages/helpers/bsv-wallet-helper/README.md @@ -175,7 +175,7 @@ await new TransactionBuilder(buyerWallet, 'Purchase listing') 📖 See the OrdLock section in **[TransactionBuilder documentation](./docs/Transaction-builder.md)** for the mechanics and required output ordering. -**Note:** For wallet compatible multisig scripts see 'https://github.com/bsv-blockchain/ts-templates'. +**Note:** For wallet-compatible multisig scripts, see [`@bsv/templates`](https://github.com/bsv-blockchain/ts-stack/tree/main/packages/helpers/ts-templates). ### Types diff --git a/packages/helpers/create-bsv-app/README.md b/packages/helpers/create-bsv-app/README.md index 26b74ff2d..0e8f7b280 100644 --- a/packages/helpers/create-bsv-app/README.md +++ b/packages/helpers/create-bsv-app/README.md @@ -247,3 +247,7 @@ pnpm --filter create-bsv-app build ``` The package is maintained in the [`bsv-blockchain/ts-stack`](https://github.com/bsv-blockchain/ts-stack) monorepo. The former `@bsv/app` package exists only as a deprecation redirect to this CLI. + +## License + +Open BSV License Version 6. See [LICENSE.txt](./LICENSE.txt). diff --git a/packages/helpers/did/README.md b/packages/helpers/did/README.md index d785c6eed..df0e6fc61 100644 --- a/packages/helpers/did/README.md +++ b/packages/helpers/did/README.md @@ -113,3 +113,7 @@ If the issuer is a `did:key`, the verifier can derive the issuer public key from - `SdJwtVcVerifier` - `publicKeyToJwk`, `privateKeyToJwk`, `jwkToPublicKey` - `parseSdJwt`, `serializeSdJwt`, `parseDisclosure`, `disclosureDigest` + +## License + +Open BSV License Version 6. See [LICENSE.txt](./LICENSE.txt). diff --git a/packages/helpers/simple/README.md b/packages/helpers/simple/README.md index 4cf312d25..ca8e4e13c 100644 --- a/packages/helpers/simple/README.md +++ b/packages/helpers/simple/README.md @@ -2,6 +2,16 @@ A high-level TypeScript library that makes BSV blockchain development simple. Build wallets, send payments, create tokens, issue credentials, and more — in just a few lines of code. +## Install + +```bash +npm install @bsv/simple @bsv/sdk +``` + +Use the browser-safe default entry point in frontend applications and +`@bsv/simple/server` only in Node.js server code. See the +[installation guide](docs/installation.md) for framework-specific setup. + ## What is @bsv/simple? `@bsv/simple` wraps the low-level `@bsv/sdk` into a clean, modular API. Instead of manually constructing locking scripts, managing key derivation, and handling transaction internalization, you call methods like `wallet.pay()`, `wallet.createToken()`, and `wallet.inscribeText()`. @@ -57,3 +67,7 @@ const did = wallet.getDID() - [Quick Start](docs/quick-start.md) — Get running in 5 minutes - [Installation](docs/installation.md) — Detailed setup instructions - [Architecture](docs/architecture.md) — How the library is built + +## License + +Open BSV License Version 6. See [LICENSE.txt](./LICENSE.txt). diff --git a/packages/messaging/ts-paymail/CHANGELOG.md b/packages/messaging/ts-paymail/CHANGELOG.md index a48f80e1a..87da07229 100644 --- a/packages/messaging/ts-paymail/CHANGELOG.md +++ b/packages/messaging/ts-paymail/CHANGELOG.md @@ -15,7 +15,8 @@ All notable changes to this project will be documented in this file. The format - (Include new features or significant user-visible enhancements here.) ### Changed -- (Detail modifications that are non-breaking but relevant to the end-users.) +- Ship the Express declaration dependency needed by strict TypeScript + consumers of the Paymail router API. ### Deprecated - (List features that are in the process of being phased out or replaced.) @@ -85,4 +86,4 @@ Replace `X.X.X` with the new version number and `YYYY-MM-DD` with the release da - ``` -Use this template as the starting point for each new version. Always update the "Unreleased" section with changes as they're implemented, and then move them under the new version header when that version is released. \ No newline at end of file +Use this template as the starting point for each new version. Always update the "Unreleased" section with changes as they're implemented, and then move them under the new version header when that version is released. diff --git a/packages/messaging/ts-paymail/package.json b/packages/messaging/ts-paymail/package.json index 50f93ce9d..ac1ec80e9 100644 --- a/packages/messaging/ts-paymail/package.json +++ b/packages/messaging/ts-paymail/package.json @@ -1,6 +1,6 @@ { "name": "@bsv/paymail", - "version": "2.4.2", + "version": "2.4.3", "sideEffects": false, "engines": { "node": ">=22" @@ -186,6 +186,7 @@ "Paymail" ], "dependencies": { + "@types/express": "^5.0.6", "cross-fetch": "^4.1.0", "express": "^5.2.1", "joi": "^18.2.3" @@ -193,7 +194,6 @@ "devDependencies": { "@bsv/sdk": "workspace:^", "@jest/globals": "^30.4.1", - "@types/express": "^5.0.6", "@types/jest": "^30.0.0", "@types/node": "^26.1.1", "@types/supertest": "^7.2.1", diff --git a/packages/middleware/auth-express-middleware/BASELINE.md b/packages/middleware/auth-express-middleware/BASELINE.md index 203603e07..c9860dda1 100644 --- a/packages/middleware/auth-express-middleware/BASELINE.md +++ b/packages/middleware/auth-express-middleware/BASELINE.md @@ -1,6 +1,6 @@ # BASELINE — @bsv/auth-express-middleware -> Verified: 2026-07-26. This is the source baseline; npm remains at the version +> Verified: 2026-07-27. This is the source baseline; npm remains at the version > shown until an explicit release is approved. ## Identity @@ -9,23 +9,23 @@ | -------------- | --------------------------------------------- | | Package | `@bsv/auth-express-middleware` | | Path | `packages/middleware/auth-express-middleware` | -| Source version | `2.1.2` | +| Source version | `2.1.3` | | Criticality | Tier 1 — service authentication boundary | | Runtime | Node.js 22+ | | Formats | Native ESM + CommonJS + declarations | ## Verified gates -| Gate | Result | -| ------------------- | ------------------------------------------------------------------------------------ | -| Strict typecheck | Passing | -| Oxlint | Passing with zero warnings | -| Prettier check | Passing | -| Deterministic tests | 97 passing across 5 suites | -| Production coverage | 93.39% lines, 89.31% branches, 88.88% functions, 92.60% statements | -| Coverage floor | 85% lines/statements/functions; 80% branches | -| Build | `tsdown` passing | -| Artifact | Exact tarball validated for ESM, CommonJS, declarations, exports, and file allowlist | +| Gate | Result | +| ------------------- | ------------------------------------------------------------------------------------------------------------------ | +| Strict typecheck | Passing | +| Oxlint | Passing with zero warnings | +| Prettier check | Passing | +| Deterministic tests | 97 passing across 5 suites | +| Production coverage | 93.39% lines, 89.31% branches, 88.88% functions, 92.60% statements | +| Coverage floor | 85% lines/statements/functions; 80% branches | +| Build | `tsdown` passing | +| Artifact | Exact tarball and workspace runtime closure validated for ESM, CommonJS, declarations, exports, and file allowlist | ## Reliability and security controls diff --git a/packages/middleware/auth-express-middleware/package.json b/packages/middleware/auth-express-middleware/package.json index 579e1b90e..bba5481de 100644 --- a/packages/middleware/auth-express-middleware/package.json +++ b/packages/middleware/auth-express-middleware/package.json @@ -1,6 +1,6 @@ { "name": "@bsv/auth-express-middleware", - "version": "2.1.2", + "version": "2.1.3", "sideEffects": false, "engines": { "node": ">=22" @@ -66,7 +66,6 @@ "devDependencies": { "@bsv/sdk": "workspace:^", "@types/body-parser": "^1.19.6", - "@types/express": "^5.0.6", "@types/jest": "^30.0.0", "@types/mime-types": "^3.0.1", "@types/node": "^26.1.1", @@ -80,6 +79,7 @@ "typescript": "npm:@typescript/typescript6@6.0.2" }, "dependencies": { + "@types/express": "^5.0.6", "express": "^5.2.1", "mime-types": "^3.0.2" }, diff --git a/packages/middleware/auth/README.md b/packages/middleware/auth/README.md index 7c08238f1..a17997b83 100644 --- a/packages/middleware/auth/README.md +++ b/packages/middleware/auth/README.md @@ -82,3 +82,7 @@ See [`docs/usage.md`](./docs/usage.md) for fuller examples. may only contain letters, numbers, and spaces. - Replay is bounded to the validity window by the expiry, and fully closed by `consumeNonce` — keep records only until `expiresAt`. + +## License + +Open BSV License Version 6. See [LICENSE.txt](./LICENSE.txt). diff --git a/packages/middleware/payment-express-middleware/BASELINE.md b/packages/middleware/payment-express-middleware/BASELINE.md index 0bb7e121a..8e7892924 100644 --- a/packages/middleware/payment-express-middleware/BASELINE.md +++ b/packages/middleware/payment-express-middleware/BASELINE.md @@ -1,6 +1,6 @@ # BASELINE — @bsv/payment-express-middleware -> Verified: 2026-07-26. This is the source baseline; npm remains at the version +> Verified: 2026-07-27. This is the source baseline; npm remains at the version > shown until an explicit release is approved. ## Identity @@ -9,7 +9,7 @@ | -------------- | ------------------------------------------------------------------------------------ | | Package | `@bsv/payment-express-middleware` | | Path | `packages/middleware/payment-express-middleware` | -| Source version | `2.1.1` | +| Source version | `2.1.2` | | Criticality | Tier 1 — payment authorization boundary | | Runtime | Node.js 22+ | | Formats | Native ESM + CommonJS + declarations | @@ -17,16 +17,16 @@ ## Verified gates -| Gate | Result | -| ------------------- | ------------------------------------------------------------------------------------ | -| Strict typecheck | Passing | -| Oxlint | Passing with zero warnings | -| Prettier check | Passing | -| Deterministic tests | 37 passing in 1 suite; no public-network calls | -| Production coverage | 98.50% lines, 98.13% branches, 100% functions, 97.90% statements | -| Coverage floor | 85% lines/statements/functions; 80% branches | -| Build | `tsdown` passing | -| Artifact | Exact tarball validated for ESM, CommonJS, declarations, exports, and file allowlist | +| Gate | Result | +| ------------------- | ------------------------------------------------------------------------------------------------------------------ | +| Strict typecheck | Passing | +| Oxlint | Passing with zero warnings | +| Prettier check | Passing | +| Deterministic tests | 37 passing in 1 suite; no public-network calls | +| Production coverage | 98.50% lines, 98.13% branches, 100% functions, 97.90% statements | +| Coverage floor | 85% lines/statements/functions; 80% branches | +| Build | `tsdown` passing | +| Artifact | Exact tarball and workspace runtime closure validated for ESM, CommonJS, declarations, exports, and file allowlist | ## Reliability and security controls diff --git a/packages/middleware/payment-express-middleware/package.json b/packages/middleware/payment-express-middleware/package.json index 5fa2cc23e..9b1eb05d6 100644 --- a/packages/middleware/payment-express-middleware/package.json +++ b/packages/middleware/payment-express-middleware/package.json @@ -1,6 +1,6 @@ { "name": "@bsv/payment-express-middleware", - "version": "2.1.1", + "version": "2.1.2", "sideEffects": false, "engines": { "node": ">=22" @@ -63,7 +63,6 @@ "@bsv/auth-express-middleware": "workspace:^", "@bsv/sdk": "workspace:^", "@types/body-parser": "^1.19.6", - "@types/express": "^5.0.6", "@types/jest": "^30.0.0", "@types/node": "^26.1.1", "fast-check": "^4.9.0", @@ -76,6 +75,7 @@ "typescript": "npm:@typescript/typescript6@6.0.2" }, "dependencies": { + "@types/express": "^5.0.6", "express": "^5.2.1" }, "bugs": { diff --git a/packages/overlays/gasp-core/README.md b/packages/overlays/gasp-core/README.md index f526312ea..d6a744729 100644 --- a/packages/overlays/gasp-core/README.md +++ b/packages/overlays/gasp-core/README.md @@ -303,4 +303,4 @@ or publish. ## License -The license for the code in this repository is the Open BSV License. +Open BSV License Version 6. See [LICENSE.txt](./LICENSE.txt). diff --git a/packages/overlays/overlay-express/CHANGELOG.md b/packages/overlays/overlay-express/CHANGELOG.md index 335fe3340..539258679 100644 --- a/packages/overlays/overlay-express/CHANGELOG.md +++ b/packages/overlays/overlay-express/CHANGELOG.md @@ -22,6 +22,8 @@ All notable changes to this project will be documented in this file. The format Origin-bearing calls. - Verbose request logging records redacted headers and body size/type metadata instead of request bodies. +- Ship the Express declaration dependency required to typecheck the packed + server API in a clean TypeScript consumer. ### Deprecated - (List features that are in the process of being phased out or replaced.) diff --git a/packages/overlays/overlay-express/package.json b/packages/overlays/overlay-express/package.json index 43b96aebb..4a824ed69 100644 --- a/packages/overlays/overlay-express/package.json +++ b/packages/overlays/overlay-express/package.json @@ -1,6 +1,6 @@ { "name": "@bsv/overlay-express", - "version": "2.4.2", + "version": "2.4.3", "sideEffects": false, "engines": { "node": ">=22" @@ -50,7 +50,7 @@ "format:check": "pnpm --workspace-root exec prettier --check \"packages/overlays/overlay-express/{README.md,jest.config.js,mod.ts,package.json,tsconfig*.json}\"", "lint": "oxlint mod.ts src jest.config.js --deny-warnings", "lint:ci": "pnpm lint", - "pack:check": "pnpm --filter @bsv/overlay build && pnpm --filter @bsv/overlay-discovery-services build && pnpm build && node ../../../scripts/check-package-artifact.mjs . --local-consumer-dependencies ../overlay,../overlay-discovery-services --exports ArcadeProvider,BanAwareLookupWrapper,BanAwareSHIPStorage,BanAwareSLAPStorage,BanAwareTopicManager,BanService,ChaintracksProvider,JanitorService,OverlayMonitor,ProviderChainBroadcaster,analyzeOverlayAnchorTip,analyzeOverlayLookupResponse,default,isTerminalArcStatus", + "pack:check": "pnpm --filter @bsv/overlay build && pnpm --filter @bsv/overlay-discovery-services build && pnpm build && node ../../../scripts/check-package-artifact.mjs . --exports ArcadeProvider,BanAwareLookupWrapper,BanAwareSHIPStorage,BanAwareSLAPStorage,BanAwareTopicManager,BanService,ChaintracksProvider,JanitorService,OverlayMonitor,ProviderChainBroadcaster,analyzeOverlayAnchorTip,analyzeOverlayLookupResponse,default,isTerminalArcStatus", "typecheck": "tsc --project tsconfig.base.json --noEmit --incremental false", "build": "tsc -b && tsconfig-to-dual-package tsconfig.cjs.json", "dev": "tsc -b -w", @@ -80,7 +80,6 @@ "@bsv/sdk": "workspace:^", "@jest/globals": "^30.4.1", "@types/body-parser": "^1.19.6", - "@types/express": "^5.0.6", "@types/jest": "^30.0.0", "@types/node": "^26.1.1", "fast-check": "^4.9.0", @@ -97,6 +96,7 @@ "@bsv/overlay": "workspace:^", "@bsv/overlay-discovery-services": "workspace:^", "@bsv/wallet-toolbox-client": "workspace:^", + "@types/express": "^5.0.6", "body-parser": "^2.3.0", "chalk": "^5.6.2", "express": "^5.2.1", diff --git a/packages/overlays/overlay-express/src/__tests__/makeUserInterface.test.ts b/packages/overlays/overlay-express/src/__tests__/makeUserInterface.test.ts index a96532b7e..96d456670 100644 --- a/packages/overlays/overlay-express/src/__tests__/makeUserInterface.test.ts +++ b/packages/overlays/overlay-express/src/__tests__/makeUserInterface.test.ts @@ -34,7 +34,9 @@ describe('makeUserInterface', () => { it('should include external links', () => { const html = makeUserInterface() - expect(html).toContain('https://github.com/bsv-blockchain/overlay-services') + expect(html).toContain( + 'https://github.com/bsv-blockchain/ts-stack/tree/main/packages/overlays' + ) expect(html).toContain('https://bsv.brc.dev/transactions/0076') expect(html).toContain('https://fast.brc.dev') }) @@ -60,7 +62,7 @@ describe('makeUserInterface', () => { const html = makeUserInterface(config) expect(html).toContain('https://example.com/favicon.ico') - expect(html).toContain('const faviconUrl = \'https://example.com/favicon.ico\'') + expect(html).toContain("const faviconUrl = 'https://example.com/favicon.ico'") }) it('should use custom colors', () => { diff --git a/packages/overlays/overlay-express/src/makeUserInterface.ts b/packages/overlays/overlay-express/src/makeUserInterface.ts index 1e13eecba..6b99e1b51 100644 --- a/packages/overlays/overlay-express/src/makeUserInterface.ts +++ b/packages/overlays/overlay-express/src/makeUserInterface.ts @@ -1191,7 +1191,7 @@ export default (config: UIConfig = {}): string => {

External Links

diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index 517f4ebac..266f518b5 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -240,6 +240,9 @@ All notable changes to this project will be documented in this file. The format compact-byte substrate avoids redundant response writers and aggregate copies while the legacy `number[]` transport and every BRC-100 shape remain unchanged. +- Declare `WindowCWISubstrate` signing and certificate methods with the + canonical BRC-100 argument and result types, so strict packed-package + consumers receive the same contract that the implementation delegates to. - Remove arbitrary post-Genesis script element and default interpreter-memory caps; explicit caller budgets remain enforceable but are not reported as invalid scripts. diff --git a/packages/sdk/mkdocs.yml b/packages/sdk/mkdocs.yml index 46a4d9ccb..c28e5dc5a 100644 --- a/packages/sdk/mkdocs.yml +++ b/packages/sdk/mkdocs.yml @@ -1,7 +1,7 @@ site_name: BSV TypeScript SDK site_description: TypeScript SDK for Bitcoin SV site_url: https://bsv-blockchain.github.io/ts-sdk/ -repo_url: https://github.com/bsv-blockchain/ts-sdk +repo_url: https://github.com/bsv-blockchain/ts-stack repo_name: bsv-blockchain/ts-sdk theme: diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 655485d75..736e5a675 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@bsv/sdk", - "version": "2.2.0", + "version": "2.2.1", "sideEffects": false, "engines": { "node": ">=22" diff --git a/packages/sdk/src/wallet/substrates/window.CWI.ts b/packages/sdk/src/wallet/substrates/window.CWI.ts index 069609657..d434a13b5 100644 --- a/packages/sdk/src/wallet/substrates/window.CWI.ts +++ b/packages/sdk/src/wallet/substrates/window.CWI.ts @@ -1,4 +1,5 @@ import { + AcquireCertificateArgs, Base64String, BasketStringUnder300Bytes, BEEF, @@ -22,10 +23,15 @@ import { PositiveIntegerOrZero, ProtocolString5To400Bytes, PubKeyHex, + ProveCertificateArgs, + ProveCertificateResult, SatoshiValue, SecurityLevel, + SignActionArgs, + SignActionResult, TXIDHexString, VersionString7To30Bytes, + WalletCertificate, WalletInterface } from '../Wallet.interfaces.js' @@ -100,30 +106,9 @@ export default class WindowCWISubstrate implements WalletInterface { } async signAction( - args: { - spends: Record< - PositiveIntegerOrZero, - { unlockingScript: HexString, sequenceNumber?: PositiveIntegerOrZero } - > - reference: Base64String - options?: { - acceptDelayedBroadcast?: BooleanDefaultTrue - returnTXIDOnly?: BooleanDefaultFalse - noSend?: BooleanDefaultFalse - noSendChange?: OutpointString[] - sendWith: TXIDHexString[] - } - }, + args: SignActionArgs, originator?: OriginatorDomainNameStringUnder250Bytes - ): Promise<{ - txid?: TXIDHexString - tx?: BEEF - noSendChange?: OutpointString[] - sendWithResults?: Array<{ - txid: TXIDHexString - status: 'unproven' | 'sending' | 'failed' - }> - }> { + ): Promise { return await this.CWI.signAction(args, originator) } @@ -398,29 +383,9 @@ export default class WindowCWISubstrate implements WalletInterface { } async acquireCertificate( - args: { - type: Base64String - subject: PubKeyHex - serialNumber: Base64String - revocationOutpoint: OutpointString - signature: HexString - fields: Record - certifier: PubKeyHex - keyringRevealer: PubKeyHex - keyringForSubject: Record - acquisitionProtocol: 'direct' | 'issuance' - certifierUrl?: string - }, + args: AcquireCertificateArgs, originator?: OriginatorDomainNameStringUnder250Bytes - ): Promise<{ - type: Base64String - subject: PubKeyHex - serialNumber: Base64String - certifier: PubKeyHex - revocationOutpoint: OutpointString - signature: HexString - fields: Record - }> { + ): Promise { return await this.CWI.acquireCertificate(args, originator) } @@ -450,25 +415,9 @@ export default class WindowCWISubstrate implements WalletInterface { } async proveCertificate( - args: { - certificate: { - type: Base64String - subject: PubKeyHex - serialNumber: Base64String - certifier: PubKeyHex - revocationOutpoint: OutpointString - signature: HexString - fields: Record - } - fieldsToReveal: CertificateFieldNameUnder50Bytes[] - verifier: PubKeyHex - privileged?: BooleanDefaultFalse - privilegedReason?: DescriptionString5to50Bytes - }, + args: ProveCertificateArgs, originator?: OriginatorDomainNameStringUnder250Bytes - ): Promise<{ - keyringForVerifier: Record - }> { + ): Promise { return await this.CWI.proveCertificate(args, originator) } diff --git a/packages/verifast/README.md b/packages/verifast/README.md index ab9edcf09..e7e3c4785 100644 --- a/packages/verifast/README.md +++ b/packages/verifast/README.md @@ -3,6 +3,15 @@ Real BSV BDK script verification in WebAssembly for `@bsv/sdk`. One package supports Node ESM, CommonJS, browser/worker ESM, and classic-script/UMD clients. +## Install + +```bash +npm install @bsv/verifast @bsv/sdk +``` + +The package includes its validated WASM assets. No native compiler or +post-install build is required for consumers. + ## Transaction verification The validated WASM module is bundled and loaded lazily. Keep one verifier for a @@ -245,3 +254,7 @@ to 12.1 ms in one WASM instance and 3.34 ms across four warm workers. A real 250-transaction dependent graph verified 3.61x faster across four workers. Typed and cached serialization materially improves large-EF workloads. See `bench/results/` for commands, environment, hashes, and full measurements. + +## License + +Open BSV License Version 6. See [LICENSE.txt](./LICENSE.txt). diff --git a/packages/wallet/ts-wallet-relay/README.md b/packages/wallet/ts-wallet-relay/README.md index 387af6fc7..488eeb38c 100644 --- a/packages/wallet/ts-wallet-relay/README.md +++ b/packages/wallet/ts-wallet-relay/README.md @@ -549,3 +549,7 @@ only by the repository release workflow. ## API reference See [API.md](./API.md) for full parameter and method documentation. + +## License + +Open BSV License Version 6. See [LICENSE.txt](./LICENSE.txt). diff --git a/packages/wallet/ts-wallet-relay/package.json b/packages/wallet/ts-wallet-relay/package.json index 0c32cd4cc..a76cf00a0 100644 --- a/packages/wallet/ts-wallet-relay/package.json +++ b/packages/wallet/ts-wallet-relay/package.json @@ -1,6 +1,6 @@ { "name": "@bsv/wallet-relay", - "version": "0.2.2", + "version": "0.2.3", "sideEffects": false, "engines": { "node": ">=22" @@ -102,7 +102,6 @@ "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "^7.0.0", "@testing-library/react": "^16.3.2", - "@types/express": "^5.0.6", "@types/jest": "^30.0.0", "@types/node": "^26.1.1", "@types/qrcode": "^1.5.6", @@ -122,6 +121,7 @@ "oxlint": "^1.75.0" }, "dependencies": { + "@types/express": "^5.0.6", "ws": "^8.21.1" }, "repository": { diff --git a/packages/wallet/wallet-toolbox/CHANGELOG.md b/packages/wallet/wallet-toolbox/CHANGELOG.md index 2776d678b..8be19c115 100644 --- a/packages/wallet/wallet-toolbox/CHANGELOG.md +++ b/packages/wallet/wallet-toolbox/CHANGELOG.md @@ -6,6 +6,10 @@ attention to changes that materially alter behavior or extend functionality. ## wallet-toolbox (unreleased) +- Ship the Express declaration dependency required by the public storage + server, edge-policy, and rate-limit declarations. Validate authenticated + storage identities explicitly and normalize multi-value Express 5 headers + instead of relying on implicit request augmentation or scalar headers. - Add capability-negotiated action-batch manifest format 2 without changing BRC-100. It derives source/output scripts from the authenticated transaction graph, retains only the external proof frontier, bulk-loads shared storage diff --git a/packages/wallet/wallet-toolbox/client/package.json b/packages/wallet/wallet-toolbox/client/package.json index b48214f19..2da340fc6 100644 --- a/packages/wallet/wallet-toolbox/client/package.json +++ b/packages/wallet/wallet-toolbox/client/package.json @@ -1,6 +1,6 @@ { "name": "@bsv/wallet-toolbox-client", - "version": "2.4.4", + "version": "2.4.5", "type": "module", "sideEffects": false, "engines": { diff --git a/packages/wallet/wallet-toolbox/mobile/package.json b/packages/wallet/wallet-toolbox/mobile/package.json index 3772ec324..ee4d6db60 100644 --- a/packages/wallet/wallet-toolbox/mobile/package.json +++ b/packages/wallet/wallet-toolbox/mobile/package.json @@ -1,6 +1,6 @@ { "name": "@bsv/wallet-toolbox-mobile", - "version": "2.4.4", + "version": "2.4.5", "type": "module", "sideEffects": false, "engines": { diff --git a/packages/wallet/wallet-toolbox/package.json b/packages/wallet/wallet-toolbox/package.json index c0e0ae108..574f3f3a9 100644 --- a/packages/wallet/wallet-toolbox/package.json +++ b/packages/wallet/wallet-toolbox/package.json @@ -1,6 +1,6 @@ { "name": "@bsv/wallet-toolbox", - "version": "2.4.4", + "version": "2.4.5", "sideEffects": false, "type": "commonjs", "engines": { @@ -74,6 +74,7 @@ "dependencies": { "@bsv/auth-express-middleware": "workspace:^", "@bsv/payment-express-middleware": "workspace:^", + "@types/express": "^5.0.6", "better-sqlite3": "^13.0.1", "body-parser": "^2.3.0", "dotenv": "^17.4.2", diff --git a/packages/wallet/wallet-toolbox/src/storage/remoting/StorageServer.ts b/packages/wallet/wallet-toolbox/src/storage/remoting/StorageServer.ts index a6f90fde0..7911c3628 100644 --- a/packages/wallet/wallet-toolbox/src/storage/remoting/StorageServer.ts +++ b/packages/wallet/wallet-toolbox/src/storage/remoting/StorageServer.ts @@ -7,7 +7,11 @@ import { MakeWalletLogger, WalletInterface, WalletLoggerInterface } from '@bsv/sdk' import express, { Request, Response } from 'express' -import { AuthMiddlewareOptions, createAuthMiddleware } from '@bsv/auth-express-middleware' +import { + AuthMiddlewareOptions, + AuthRequest, + createAuthMiddleware +} from '@bsv/auth-express-middleware' import { createPaymentMiddleware } from '@bsv/payment-express-middleware' import { Options as RateLimitOptions, rateLimit } from 'express-rate-limit' import { Wallet } from '../../Wallet' @@ -124,6 +128,23 @@ interface RpcDispatchResult { result?: unknown } +function requiredAuthenticatedIdentityKey (req: Request): string { + const identityKey = (req as AuthRequest).auth?.identityKey + if ( + typeof identityKey !== 'string' || + identityKey.trim() === '' || + identityKey === 'unknown' + ) { + throw new WERR_UNAUTHORIZED('authenticated request identity is required') + } + return identityKey +} + +function firstRequestHeader (req: Request, name: string): string | undefined { + const value = req.headers[name.toLowerCase()] + return Array.isArray(value) ? value[0] : value +} + export interface WalletStorageServerOptions { port: number wallet: Wallet @@ -231,9 +252,7 @@ export class StorageServer { ip: req.ip || req.socket.remoteAddress, ua: req.headers['user-agent'] || '-' } - const traceContext = (req.headers['X-Cloud-Trace-Context'] || req.headers['x-cloud-trace-context'])?.split( - '/' - )[0] + const traceContext = firstRequestHeader(req, 'X-Cloud-Trace-Context')?.split('/')[0] if (traceContext) { logObj['logging.googleapis.com/trace'] = `projects/computing-with-integrity/traces/${traceContext}` } // Request bodies and BSV auth/payment headers can contain sensitive @@ -443,10 +462,10 @@ export class StorageServer { source: 'StorageServer POST handler', method, id, - user: req.auth.identityKey, + user: requiredAuthenticatedIdentityKey(req), params: JSON.stringify(params || '').slice(0, 256) } - const traceContext = (req.headers['X-Cloud-Trace-Context'] || req.headers['x-cloud-trace-context'])?.split('/')[0] + const traceContext = firstRequestHeader(req, 'X-Cloud-Trace-Context')?.split('/')[0] if (traceContext) { logObj['logging.googleapis.com/trace'] = `projects/computing-with-integrity/traces/${traceContext}` } @@ -496,7 +515,7 @@ export class StorageServer { case 'getSettings': return true case 'findOrInsertUser': - if (params[0] !== req.auth.identityKey) { + if (params[0] !== requiredAuthenticatedIdentityKey(req)) { throw new WERR_UNAUTHORIZED('function may only access authenticated user.') } return true @@ -521,10 +540,11 @@ export class StorageServer { } private authorizeAdminStats (params: any[], req: Request): void { - if (params[0] !== req.auth.identityKey) { + const identityKey = requiredAuthenticatedIdentityKey(req) + if (params[0] !== identityKey) { throw new WERR_UNAUTHORIZED('function may only access authenticated admin user.') } - if (!this.adminIdentityKeys?.includes(req.auth.identityKey)) { + if (!this.adminIdentityKeys?.includes(identityKey)) { throw new WERR_UNAUTHORIZED('function may only be accessed by admin user.') } } @@ -562,13 +582,14 @@ export class StorageServer { } private async authenticatedAuth (req: Request, requireActive: boolean): Promise { - const { user } = await this.storage.findOrInsertUser(req.auth.identityKey) + const identityKey = requiredAuthenticatedIdentityKey(req) + const { user } = await this.storage.findOrInsertUser(identityKey) const isActive = user.activeStorage === this.storage.getSettings().storageIdentityKey if (requireActive && !isActive) { throw new WERR_NOT_ACTIVE('action batch methods require the authenticated user\'s active storage provider') } return { - identityKey: req.auth.identityKey, + identityKey, userId: user.userId, isActive } @@ -577,7 +598,8 @@ export class StorageServer { private async bindAuthenticatedAuth (params: any[], req: Request, requireActive: boolean): Promise { if (!Array.isArray(params)) throw new WERR_UNAUTHORIZED('authenticated RPC parameters are required') const claimed = typeof params[0] === 'object' && params[0] != null ? params[0] : {} - if (claimed.identityKey != null && claimed.identityKey !== req.auth.identityKey) { + const identityKey = requiredAuthenticatedIdentityKey(req) + if (claimed.identityKey != null && claimed.identityKey !== identityKey) { throw new WERR_UNAUTHORIZED('identityKey does not match authentication') } const auth = await this.authenticatedAuth(req, requireActive) @@ -593,9 +615,10 @@ export class StorageServer { if (typeof params[0] !== 'object' || !params[0]) { params[0] = {} } - if (params[0].identityKey && params[0].identityKey !== req.auth.identityKey) { throw new WERR_UNAUTHORIZED('identityKey does not match authentication') } - // console.log('looking up user with identityKey:', req.auth.identityKey) - const { user } = await this.storage.findOrInsertUser(req.auth.identityKey) + const identityKey = requiredAuthenticatedIdentityKey(req) + if (params[0].identityKey && params[0].identityKey !== identityKey) { throw new WERR_UNAUTHORIZED('identityKey does not match authentication') } + // console.log('looking up user with identityKey:', identityKey) + const { user } = await this.storage.findOrInsertUser(identityKey) params[0].reqAuthUserId = user.userId if (params[0].identityKey || params[0].userId != null) params[0].userId = user.userId } diff --git a/packages/wallet/wallet-toolbox/src/storage/remoting/__test/StorageServerRpc.test.ts b/packages/wallet/wallet-toolbox/src/storage/remoting/__test/StorageServerRpc.test.ts index ef5a64627..7fcf0152f 100644 --- a/packages/wallet/wallet-toolbox/src/storage/remoting/__test/StorageServerRpc.test.ts +++ b/packages/wallet/wallet-toolbox/src/storage/remoting/__test/StorageServerRpc.test.ts @@ -42,7 +42,7 @@ function makeResponse (): CapturedResponse { function makeRequest ( body: unknown, - headers: Record = {}, + headers: Record = {}, identityKey: string = 'alice' ): Request { const normalizedHeaders = Object.fromEntries( @@ -201,6 +201,64 @@ describe('StorageServer JSON-RPC boundary', () => { }) }) + test('rejects an RPC request without a valid authenticated identity', async () => { + const server = makeServer() + const body = { + jsonrpc: '2.0', + method: 'getSettings', + params: [], + id: 6 + } + const requests = [ + makeRequest(body, {}, 'unknown'), + makeRequest(body, {}, ' '), + makeRequest(body) + ] + Reflect.set(requests[2], 'auth', { identityKey: null }) + const missingAuth = makeRequest(body) + Reflect.deleteProperty(missingAuth, 'auth') + requests.push(missingAuth) + + for (const request of requests) { + await expect(invoke( + server, + 'handleRpcRequest', + request, + makeResponse().response + )).rejects.toThrow('authenticated request identity is required') + } + }) + + test('normalizes a multi-value trace header in short-request logging', async () => { + const server = makeServer() + const app = Reflect.get(server, 'app') + const use = jest.spyOn(app, 'use') + await invoke(server, 'setupShortReqLogging') + const middleware = use.mock.calls.at(-1)?.[0] + expect(typeof middleware).toBe('function') + + const next = jest.fn() + middleware( + makeRequest({ + jsonrpc: '2.0', + method: 'getSettings', + params: [], + id: 7 + }, { + 'content-length': '42', + 'content-type': 'application/json', + 'X-Cloud-Trace-Context': ['first-trace/123', 'second-trace/456'] + }), + makeResponse().response, + next + ) + + expect(next).toHaveBeenCalledTimes(1) + expect(consoleLog).toHaveBeenCalledWith(expect.stringContaining('first-trace')) + expect(consoleLog).not.toHaveBeenCalledWith(expect.stringContaining('second-trace')) + use.mockRestore() + }) + test('enforces method-specific authorization and validates sync chunks', async () => { const request = makeRequest({}, {}, 'alice') const server = makeServer({}, { adminIdentityKeys: ['alice'] }) @@ -247,6 +305,24 @@ describe('StorageServer JSON-RPC boundary', () => { request )).resolves.toBe(true) expect(syncParams[0].reqAuthUserId).toBe(7) + + const syncParamsWithoutClaim: any[] = [{}, { ...emptyChunk }] + await expect(invoke( + server, + 'authorizeRpcCall', + 'processSyncChunk', + syncParamsWithoutClaim, + request + )).resolves.toBe(true) + expect(syncParamsWithoutClaim[0].reqAuthUserId).toBe(7) + + await expect(invoke( + server, + 'authorizeRpcCall', + 'processSyncChunk', + [{ identityKey: 'mallory' }, { ...emptyChunk }], + request + )).rejects.toThrow('identityKey does not match authentication') }) test('propagates authenticated identity and nested logger output', async () => { @@ -274,5 +350,22 @@ describe('StorageServer JSON-RPC boundary', () => { expect(logger.logs?.some(entry => entry.log.includes('userId: 7'))).toBe(true) expect(logger.logs?.some(entry => entry.log.includes('identityKey: alice'))).toBe(true) expect(result.log).toEqual({ logs: logger.logs }) + + const paramsWithoutClaim: any[] = [{}, {}] + await invoke(server, 'authorizeStandardRpcCall', 'abortAction', paramsWithoutClaim, request) + expect(paramsWithoutClaim[0]).toMatchObject({ + identityKey: 'alice', + userId: 7, + reqAuthUserId: 7, + isActive: true + }) + + await expect(invoke( + server, + 'authorizeStandardRpcCall', + 'abortAction', + [{ identityKey: 'mallory' }, {}], + request + )).rejects.toThrow('identityKey does not match authentication') }) }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 85d1f280d..814ecdf82 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -624,6 +624,9 @@ importers: packages/messaging/ts-paymail: dependencies: + '@types/express': + specifier: ^5.0.6 + version: 5.0.6 cross-fetch: specifier: ^4.1.0 version: 4.1.0 @@ -640,9 +643,6 @@ importers: '@jest/globals': specifier: ^30.4.1 version: 30.4.1 - '@types/express': - specifier: ^5.0.6 - version: 5.0.6 '@types/jest': specifier: ^30.0.0 version: 30.0.0 @@ -779,6 +779,9 @@ importers: packages/middleware/auth-express-middleware: dependencies: + '@types/express': + specifier: ^5.0.6 + version: 5.0.6 express: specifier: ^5.2.1 version: 5.2.1 @@ -792,9 +795,6 @@ importers: '@types/body-parser': specifier: ^1.19.6 version: 1.19.6 - '@types/express': - specifier: ^5.0.6 - version: 5.0.6 '@types/jest': specifier: ^30.0.0 version: 30.0.0 @@ -831,6 +831,9 @@ importers: packages/middleware/payment-express-middleware: dependencies: + '@types/express': + specifier: ^5.0.6 + version: 5.0.6 express: specifier: ^5.2.1 version: 5.2.1 @@ -844,9 +847,6 @@ importers: '@types/body-parser': specifier: ^1.19.6 version: 1.19.6 - '@types/express': - specifier: ^5.0.6 - version: 5.0.6 '@types/jest': specifier: ^30.0.0 version: 30.0.0 @@ -1154,6 +1154,9 @@ importers: '@bsv/wallet-toolbox-client': specifier: workspace:^ version: link:../../wallet/wallet-toolbox/client + '@types/express': + specifier: ^5.0.6 + version: 5.0.6 body-parser: specifier: ^2.3.0 version: 2.3.0 @@ -1182,9 +1185,6 @@ importers: '@types/body-parser': specifier: ^1.19.6 version: 1.19.6 - '@types/express': - specifier: ^5.0.6 - version: 5.0.6 '@types/jest': specifier: ^30.0.0 version: 30.0.0 @@ -1444,6 +1444,9 @@ importers: packages/wallet/ts-wallet-relay: dependencies: + '@types/express': + specifier: ^5.0.6 + version: 5.0.6 ws: specifier: ^8.21.1 version: 8.21.1 @@ -1460,9 +1463,6 @@ importers: '@testing-library/react': specifier: ^16.3.2 version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) - '@types/express': - specifier: ^5.0.6 - version: 5.0.6 '@types/jest': specifier: ^30.0.0 version: 30.0.0 @@ -1523,6 +1523,9 @@ importers: '@bsv/payment-express-middleware': specifier: workspace:^ version: link:../../middleware/payment-express-middleware + '@types/express': + specifier: ^5.0.6 + version: 5.0.6 better-sqlite3: specifier: ^13.0.1 version: 13.0.1 diff --git a/scripts/check-documentation-examples.mjs b/scripts/check-documentation-examples.mjs new file mode 100644 index 000000000..60c139df7 --- /dev/null +++ b/scripts/check-documentation-examples.mjs @@ -0,0 +1,187 @@ +#!/usr/bin/env node + +import { execFile } from 'node:child_process' +import { mkdtemp, mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { join, resolve } from 'node:path' +import { promisify } from 'node:util' +import { fileURLToPath } from 'node:url' + +const execFileAsync = promisify(execFile) +const ROOT = fileURLToPath(new URL('..', import.meta.url)) +const EXAMPLES = join(ROOT, 'docs/guides/compiled-package-examples.md') +const INVENTORY = join(ROOT, 'governance/repository-health/projects.json') +const inventory = JSON.parse(await readFile(INVENTORY, 'utf8')) +const publicProjects = inventory.projects.filter(project => project.release === 'npm-oidc') +const projectsByName = new Map(publicProjects.map(project => [project.name, project])) +const sdkProject = projectsByName.get('@bsv/sdk') +if (!sdkProject) throw new Error('Governed project inventory is missing @bsv/sdk') +const sdkManifest = JSON.parse(await readFile(join(ROOT, sdkProject.path, 'package.json'), 'utf8')) +const nodeTypesVersion = sdkManifest.devDependencies?.['@types/node'] +if (!nodeTypesVersion) + throw new Error('@bsv/sdk must govern the compiled-example @types/node version') +const nativeTypeScript = join(ROOT, sdkProject.path, 'node_modules/.bin/tsc') + +async function run(command, args, options = {}) { + try { + return await execFileAsync(command, args, { + cwd: options.cwd ?? ROOT, + env: options.env ?? process.env, + maxBuffer: 16 * 1024 * 1024 + }) + } catch (error) { + const output = [error.stdout, error.stderr].filter(Boolean).join('\n') + throw new Error(`${command} ${args.join(' ')} failed\n${output}`, { cause: error }) + } +} + +function extractExamples(markdown) { + const blocks = [] + const ids = new Set() + let sourceLines + for (const line of markdown.split('\n')) { + const marker = line.trim() + if (sourceLines === undefined) { + if (marker === '```ts compile' || marker === '```typescript compile') sourceLines = [] + continue + } + if (marker !== '```') { + sourceLines.push(line) + continue + } + const source = sourceLines.join('\n').trim() + const id = /^\/\/ example-id:\s*([a-z0-9-]+)\s*$/m.exec(source)?.[1] + if (!id) throw new Error('Every compiled example needs a // example-id: marker') + if (ids.has(id)) throw new Error(`Duplicate compiled example id: ${id}`) + ids.add(id) + blocks.push({ id, source }) + sourceLines = undefined + } + if (sourceLines !== undefined) throw new Error('Compiled example fence is not closed') + if (blocks.length < 8) { + throw new Error(`Expected at least 8 compiled cross-domain examples, found ${blocks.length}`) + } + return blocks +} + +function importedPackages(blocks) { + const names = new Set() + const importPattern = /from\s+['"](@bsv\/[^/'"]+|create-bsv-app)(?:\/[^'"]+)?['"]/g + for (const { source } of blocks) { + for (const match of source.matchAll(importPattern)) names.add(match[1]) + } + return names +} + +async function firstPartyClosure(initialNames) { + const closure = new Set(initialNames) + const queue = [...initialNames] + while (queue.length > 0) { + const name = queue.shift() + const project = projectsByName.get(name) + if (!project) throw new Error(`Compiled example imports ungoverned package ${name}`) + const manifest = JSON.parse(await readFile(join(ROOT, project.path, 'package.json'), 'utf8')) + for (const section of ['dependencies', 'optionalDependencies', 'peerDependencies']) { + for (const dependency of Object.keys(manifest[section] ?? {})) { + if (!projectsByName.has(dependency) || closure.has(dependency)) continue + closure.add(dependency) + queue.push(dependency) + } + } + } + return [...closure].sort((left, right) => left.localeCompare(right)) +} + +async function packProject(name, tarballDirectory) { + const project = projectsByName.get(name) + const { stdout } = await run('pnpm', ['pack', '--json', '--pack-destination', tarballDirectory], { + cwd: join(ROOT, project.path), + env: { ...process.env, npm_config_ignore_scripts: 'true' } + }) + const result = JSON.parse(stdout) + const tarballPath = resolve(result.filename) + if (!tarballPath.startsWith(`${tarballDirectory}/`)) { + throw new Error(`${name} packed outside the temporary artifact directory`) + } + return tarballPath +} + +const temporaryDirectory = await mkdtemp(join(tmpdir(), 'ts-stack-doc-examples-')) +try { + const blocks = extractExamples(await readFile(EXAMPLES, 'utf8')) + const packageNames = await firstPartyClosure(importedPackages(blocks)) + const tarballDirectory = join(temporaryDirectory, 'tarballs') + const consumerDirectory = join(temporaryDirectory, 'consumer') + await mkdir(tarballDirectory) + await mkdir(consumerDirectory) + + const dependencies = {} + for (const name of packageNames) { + dependencies[name] = `file:${await packProject(name, tarballDirectory)}` + } + + const developmentDependencies = { + '@types/node': nodeTypesVersion + } + await writeFile( + join(consumerDirectory, 'package.json'), + `${JSON.stringify( + { + name: 'ts-stack-compiled-documentation-consumer', + private: true, + type: 'module', + dependencies, + devDependencies: developmentDependencies + }, + null, + 2 + )}\n` + ) + await writeFile( + join(consumerDirectory, 'pnpm-workspace.yaml'), + `${JSON.stringify({ overrides: dependencies }, null, 2)}\n` + ) + const combinedExamples = blocks + .map(block => [`// ${block.id}`, block.source].join('\n')) + .join('\n\n') + await writeFile(join(consumerDirectory, 'examples.ts'), `${combinedExamples}\n`) + await writeFile( + join(consumerDirectory, 'tsconfig.json'), + `${JSON.stringify( + { + compilerOptions: { + strict: true, + noEmit: true, + target: 'ES2024', + module: 'ESNext', + moduleResolution: 'Bundler', + lib: ['ES2024', 'DOM'], + types: ['node'], + skipLibCheck: false + }, + include: ['examples.ts'] + }, + null, + 2 + )}\n` + ) + + await run('pnpm', ['install', '--ignore-scripts', '--no-frozen-lockfile'], { + cwd: consumerDirectory + }) + await run( + nativeTypeScript, + ['--project', join(consumerDirectory, 'tsconfig.json'), '--pretty', 'false'], + { cwd: consumerDirectory } + ) + + const tarballs = (await readdir(tarballDirectory)).filter(file => file.endsWith('.tgz')) + if (tarballs.length !== packageNames.length) { + throw new Error(`Expected ${packageNames.length} tarballs, found ${tarballs.length}`) + } + console.log( + `Compiled documentation examples passed: ${blocks.length} examples, ${packageNames.length} exact package tarballs` + ) +} finally { + await rm(temporaryDirectory, { recursive: true, force: true }) +} diff --git a/scripts/check-package-artifact.mjs b/scripts/check-package-artifact.mjs index 291c80ae6..ad315ab40 100644 --- a/scripts/check-package-artifact.mjs +++ b/scripts/check-package-artifact.mjs @@ -4,12 +4,13 @@ import fs from 'node:fs/promises' import os from 'node:os' import path from 'node:path' import process from 'node:process' -import { pathToFileURL } from 'node:url' +import { fileURLToPath, pathToFileURL } from 'node:url' import { createCommandRunner } from './lib/command-runner.mjs' const COMMAND_TIMEOUT_MS = 180_000 const MAX_BUFFER_BYTES = 20 * 1024 * 1024 +const REPOSITORY_ROOT = fileURLToPath(new URL('..', import.meta.url)) function optionValue(arguments_, name, fallback = '') { const index = arguments_.indexOf(name) @@ -128,6 +129,50 @@ function identityErrors(packResult, manifest) { return errors } +function workspaceRuntimeDependencies(manifest) { + const dependencies = [] + for (const field of ['dependencies', 'optionalDependencies']) { + for (const [name, range] of Object.entries(manifest[field] ?? {})) { + if (typeof range === 'string' && range.startsWith('workspace:')) { + dependencies.push(name) + } + } + } + return dependencies +} + +export function workspaceRuntimeClosure(rootManifest, manifestsByName) { + const selected = new Set() + const queue = workspaceRuntimeDependencies(rootManifest) + while (queue.length > 0) { + const name = queue.shift() + if (name === rootManifest.name || selected.has(name)) continue + const manifest = manifestsByName.get(name) + if (!manifest) { + throw new Error(`${rootManifest.name} references unknown workspace dependency ${name}`) + } + selected.add(name) + queue.push(...workspaceRuntimeDependencies(manifest)) + } + return [...selected].sort((left, right) => left.localeCompare(right)) +} + +async function governedWorkspaceManifests() { + const registry = JSON.parse( + await fs.readFile( + path.join(REPOSITORY_ROOT, 'governance/repository-health/projects.json'), + 'utf8' + ) + ) + const manifests = new Map() + for (const project of registry.projects) { + const directory = path.join(REPOSITORY_ROOT, project.path) + const manifest = JSON.parse(await fs.readFile(path.join(directory, 'package.json'), 'utf8')) + manifests.set(manifest.name, { directory, manifest }) + } + return manifests +} + export function validatePackedFiles(packResult, manifest, allowedSourcePrefixes = []) { const normalizedSourcePrefixes = normalizeSourcePrefixes(allowedSourcePrefixes) const files = (packResult.files ?? []).map(file => file.path) @@ -334,13 +379,21 @@ export async function checkPackageArtifact({ const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8')) const packed = await packPackage(packageDirectory) const localDependencies = [] - const localDependencyNames = new Set() + const explicitDependencyNames = new Set() const declaredDependencies = { ...manifest.dependencies, ...manifest.optionalDependencies, ...manifest.peerDependencies } try { + const workspaceManifests = await governedWorkspaceManifests() + const manifestsByName = new Map( + [...workspaceManifests].map(([name, project]) => [name, project.manifest]) + ) + const localDependencyDirectories = new Map() + for (const name of workspaceRuntimeClosure(manifest, manifestsByName)) { + localDependencyDirectories.set(name, workspaceManifests.get(name).directory) + } for (const dependencyDirectory of localConsumerDependencyDirectories) { const dependencyManifest = JSON.parse( await fs.readFile(path.join(dependencyDirectory, 'package.json'), 'utf8') @@ -348,12 +401,17 @@ export async function checkPackageArtifact({ if ( typeof dependencyManifest.name !== 'string' || dependencyManifest.name === manifest.name || - localDependencyNames.has(dependencyManifest.name) || + explicitDependencyNames.has(dependencyManifest.name) || !(dependencyManifest.name in declaredDependencies) ) { throw new Error(`invalid local consumer dependency ${JSON.stringify(dependencyDirectory)}`) } - localDependencyNames.add(dependencyManifest.name) + explicitDependencyNames.add(dependencyManifest.name) + localDependencyDirectories.set(dependencyManifest.name, dependencyDirectory) + } + for (const [, dependencyDirectory] of [...localDependencyDirectories].sort(([left], [right]) => + left.localeCompare(right) + )) { localDependencies.push(await packPackage(dependencyDirectory)) } const payloadErrors = validatePackedFiles(packed.result, manifest, allowedSourcePrefixes) diff --git a/scripts/check-package-artifact.test.mjs b/scripts/check-package-artifact.test.mjs index 2ccc097b5..a6cedfd03 100644 --- a/scripts/check-package-artifact.test.mjs +++ b/scripts/check-package-artifact.test.mjs @@ -1,7 +1,11 @@ import assert from 'node:assert/strict' import test from 'node:test' -import { typeProblemsForModes, validatePackedFiles } from './check-package-artifact.mjs' +import { + typeProblemsForModes, + validatePackedFiles, + workspaceRuntimeClosure +} from './check-package-artifact.mjs' const manifest = { name: '@bsv/example', @@ -102,3 +106,42 @@ test('strict type policy ignores only the unsupported CommonJS mode for ESM-only assert.deepEqual(typeProblemsForModes(problems, ['esm', 'cjs'], ['.']), problems.slice(2)) assert.deepEqual(typeProblemsForModes(problems, ['esm', 'cjs'], [], ['.']), []) }) + +test('packed consumers use the exact transitive workspace runtime closure', () => { + const root = { + name: '@bsv/root', + dependencies: { + '@bsv/a': 'workspace:^', + '@bsv/registry-only': '^1.0.0' + }, + peerDependencies: { + '@bsv/peer': '^1.0.0' + } + } + const manifests = new Map([ + [ + '@bsv/a', + { + name: '@bsv/a', + optionalDependencies: { '@bsv/b': 'workspace:*' } + } + ], + [ + '@bsv/b', + { + name: '@bsv/b', + dependencies: { '@bsv/a': 'workspace:^' } + } + ] + ]) + + assert.deepEqual(workspaceRuntimeClosure(root, manifests), ['@bsv/a', '@bsv/b']) + assert.throws( + () => + workspaceRuntimeClosure( + { name: '@bsv/root', dependencies: { '@bsv/missing': 'workspace:^' } }, + manifests + ), + /unknown workspace dependency @bsv\/missing/ + ) +}) diff --git a/scripts/check-versions.mjs b/scripts/check-versions.mjs index b53a54337..f7b1f9e7f 100644 --- a/scripts/check-versions.mjs +++ b/scripts/check-versions.mjs @@ -16,6 +16,10 @@ import { execSync } from 'node:child_process' const __dirname = dirname(fileURLToPath(import.meta.url)) const ROOT = resolve(__dirname, '..') +const projectRegistry = JSON.parse( + readFileSync(resolve(ROOT, 'governance/repository-health/projects.json'), 'utf8') +) +const projectPolicies = new Map(projectRegistry.projects.map(project => [project.name, project])) const output = execSync('pnpm -r ls --json --depth 0', { cwd: ROOT }).toString() const pkgList = JSON.parse(output) @@ -78,6 +82,14 @@ const developmentOnlyPackages = new Set([ 'typescript' ]) +function runtimePackageForTypes(dependency) { + const name = dependency.slice('@types/'.length) + const scopedSeparator = name.indexOf('__') + return scopedSeparator === -1 + ? name + : `@${name.slice(0, scopedSeparator)}/${name.slice(scopedSeparator + 2)}` +} + for (const pkg of pkgList) { if (!pkg.path) continue const jsonPath = resolve(pkg.path, 'package.json') @@ -89,12 +101,38 @@ for (const pkg of pkgList) { } const d = JSON.parse(raw) if (d.private !== true) { + const declarationDependencies = new Set( + projectPolicies.get(d.name)?.declarationDependencies ?? [] + ) for (const dependency of Object.keys(d.dependencies ?? {})) { - if (dependency.startsWith('@types/') || developmentOnlyPackages.has(dependency)) { + if ( + developmentOnlyPackages.has(dependency) || + (dependency.startsWith('@types/') && !declarationDependencies.has(dependency)) + ) { console.log(`PUBLISH SURFACE ${d.name} exposes development-only dependency ${dependency}`) runtimeToolLeaks++ } } + for (const dependency of declarationDependencies) { + if (!Object.hasOwn(d.dependencies ?? {}, dependency)) { + console.log( + `DECLARATION DEPENDENCY ${d.name} must publish governed dependency ${dependency}` + ) + runtimeToolLeaks++ + } + const runtimePackage = runtimePackageForTypes(dependency) + const runtimeSurface = { + ...d.dependencies, + ...d.optionalDependencies, + ...d.peerDependencies + } + if (!Object.hasOwn(runtimeSurface, runtimePackage)) { + console.log( + `DECLARATION DEPENDENCY ${d.name} publishes ${dependency} without ${runtimePackage}` + ) + runtimeToolLeaks++ + } + } } const testCommand = d.scripts?.test diff --git a/scripts/documentation-policy.mjs b/scripts/documentation-policy.mjs new file mode 100644 index 000000000..b2a38f8b0 --- /dev/null +++ b/scripts/documentation-policy.mjs @@ -0,0 +1,160 @@ +#!/usr/bin/env node + +import { readdir, readFile } from 'node:fs/promises' +import { join } from 'node:path' +import { fileURLToPath } from 'node:url' + +const ROOT = fileURLToPath(new URL('..', import.meta.url)) +const INVENTORY = join(ROOT, 'governance/repository-health/projects.json') +const POLICY = join(ROOT, 'governance/documentation-policy.json') + +const installationHeading = + /^## (?:Install|Installation|Getting Started|Quick start|Quickstart|Requirements and installation|Using)\b/im +function failure(project, message) { + return `${project.name} (${project.path}/README.md): ${message}` +} + +function frontmatterValue(frontmatter, key) { + return frontmatter.match(new RegExp(String.raw`^${key}:\s*["']?([^"'\n]+)["']?\s*$`, 'm'))?.[1] +} + +async function walkMarkdown(directory) { + const entries = await readdir(directory, { withFileTypes: true }) + const files = [] + for (const entry of entries) { + const fullPath = join(directory, entry.name) + if (entry.isDirectory()) files.push(...(await walkMarkdown(fullPath))) + else if (entry.name.endsWith('.md')) files.push(fullPath) + } + return files +} + +const inventory = JSON.parse(await readFile(INVENTORY, 'utf8')) +const policy = JSON.parse(await readFile(POLICY, 'utf8')) +const publicPackages = inventory.projects.filter(project => project.release === 'npm-oidc') +const projectsByName = new Map(inventory.projects.map(project => [project.name, project])) +const failures = [] +const documentedProjects = new Set() +let packageDocCount = 0 +let freshnessDocCount = 0 + +for (const project of publicPackages) { + const packageJsonPath = join(ROOT, project.path, 'package.json') + const readmePath = join(ROOT, project.path, 'README.md') + const licensePath = join(ROOT, project.path, policy.publicPackageReadme.requiredLicenseFile) + const manifest = JSON.parse(await readFile(packageJsonPath, 'utf8')) + const readme = await readFile(readmePath, 'utf8') + + if (!readme.startsWith('# ')) failures.push(failure(project, 'must start with an H1')) + if (!readme.includes(manifest.name)) { + failures.push(failure(project, `must identify the package as ${manifest.name}`)) + } + if (!installationHeading.test(readme)) { + failures.push(failure(project, 'needs an installation or getting-started section')) + } + if (!readme.includes('```')) { + failures.push(failure(project, 'needs usable guidance with a fenced example')) + } + if (!/^## License\s*$/im.test(readme)) { + failures.push(failure(project, 'needs a License section')) + } + if (!readme.includes('LICENSE.txt')) { + failures.push(failure(project, 'must link its package-local LICENSE.txt')) + } + await readFile(licensePath, 'utf8') +} + +const versions = new Map() +for (const project of inventory.projects) { + const manifest = JSON.parse( + await readFile(join(ROOT, project.path === '.' ? '' : project.path, 'package.json'), 'utf8') + ) + versions.set(project.name, manifest.version) +} + +for (const docPath of await walkMarkdown(join(ROOT, 'docs/packages'))) { + packageDocCount += 1 + const document = await readFile(docPath, 'utf8') + const frontmatter = document.split('---')[1] ?? '' + const title = frontmatterValue(frontmatter, 'title') + const project = projectsByName.get(title) + if (!title || !project) continue + if (documentedProjects.has(title)) { + failures.push(`${docPath.slice(ROOT.length + 1)}: duplicate package page for ${title}`) + } + documentedProjects.add(title) + + const documented = frontmatterValue(frontmatter, 'version') + if (documented !== versions.get(title)) { + failures.push( + `${docPath.slice(ROOT.length + 1)}: version ${documented ?? ''} does not match ${title}@${versions.get(title)}` + ) + } + const expectedRepository = `https://github.com/bsv-blockchain/ts-stack/tree/main/${project.path}` + const repository = frontmatterValue(frontmatter, 'repo') + if (repository !== expectedRepository) { + failures.push(`${docPath.slice(ROOT.length + 1)}: repo must be ${expectedRepository}`) + } + const sourceRepository = frontmatterValue(frontmatter, 'source_repo') + if (sourceRepository && sourceRepository !== 'bsv-blockchain/ts-stack') { + failures.push(`${docPath.slice(ROOT.length + 1)}: source_repo must be bsv-blockchain/ts-stack`) + } + if (/^source_commit:/m.test(frontmatter)) { + failures.push( + `${docPath.slice(ROOT.length + 1)}: source_commit snapshots are not valid current package authority` + ) + } + if (project.release !== 'npm-oidc' && /^npm:/m.test(frontmatter)) { + failures.push(`${docPath.slice(ROOT.length + 1)}: private project must not advertise npm`) + } + for (const field of ['last_updated', 'last_verified', 'review_cadence_days']) { + if (!new RegExp(`^${field}:`, 'm').test(frontmatter)) { + failures.push(`${docPath.slice(ROOT.length + 1)}: package page is missing ${field}`) + } + } +} + +for (const project of publicPackages) { + if (!documentedProjects.has(project.name)) { + failures.push(`${project.name}: public package is missing a docs/packages page`) + } +} + +const today = new Date() +today.setUTCHours(0, 0, 0, 0) +for (const docPath of await walkMarkdown(join(ROOT, 'docs'))) { + if (docPath.includes('/_internal/') || docPath.includes('/_schemas/')) continue + const document = await readFile(docPath, 'utf8') + const frontmatter = document.split('---')[1] ?? '' + const updated = frontmatter.match(/^last_updated:\s*["']?(\d{4}-\d{2}-\d{2})/m)?.[1] + const verified = frontmatter.match(/^last_verified:\s*["']?(\d{4}-\d{2}-\d{2})/m)?.[1] + const cadence = Number(frontmatter.match(/^review_cadence_days:\s*(\d+)/m)?.[1]) + const relativePath = docPath.slice(ROOT.length + 1) + + if (!updated || !verified || !Number.isInteger(cadence)) continue + freshnessDocCount += 1 + if (updated > verified) { + failures.push(`${relativePath}: last_verified predates last_updated`) + } + + const verifiedDate = new Date(`${verified}T00:00:00Z`) + const staleAfter = new Date(verifiedDate) + staleAfter.setUTCDate(staleAfter.getUTCDate() + cadence) + if (staleAfter < today) { + failures.push(`${relativePath}: verification expired ${staleAfter.toISOString().slice(0, 10)}`) + } + if (verifiedDate > today) { + failures.push(`${relativePath}: last_verified cannot be in the future`) + } +} + +if (failures.length > 0) { + console.error(`Documentation policy failed (${failures.length} finding(s)):`) + for (const item of failures) console.error(`- ${item}`) + process.exit(1) +} + +console.log( + `Documentation policy passed: ${publicPackages.length} public package READMEs, ` + + `${packageDocCount} package docs, ${freshnessDocCount} freshness records, 0 findings` +) diff --git a/scripts/generate-parity-matrix.mjs b/scripts/generate-parity-matrix.mjs index b100e7df6..1b43dd0e4 100644 --- a/scripts/generate-parity-matrix.mjs +++ b/scripts/generate-parity-matrix.mjs @@ -14,6 +14,12 @@ const __dirname = fileURLToPath(new URL('.', import.meta.url)) const ROOT = join(__dirname, '..') const VECTORS_DIR = join(ROOT, 'conformance/vectors') const OUTPUT = join(ROOT, 'conformance/PARITY_MATRIX.json') +const META = join(ROOT, 'conformance/META.json') +const CHECK_MODE = process.argv.includes('--check') + +if (process.argv.slice(2).some(arg => arg !== '--check')) { + throw new Error('Usage: node scripts/generate-parity-matrix.mjs [--check]') +} const STATEFUL_TAG_KEYS = ['funded', 'live_overlay', 'state', 'harness'] @@ -89,6 +95,18 @@ function classifyReason(relPath, counts) { justification: `${counts.intended} tx_invalid / MINIMALDATA / OP_VER edge cases intentionally differ from reference test vectors` } } + if (counts.intended > 0) { + return { + reasonCategory: 'intended_parity_work', + justification: `${counts.intended} vector(s) are classified as intended rather than required` + } + } + if (counts.skipped > 0) { + return { + reasonCategory: 'governed_vector_skip', + justification: '' + } + } return { reasonCategory: 'fully_supported', justification: '' } } @@ -146,6 +164,7 @@ function buildSummary(files) { } try { + const meta = JSON.parse(await readFile(META, 'utf8')) const jsonFiles = await walk(VECTORS_DIR) const files = [] for (const fullPath of jsonFiles) { @@ -154,9 +173,21 @@ try { files.sort((a, b) => a.path.localeCompare(b.path)) const summary = buildSummary(files) + if ( + meta.stats?.total_files !== summary.total_files || + meta.stats?.total_vectors !== summary.total_vectors + ) { + throw new Error( + `conformance/META.json stats are stale: expected ${summary.total_files} files / ${summary.total_vectors} vectors` + ) + } + if (!/^\d{4}-\d{2}-\d{2}$/.test(meta.stats?.last_updated ?? '')) { + throw new Error('conformance/META.json stats.last_updated must be an ISO date') + } + const matrix = { schema_version: '1.0', - generated_at: new Date().toISOString().split('T')[0], + generated_at: meta.stats.last_updated, source: 'ts-stack conformance corpus', description: 'Machine-readable parity status for cross-language SDK implementations (Go, Rust, Python). Use this to track and drive conformance.', @@ -164,8 +195,19 @@ try { files } - await writeFile(OUTPUT, JSON.stringify(matrix, null, 2) + '\n') - console.log(`Generated ${OUTPUT}`) + const generated = JSON.stringify(matrix, null, 2) + '\n' + if (CHECK_MODE) { + const committed = await readFile(OUTPUT, 'utf8') + if (committed !== generated) { + throw new Error( + 'conformance/PARITY_MATRIX.json is stale; run `pnpm docs:facts` and commit the result' + ) + } + console.log(`Verified ${OUTPUT}`) + } else { + await writeFile(OUTPUT, generated) + console.log(`Generated ${OUTPUT}`) + } console.log(` Files: ${summary.total_files}`) console.log(` Vectors: ${summary.total_vectors}`) console.log(` Fully required files: ${summary.fully_required_files}`) diff --git a/scripts/generate-stack-facts.mjs b/scripts/generate-stack-facts.mjs new file mode 100644 index 000000000..4d17a52ca --- /dev/null +++ b/scripts/generate-stack-facts.mjs @@ -0,0 +1,243 @@ +#!/usr/bin/env node + +import { readFile, writeFile } from 'node:fs/promises' +import { join } from 'node:path' +import { fileURLToPath } from 'node:url' + +const ROOT = fileURLToPath(new URL('..', import.meta.url)) +const OUTPUT = join(ROOT, 'docs/reference/stack-facts.md') +const CHECK_MODE = process.argv.includes('--check') + +if (process.argv.slice(2).some(arg => arg !== '--check')) { + throw new Error('Usage: node scripts/generate-stack-facts.mjs [--check]') +} + +async function readJson(path) { + return JSON.parse(await readFile(join(ROOT, path), 'utf8')) +} + +function escapeCell(value) { + return String(value === undefined || value === null || value === '' ? '—' : value) + .replaceAll('|', String.raw`\|`) + .replaceAll('\n', ' ') +} + +function table(headers, rows) { + const header = `| ${headers.join(' | ')} |` + const separator = `| ${headers.map(() => '---').join(' | ')} |` + return [header, separator, ...rows.map(row => `| ${row.map(escapeCell).join(' | ')} |`)].join( + '\n' + ) +} + +function repositoryLink(project) { + if (project.path === '.') { + return '[repository root](https://github.com/bsv-blockchain/ts-stack)' + } + return `[${project.path}](https://github.com/bsv-blockchain/ts-stack/tree/main/${project.path})` +} + +const [rootManifest, inventory, containerPolicy, policy, meta, parity, baseline] = + await Promise.all([ + readJson('package.json'), + readJson('governance/repository-health/projects.json'), + readJson('governance/container-images.json'), + readJson('governance/documentation-policy.json'), + readJson('conformance/META.json'), + readJson('conformance/PARITY_MATRIX.json'), + readJson('governance/repository-health/baselines.json') + ]) + +const projects = await Promise.all( + inventory.projects.map(async project => { + const manifest = await readJson( + project.path === '.' ? 'package.json' : `${project.path}/package.json` + ) + return { ...project, version: manifest.version, engines: manifest.engines ?? {} } + }) +) +const publicPackages = projects + .filter(project => project.release === 'npm-oidc') + .sort((a, b) => a.area.localeCompare(b.area) || a.name.localeCompare(b.name)) +const infrastructure = ( + await Promise.all( + containerPolicy.components.map(async component => { + const manifest = await readJson(`${component.path}/package.json`) + return { + ...component, + packageName: manifest.name, + version: manifest.version, + engines: manifest.engines ?? {}, + runtimeTargets: ['node', containerPolicy.platform] + } + }) + ) +).sort((a, b) => a.name.localeCompare(b.name)) +const sdk = projects.find(project => project.name === '@bsv/sdk') +if (!sdk) throw new Error('Governed project inventory is missing @bsv/sdk') +const sdkManifest = await readJson(`${sdk.path}/package.json`) +const publicNodeRanges = [...new Set(publicPackages.map(project => project.engines.node))] +const infrastructureNodeRanges = [...new Set(infrastructure.map(project => project.engines.node))] + +if (publicPackages.length !== baseline.workspace.publicPackages) { + throw new Error('Public-package inventory and repository-health baseline disagree') +} +if ( + meta.stats.total_files !== parity.summary.total_files || + meta.stats.total_vectors !== parity.summary.total_vectors || + meta.stats.total_files !== baseline.conformance.vectorFiles || + meta.stats.total_vectors !== baseline.conformance.total +) { + throw new Error('Conformance metadata, parity matrix, and governed baseline disagree') +} + +const content = `--- +id: stack-facts +title: 'Generated Stack Facts' +kind: reference +version: '1.0.0' +last_updated: '${policy.lastReviewed}' +last_verified: '${policy.lastReviewed}' +review_cadence_days: 30 +status: stable +tags: [reference, packages, versions, runtimes, conformance, generated] +--- + +# Generated Stack Facts + +This page is generated from committed manifests and governance records. Edit the source +manifests, \`governance/repository-health/projects.json\`, +\`governance/documentation-policy.json\`, or conformance metadata, then run +\`pnpm docs:facts\`. CI runs \`pnpm docs:facts:check\` and rejects drift. + +## Support and toolchain + +${table( + ['Profile', 'Current contract', 'Authority'], + [ + [ + 'Repository contributors, CI, releases', + `Node.js ${rootManifest.engines.node}; pnpm ${rootManifest.engines.pnpm} (${rootManifest.packageManager})`, + 'root package.json' + ], + [ + 'Published npm packages', + `${publicNodeRanges.join(', ')} for Node consumers; browser/mobile targets remain package-specific`, + 'public package manifests' + ], + [ + 'Standalone infrastructure', + infrastructureNodeRanges.join(', '), + 'service manifests and digest-pinned Dockerfiles' + ], + [ + 'TypeScript compiler', + `${sdkManifest.devDependencies['@typescript/native']} compiler; ${sdkManifest.devDependencies.typescript} tooling API`, + '@bsv/sdk package.json and TypeScript toolchain policy' + ] + ] +)} + +Node engine declarations on browser and React Native packages govern package tooling and +Node consumers; they do not require a browser or mobile device to provide Node APIs. + +## Public package manifest + +The release graph currently contains **${publicPackages.length} public packages**. Versions +below are source-manifest versions; registry publication is a separate, explicitly +authorized release action. + +${table( + ['Area', 'Package', 'Source version', 'Profile', 'Runtime targets', 'Node engine', 'Source'], + publicPackages.map(project => [ + project.area, + `\`${project.name}\``, + `\`${project.version}\``, + project.profile, + project.runtimeTargets.join(', '), + `\`${project.engines.node}\``, + repositoryLink(project) + ]) +)} + +## Standalone infrastructure manifests + +These versions identify the checked-in service manifests; production identity is +the separately released and verified image digest. + +${table( + ['Service', 'Package', 'Manifest version', 'Node engine', 'Runtime targets', 'Release', 'Source'], + infrastructure.map(project => [ + project.title, + `\`${project.packageName}\``, + `\`${project.version}\``, + `\`${project.engines.node}\``, + project.runtimeTargets.join(', '), + project.release, + repositoryLink(project) + ]) +)} + +## Governed project and release inventory + +${table( + ['Metric', 'Count'], + [ + ['Governed projects', projects.length], + ['Package-area projects', baseline.workspace.packageAreaProjects], + ['Public npm packages', publicPackages.length], + ['Private package-area projects', baseline.workspace.privatePackageAreaProjects], + ['Standalone infrastructure projects', infrastructure.length] + ] +)} + +Public packages use the \`npm-oidc\` release route. Other workspace projects are +private packages or documentation/conformance tooling. Standalone infrastructure +components are governed separately by \`governance/container-images.json\` and use their +recorded container release route; they are not published by the public-package job. + +## Conformance corpus + +${table( + ['Metric', 'Current value'], + [ + ['Vector files', meta.stats.total_files], + ['Vectors', meta.stats.total_vectors], + ['Structurally passed', baseline.conformance.passed], + ['Governed skips', baseline.conformance.skipped], + ['Required parity vectors', parity.summary.vectors_by_status.required], + ['Intended parity vectors', parity.summary.vectors_by_status.intended], + ['Explicitly skipped vector entries', parity.summary.vectors_by_status.skipped], + ['Corpus metadata revision', meta.stats.last_updated] + ] +)} + +Structural runner pass/skip results and parity classifications answer different questions: +the former is the current runner outcome, while the latter records cross-language +implementation intent. Neither count may be silently presented as the other. + +## Change procedure + +1. Change source manifests or vector files. +2. Update the governed inventory or \`conformance/META.json\` when its declared facts change. +3. Run \`pnpm docs:facts\`. +4. Run \`pnpm docs:facts:check\`, \`pnpm health:check\`, and the relevant package, + conformance, documentation, and release checks. +5. Review generated diffs together with the source change. Do not hand-edit this page or + \`conformance/PARITY_MATRIX.json\`. + +See [Versioning Policy](../about/versioning.md), +[Dependency and Release Policy](./dependency-policy.md), and +[Conformance Testing](../conformance/index.md) for the operational meaning of these facts. +` + +if (CHECK_MODE) { + const committed = await readFile(OUTPUT, 'utf8') + if (committed !== content) { + throw new Error('docs/reference/stack-facts.md is stale; run `pnpm docs:facts`') + } + console.log(`Verified ${OUTPUT}`) +} else { + await writeFile(OUTPUT, content) + console.log(`Generated ${OUTPUT}`) +} diff --git a/scripts/generated-documentation.test.mjs b/scripts/generated-documentation.test.mjs new file mode 100644 index 000000000..adc69b984 --- /dev/null +++ b/scripts/generated-documentation.test.mjs @@ -0,0 +1,25 @@ +import assert from 'node:assert/strict' +import { spawnSync } from 'node:child_process' +import { test } from 'node:test' + +function run(script, ...args) { + return spawnSync(process.execPath, [script, ...args], { + cwd: new URL('..', import.meta.url), + encoding: 'utf8' + }) +} + +test('generated stack facts are current', () => { + const result = run('scripts/generate-stack-facts.mjs', '--check') + assert.equal(result.status, 0, result.stderr || result.stdout) +}) + +test('conformance metadata and parity matrix are current', () => { + const result = run('scripts/generate-parity-matrix.mjs', '--check') + assert.equal(result.status, 0, result.stderr || result.stdout) +}) + +test('documentation policy is satisfied', () => { + const result = run('scripts/documentation-policy.mjs') + assert.equal(result.status, 0, result.stderr || result.stdout) +}) diff --git a/scripts/repository-health.mjs b/scripts/repository-health.mjs index a98a0c60a..b3ede3e2c 100644 --- a/scripts/repository-health.mjs +++ b/scripts/repository-health.mjs @@ -170,6 +170,36 @@ function validateDependencyAutomation(registry) { return errors } +function isDeclarationDependency(value) { + if (typeof value !== 'string' || !value.startsWith('@types/')) return false + const parts = value.slice('@types/'.length).split('__') + return parts.length <= 2 && parts.every(part => part.length > 0 && /^[a-z0-9._-]+$/i.test(part)) +} + +function validateDeclarationDependencies(project, prefix) { + const errors = [] + if (project.declarationDependencies === undefined) return errors + if ( + !Array.isArray(project.declarationDependencies) || + project.declarationDependencies.length === 0 + ) { + errors.push(`${prefix} declarationDependencies must be a non-empty array`) + } else { + for (const dependency of project.declarationDependencies) { + if (!isDeclarationDependency(dependency)) { + errors.push(`${prefix} has invalid declaration dependency ${JSON.stringify(dependency)}`) + } + } + for (const duplicate of duplicateValues(project.declarationDependencies)) { + errors.push(`${prefix} repeats declaration dependency ${duplicate}`) + } + } + if (project.release !== 'npm-oidc') { + errors.push(`${prefix} declarationDependencies are only valid for public packages`) + } + return errors +} + function validateProjectMetadata(project, registry) { const errors = [] const prefix = `projects.json entry ${project.path ?? ''}` @@ -195,9 +225,18 @@ function validateProjectMetadata(project, registry) { if (!RELEASES.has(project.release)) { errors.push(`${prefix} has invalid release ${JSON.stringify(project.release)}`) } + errors.push(...validateDeclarationDependencies(project, prefix)) return errors } +function runtimePackageForTypes(dependency) { + const name = dependency.slice('@types/'.length) + const scopedSeparator = name.indexOf('__') + return scopedSeparator === -1 + ? name + : `@${name.slice(0, scopedSeparator)}/${name.slice(scopedSeparator + 2)}` +} + function validateProjectManifest(project, actual) { const prefix = `projects.json entry ${project.path ?? ''}` if (!actual) return [`${prefix} has no discovered workspace package.json`] @@ -216,6 +255,22 @@ function validateProjectManifest(project, actual) { if (!isPrivate && project.release !== 'npm-oidc') { errors.push(`${prefix} is public but release is not npm-oidc`) } + for (const dependency of project.declarationDependencies ?? []) { + if (!Object.hasOwn(actual.manifest.dependencies ?? {}, dependency)) { + errors.push(`${prefix} must publish declaration dependency ${dependency}`) + } + const runtimePackage = runtimePackageForTypes(dependency) + const runtimeSurface = { + ...actual.manifest.dependencies, + ...actual.manifest.optionalDependencies, + ...actual.manifest.peerDependencies + } + if (!Object.hasOwn(runtimeSurface, runtimePackage)) { + errors.push( + `${prefix} declaration dependency ${dependency} requires runtime package ${runtimePackage}` + ) + } + } return errors } diff --git a/scripts/repository-health.test.mjs b/scripts/repository-health.test.mjs index e564b4da0..92792643f 100644 --- a/scripts/repository-health.test.mjs +++ b/scripts/repository-health.test.mjs @@ -51,6 +51,45 @@ test('current repository health controls and ratchet are internally consistent', assert.equal(result.findings.length, 0) }) +test('published declaration dependencies are explicit and backed by runtime modules', () => { + const governed = projects.projects.filter(project => project.declarationDependencies) + assert.deepEqual( + governed.map(project => project.name), + [ + '@bsv/paymail', + '@bsv/auth-express-middleware', + '@bsv/payment-express-middleware', + '@bsv/overlay-express', + '@bsv/wallet-relay', + '@bsv/wallet-toolbox' + ] + ) + assert.ok( + governed.every( + project => + project.declarationDependencies.length === 1 && + project.declarationDependencies[0] === '@types/express' + ) + ) + + const invalidProjects = structuredClone(projects) + invalidProjects.projects.find( + project => project.name === '@bsv/paymail' + ).declarationDependencies = ['express'] + assert.match( + validateProjectRegistry(invalidProjects, discoverWorkspaceProjects()).join('\n'), + /invalid declaration dependency "express"/ + ) + + const invalidDiscovered = structuredClone(discoverWorkspaceProjects()) + delete invalidDiscovered.find(project => project.manifest.name === '@bsv/paymail').manifest + .dependencies['@types/express'] + assert.match( + validateProjectRegistry(projects, invalidDiscovered).join('\n'), + /must publish declaration dependency @types\/express/ + ) +}) + test('every public package declares supported runtime and canonical support metadata', () => { const publicPackages = discoverWorkspaceProjects().filter( project => project.manifest.private !== true diff --git a/specs/reliability/README.md b/specs/reliability/README.md index b027cdf86..8d6cfa65e 100644 --- a/specs/reliability/README.md +++ b/specs/reliability/README.md @@ -1,11 +1,17 @@ -# Reliability Registry +# Reliability Registry — Historical Baselines -Centralized reliability records for all Tier 0/1 repos tracked by the MBGA plan. +These files preserve April 2026 MBGA point-in-time measurements. They are not +the current ts-stack status, package versions, support matrix, or work backlog. +Consolidation and later hardening invalidated many of their original gap +statements. -> **Why here, not in the source repos?** -> Phase 5 consolidates source repos into ts-stack. Keeping docs here avoids a double-touch (add now, move on consolidation). When a repo is consolidated, its reliability doc moves with it into `packages//`. -> -> Source repos get a short redirect in their README pointing here — see Phase 0 end-of-day task. +Use [Generated Stack Facts](../../docs/reference/stack-facts.md) for current +versions/runtime profiles, [Repository Health](../../docs/reference/repository-health.md) +for enforced controls, [Security Policy](../../.github/SECURITY.md) for current +security scope, and +[tracker #324](https://github.com/bsv-blockchain/ts-stack/issues/324) for +unfinished work. Keep the files below unchanged except for factual archival +corrections; new findings belong in current governance or the tracker. ## Registry @@ -29,9 +35,9 @@ Centralized reliability records for all Tier 0/1 repos tracked by the MBGA plan. | RL4 | healthz/readyz, structured logs, metrics, traces, runbook, SLOs, alerts | | RL5 | Fuzz/property tests, threat model, tracked security findings, green interop matrix | -## Notable gaps (2026-04-27) +## Notable gaps recorded on 2026-04-27 - **message-box-server** is RL1: no CI test workflow on push/PR (only a manual Docker ECR publish). Most urgent gap. -- No repo has a formal threat model or SBOM generation. -- No repo has fuzz/property tests (RL5 requirement for Tier 0). +- These statements describe the historical baseline and must not be quoted as + current status. - arc is the most mature at RL3: OTel tracing, Prometheus metrics, E2E Docker suite, OpenAPI + protobuf contracts. diff --git a/specs/reliability/arc.md b/specs/reliability/arc.md index 08f25d4e7..a39acfbee 100644 --- a/specs/reliability/arc.md +++ b/specs/reliability/arc.md @@ -1,6 +1,9 @@ +> **Historical April 2026 external-repository baseline.** Revalidate against +> the ARC repository before using any version, control, or gap statement. + # Reliability Status ## Component diff --git a/specs/reliability/go-sdk.md b/specs/reliability/go-sdk.md index ba613d391..4c53e77a7 100644 --- a/specs/reliability/go-sdk.md +++ b/specs/reliability/go-sdk.md @@ -1,6 +1,9 @@ +> **Historical April 2026 external-repository baseline.** Revalidate against +> the Go SDK repository before using any version, control, or gap statement. + # Reliability Status ## Component diff --git a/specs/reliability/message-box-server.md b/specs/reliability/message-box-server.md index cb8634124..f9c94f337 100644 --- a/specs/reliability/message-box-server.md +++ b/specs/reliability/message-box-server.md @@ -1,6 +1,10 @@ +> **Historical April 2026 baseline.** Current Message Box controls and +> remaining work are generated or tracked in the references linked from +> [the reliability registry](./README.md). + # Reliability Status ## Component diff --git a/specs/reliability/overlay-express.md b/specs/reliability/overlay-express.md index f93b8e8ec..fdff11b13 100644 --- a/specs/reliability/overlay-express.md +++ b/specs/reliability/overlay-express.md @@ -1,6 +1,10 @@ +> **Historical April 2026 baseline.** Current Overlay Express version, +> controls, and remaining work are generated or tracked in the references +> linked from [the reliability registry](./README.md). + # Reliability Status ## Component diff --git a/specs/reliability/ts-sdk.md b/specs/reliability/ts-sdk.md index 31c98230f..bce879092 100644 --- a/specs/reliability/ts-sdk.md +++ b/specs/reliability/ts-sdk.md @@ -1,6 +1,10 @@ +> **Historical April 2026 baseline.** Current SDK version, controls, and +> remaining work are generated or tracked in the references linked from +> [the reliability registry](./README.md). + # Reliability Status ## Component diff --git a/specs/reliability/wallet-toolbox.md b/specs/reliability/wallet-toolbox.md index 15ea82665..bab547239 100644 --- a/specs/reliability/wallet-toolbox.md +++ b/specs/reliability/wallet-toolbox.md @@ -1,6 +1,10 @@ +> **Historical April 2026 baseline.** Current Wallet Toolbox version, controls, +> and remaining work are generated or tracked in the references linked from +> [the reliability registry](./README.md). + # Reliability Status ## Component