From 95aeb9ac55f33211872dc4679f9a1ccc10e9c170 Mon Sep 17 00:00:00 2001 From: Kevin Nzeng Essimengane Date: Sun, 26 Jul 2026 21:22:09 +0200 Subject: [PATCH 1/4] Adapt Dotify for Product DevNet --- .gitignore | 2 + README.md | 28 +- docs/README.md | 2 + docs/backlog/24-access-streaming-v2.md | 8 +- docs/backlog/README.md | 26 +- docs/backlog/improvement-plan.md | 15 +- ...oduct-readiness-and-killer-dapp-roadmap.md | 60 +- docs/design/dotify-v2-access-and-streaming.md | 2 +- docs/explanation/architecture-overview.md | 5 +- .../product-devnet-architecture.md | 209 + docs/index.html | 21 +- docs/operations/deployment-configuration.md | 66 +- docs/operations/product-devnet-deployment.md | 174 + docs/reference/environment-variables.md | 68 +- services/api/.env.example | 2 + services/api/fly.toml | 1 + services/api/package.json | 2 +- services/api/src/app.ts | 5 +- services/api/src/config.ts | 17 +- services/api/src/cors.test.ts | 36 + spec.md | 36 +- web/.env.example | 6 + web/.env.product-devnet | 22 + web/README.md | 18 + web/eslint.config.js | 2 +- web/fly.signal.toml | 1 + web/package-lock.json | 4100 ++++++++++++++++- web/package.json | 4 + web/polkadot-app-deploy.config.ts | 16 + web/product-icon.png | Bin 0 -> 23535 bytes web/product-icon.svg | 13 + web/src/app/providers/SessionProvider.tsx | 12 +- web/src/app/providers/WalletProvider.tsx | 32 +- web/src/components/WalletModal.tsx | 77 +- .../features/productHost/productHost.test.ts | 53 + web/src/features/productHost/productHost.ts | 76 + web/src/features/rooms/roomState.test.ts | 4 + web/src/hooks/useArtistConsole.ts | 3 + web/src/hooks/useCatalog.ts | 4 +- web/src/hooks/useSession.ts | 21 +- web/src/hooks/useWallet.ts | 59 +- .../shared/config/deploymentSafety.test.ts | 28 + web/src/shared/config/deploymentSafety.ts | 14 + web/vite.product.config.ts | 31 + 44 files changed, 5002 insertions(+), 379 deletions(-) create mode 100644 docs/explanation/product-devnet-architecture.md create mode 100644 docs/operations/product-devnet-deployment.md create mode 100644 services/api/src/cors.test.ts create mode 100644 web/.env.product-devnet create mode 100644 web/polkadot-app-deploy.config.ts create mode 100644 web/product-icon.png create mode 100644 web/product-icon.svg create mode 100644 web/src/features/productHost/productHost.test.ts create mode 100644 web/src/features/productHost/productHost.ts create mode 100644 web/vite.product.config.ts diff --git a/.gitignore b/.gitignore index 3214ad8..1d6542e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,11 +8,13 @@ dist/ .playwright* !.env.example !web/.env.example +!web/.env.product-devnet !contracts/evm/.env.example web/node_modules/ web/dist/ web/dist-bulletin* +web/dist-product/ web/.playwright* web/playwright-report/ web/test-results/ diff --git a/README.md b/README.md index eed1f79..a4b2fe2 100644 --- a/README.md +++ b/README.md @@ -34,20 +34,23 @@ aura lights the whole field (`web/src/styles/aura.css`). creates one personal `SmartRuntime` per artist, and `ArtistDirectory` indexes artist addresses to their runtimes. -**Frontend**: Static React + Vite web app deployed to dot.li. +**Frontend**: Static React + Vite web app deployed to Netlify and, through the +Product profile, Bulletin/DotNS at `dotify.dot`. **WebRTC**: real-time music streaming. **Socket.IO**: signaling for room discovery and SDP/ICE exchange. A future iteration can move signaling to statement-store style infrastructure. -**Product SDK direction**: Dotify remains a standalone web app first. Product -SDK / Playground / Humanity work is a progressive-enhancement track documented -in -[`docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md`](docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md). -The current SDK snapshot is prototype/reference/unaudited and must be proven -against Dotify's Host, key-delivery, room, and contract constraints before it -becomes a production dependency. +**Product SDK direction**: Dotify now has an adaptive Product DevNet build for +`dotify.dot`. It keeps standalone link-first rooms and Free listening intact, +adds explicit app-scoped Product identity, and publishes through +Bulletin/DotNS. Product host signing is not yet accepted for contract writes or +protected key delivery; those boundaries remain passkey/EVM until the CDM/PAPI +and backend signature adapters are proven. See +[`docs/explanation/product-devnet-architecture.md`](docs/explanation/product-devnet-architecture.md) +and the +[`Product roadmap`](docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md). ## Deployed @@ -118,7 +121,8 @@ npm run dev | Variable | Required | Purpose | | --------------------------- | ---------------- | -------------------------------------------------------- | -| `API_ORIGIN` | Production | Frontend origin allowed by API CORS | +| `API_ORIGIN` | Compatibility | Singular frontend CORS origin fallback | +| `API_ORIGINS` | Production | Comma-separated exact frontend CORS origins | | `PASEO_ASSET_HUB_RPC` | Key requests | Paseo Asset Hub EVM RPC used for access checks | | `DOTIFY_DIRECTORY_ADDRESS` | Key requests | ArtistDirectory address used to resolve artist runtimes | | `DOTIFY_CHAIN_ID` | Key requests | Chain ID expected in wallet-signed key requests | @@ -430,9 +434,9 @@ handle: and decide whether a backend read-through gateway is needed. 4. Keep demo-mode browser-exposed Pinata/content secrets out of public deployments. -5. Run Product SDK feasibility spikes: Host detection, Product account signing, - resource allocation, Playground/Bulletin/DotNS deployment, and PolkaVM/CDM - contract portability. +5. Validate the Product host/account and Bulletin/DotNS deployment baseline, + then implement Product signature verification, resource allocation, and + PolkaVM/CDM contract portability. 6. Add a production artist dashboard on `/artists`: release drafts, edit metadata, royalty analytics, and profile verification state. 7. Deploy and monitor a public signaling server for DotNS / Bulletin builds. diff --git a/docs/README.md b/docs/README.md index 9b47fa3..f1fa94d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -15,6 +15,7 @@ Conceptual documents that help you understand why Dotify works the way it does. | [Content Protection](./explanation/content-protection.md) | All | Audio encryption pipeline, what it protects, and what it does not | | [Royalty Settlement](./explanation/royalty-settlement.md) | All | How DOT payments flow from listener wallet to artist wallet | | [Listening Rooms](./explanation/listening-rooms.md) | All | WebRTC peer-to-peer streaming, signaling protocol, known limitations | +| [Product DevNet Architecture](./explanation/product-devnet-architecture.md) | Maintainers | Dual-host boundaries, Product account capabilities, rooms, storage, and the proposed contract port | --- @@ -40,6 +41,7 @@ Runbooks for hosted configuration and production validation. | Document | Summary | |---|---| | [Deployment Configuration](./operations/deployment-configuration.md) | Netlify and Fly dashboard settings, secrets, catalog persistence, validation, and the update checklist for future env/config changes | +| [Product DevNet Deployment](./operations/product-devnet-deployment.md) | Build, publish, validate, and roll back the `dotify.dot` Product DevNet app | --- diff --git a/docs/backlog/24-access-streaming-v2.md b/docs/backlog/24-access-streaming-v2.md index 556fccd..1267a60 100644 --- a/docs/backlog/24-access-streaming-v2.md +++ b/docs/backlog/24-access-streaming-v2.md @@ -139,12 +139,14 @@ P3 first vertical slice delivered (`agent/audio-v2-p3`): the browser/device validation matrix, startup telemetry export, and the backend read-through gateway decision. -Product SDK replanning note (2026-07-14): +Product SDK adaptation note (2026-07-26): -- Product SDK (`@parity/product-sdk` 0.17.0 at - `2f359bba28ca72855207a0a519d4118b37b4438c`) is prototype/reference/unaudited. +- Product SDK 0.19.1 and deploy tooling 0.13.1 remain + prototype/reference/unaudited. - Host APIs are progressive enhancement for Product containers; standalone web remains a supported mode. +- Host detection, explicit Product account identity, a Product DevNet build, + canonical room links, and dual-origin Fly configuration are implemented. - Product SDK contracts use `pallet-revive`, PolkaVM artifacts, and CDM manifests. Dotify's current Hardhat + viem + Paseo Asset Hub EVM path needs a portability spike before adopting that layer. diff --git a/docs/backlog/README.md b/docs/backlog/README.md index 5afea40..8dec0ef 100644 --- a/docs/backlog/README.md +++ b/docs/backlog/README.md @@ -104,18 +104,18 @@ ticket 18 preview assets are consciously retired by access model v2. `improvement-plan.md` tracks the July 2026 review of the implementation against the product/technical/philosophical memory and the current Parity Product SDK direction. The plan is now dual-mode: standalone web remains the -first public listening path, while Product SDK / Playground / Humanity -integration is a gated feasibility track. Nothing in that track may imply live -Host, Statement Store, Product account, Humanity, or `.dot` deployment support -until the relevant spike proves the current API, environment, and security -boundary. +first public listening path, while the Product DevNet build adds `dotify.dot`, +explicit Host detection, app-scoped Product identity, and canonical +Product-origin room links. It does not imply Product-signed contract writes, +protected key access, Statement Store rooms, or Humanity decisions; those +remain gated until their adapters prove the current API and security boundary. The Product SDK evidence snapshot used for this replanning is -`paritytech/product-sdk@2f359bba28ca72855207a0a519d4118b37b4438c` -(`@parity/product-sdk` 0.17.0), fetched on 2026-07-14. It is explicitly -prototype / reference / unaudited code. Paseo and Summit are the live preset -environments; Product SDK contracts target `pallet-revive` / PolkaVM CDM flows, -not Dotify's current viem + EVM RPC path; Statement Store is useful for small +`@parity/product-sdk` 0.19.1 and +`@polkadot-community-foundation/polkadot-app-deploy` 0.13.1, +verified on 2026-07-26. They remain prototype / reference / unaudited code. +Product SDK contracts target `pallet-revive` / PolkaVM CDM flows, not Dotify's +current viem + EVM RPC write path; Statement Store is useful for small ephemeral presence, not full chat, SDP/ICE, durable media metadata, or guest reactions. @@ -160,9 +160,9 @@ on `main`. The remaining order is: signaling and production-env evidence are closed through #36/#37. 3. Improve room resilience and shared-listening depth only where it preserves the link-first guest doctrine. -4. Run Product SDK feasibility spikes: Host capability detection, Product - account signing, resource allocation, PolkaVM/CDM contract portability, - Playground/Bulletin/DotNS deployment, and Statement Store presence. +4. Validate the delivered Product host/account and Bulletin/DotNS baseline, + then port writes through CDM/PAPI, add backend Product-signature + verification, and run bounded resource-allocation/Statement Store spikes. 5. Build live Humanity / Individuality only after the research ticket proves a privacy-preserving source, proof shape, address-binding story, and fallback UX. diff --git a/docs/backlog/improvement-plan.md b/docs/backlog/improvement-plan.md index 49937b0..23fd81f 100644 --- a/docs/backlog/improvement-plan.md +++ b/docs/backlog/improvement-plan.md @@ -62,25 +62,24 @@ Where it falls short of its own standards: ## Product SDK feasibility track -This track runs in parallel with standalone hardening, but it does not block -first sound and must not be sold as a delivered capability. +This track runs in parallel with standalone hardening and does not block first +sound. Only the baseline rows marked delivered may be presented as live. Product SDK snapshot used for this plan: -- `paritytech/product-sdk@2f359bba28ca72855207a0a519d4118b37b4438c` - (fetched 2026-07-14); -- `@parity/product-sdk` 0.17.0; +- `@parity/product-sdk` 0.19.1 (verified 2026-07-26); +- `@polkadot-community-foundation/polkadot-app-deploy` 0.13.1; - explicit prototype / reference / unaudited status; -- live preset environments: Paseo and Summit; +- Product target: DevNet Asset Hub / People / Bulletin; - contracts package: `pallet-revive`, PolkaVM artifacts, and CDM manifests; - Statement Store: 512-byte statement payload, 1024-byte user total, default 30-second TTL. | Item | Tracking | Status | | --- | --- | --- | -| Product SDK baseline: pin SDK versions, document compatible Host surfaces, and add feature detection for Host local storage, signing, permissions, resource allocation, payments, and chain support. | #85, `polkadot-product-readiness-and-killer-dapp-roadmap.md` | Proposed | +| Product SDK baseline: pin SDK versions, detect Host availability, connect an app-scoped account explicitly, and separate presence identity from EVM signing authority. | #85, `polkadot-product-readiness-and-killer-dapp-roadmap.md` | Delivered on Product adaptation branch | | Contract portability spike: compare Dotify's current Paseo Asset Hub EVM / viem / Hardhat flow with Product SDK contracts on `pallet-revive`, PolkaVM artifacts, and CDM manifests. | #85 | Proposed | -| Playground deployment spike: determine whether Dotify's static build can use Playground/Bulletin/DotNS deploy flows without weakening current secret and publication boundaries. | #85 | Proposed | +| Product deployment baseline: build a browser-safe multi-file bundle, publish through Bulletin/DotNS tooling, preserve backend key custody, and use a canonical public room URL. | #85 | Delivered on Product adaptation branch; live publication pending operator credentials | | Statement Store presence spike: use it for small, signed, ephemeral discovery/presence only. Do not move SDP/ICE, full chat history, media metadata, or link-only guest reactions there until signer, TTL, and size constraints are solved. | #89, `20-room-social-layer.md`, `21-room-collaborative-queue.md` | Proposed | | Humanity / Individuality research rewrite: prove the canonical live source, privacy-preserving proof shape, product-account/identity-account binding, and fallback UX before promoting Human free from research to build. | #12, `11-proof-of-personhood-integration-research.md` | Open | diff --git a/docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md b/docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md index d6d497f..1a8daab 100644 --- a/docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md +++ b/docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md @@ -1,15 +1,16 @@ # Polkadot product readiness and killer dapp roadmap -Status: active planning note, supersedes the stale draft from PR #91. +Status: active execution note; the Product DevNet baseline is implemented on +`feat/product-devnet-adaptation`. -Last Product SDK verification: 2026-07-14 against -`paritytech/product-sdk@2f359bba28ca72855207a0a519d4118b37b4438c` -(`@parity/product-sdk` 0.17.0). +Last Product SDK verification: 2026-07-26 against +`@parity/product-sdk` 0.19.1 and +`@polkadot-community-foundation/polkadot-app-deploy` 0.13.1. ## Verdict -Dotify should align with the Polkadot product ecosystem, but it should not -replace its standalone production path with Product SDK assumptions yet. +Dotify should align with the Polkadot product ecosystem without replacing its +standalone production path with Product SDK assumptions. The right product shape is dual-mode: @@ -23,6 +24,18 @@ The right product shape is dual-mode: product failure state. It must not fall back to demo secrets, hidden signers, or bypassed access checks. +The first adaptive slice is now implemented: + +- a separate Product DevNet build and `dotify.dot` manifest; +- explicit Host detection and app-scoped Product account connection; +- Product identity for room presence without claiming EVM/EIP-191 authority; +- canonical `.dev-dot.li` room links; +- shared Fly API/signaling allowlists for Netlify and Product origins; +- a pinned build/deploy workflow and operator rollback guide. + +Contract writes, Product-signed key requests, Product personhood, and Product +presence transport remain gated follow-up work. + ## Product ecosystem evidence The current Parity product direction is coherent: Levity for publishing, @@ -35,9 +48,8 @@ The SDK details matter for Dotify: - Product SDK and Playground are explicitly prototype / reference / unaudited code. -- Product SDK preset chains are live for Paseo and Summit. Polkadot and Kusama - preset paths are gated because Bulletin / Individuality descriptors are not - live there. +- Product DevNet exposes the Asset Hub, People, and Bulletin system-chain + topology used by the current Product tooling. - Product SDK contract helpers target `pallet-revive`, PolkaVM artifacts, and CDM manifests. Dotify currently uses Hardhat Solidity, generated EVM ABIs, viem, and Paseo Asset Hub EVM RPCs. @@ -131,24 +143,27 @@ Goal: deepen rooms without breaking the room-guest doctrine. Goal: prove the Product host path with small spikes before committing the app. -- Pin Product SDK versions and add a compatibility matrix. -- Detect Host availability and supported chain/capability surfaces. -- Prototype Product account connection, signing, identity prompt behavior, and - resource allocation. +- Delivered: pin Product SDK/deploy versions and add a compatibility matrix. +- Delivered: detect Host availability without blocking standalone first sound. +- Delivered: connect the app-scoped Product account only on explicit action and + separate identity capability from EVM signing capability. +- Delivered: publishable Bulletin/DotNS build and dual-origin Fly boundary. +- Remaining: prototype host transaction signing and resource allocation. - Compare Dotify's Hardhat/EVM runtime with Product SDK PolkaVM/CDM contracts. -- Prototype Playground deployment against Dotify's single-file build and secret - boundary. - Prototype Statement Store presence with strict payload, TTL, and signer limits. ### Phase 4 - Product integration -Goal: ship Product mode as progressive enhancement. +Goal: deepen the delivered Product mode one adapter at a time. -- Add Product-mode adapters behind explicit ports, leaving standalone adapters - intact. -- Use Host signing and Product accounts only when the Host path is available. -- Surface Host permission denial as actionable UI state. +- Delivered: keep standalone adapters intact and lazy-load Product host code. +- Delivered: use the Product account as presence identity only when available. +- Delivered: surface host absence and unsupported signer boundaries explicitly. +- Next: extract typed runtime read/write ports and add a generated CDM/PAPI + adapter. +- Next: add a backend signature-scheme adapter that verifies Product account + signatures and address binding before key delivery. - Keep backend key delivery authoritative unless a Product-host design proves a stronger key-custody boundary. - Keep `.dot`/Playground deployment separate from access enforcement. @@ -219,8 +234,9 @@ Recommended Project 5 fields: - #36: closed after hosted signaling operation evidence. - #37: closed after #99 and manually checked deploy-host production env evidence. -- #85: split into Product SDK baseline, contract portability, Playground deploy, - Statement Store presence, and integration adapter spikes. +- #85: Product SDK baseline and Product DevNet deployment slice implemented; + keep open for contract portability, backend Product signatures, resource + allocation, and bounded Statement Store presence. - #86: implementation active on `codex/86-catalog-read-model`; keep In Progress until review and public performance evidence close the warm/cold budgets. - #87: keep for responsive cover/gateway pipeline. diff --git a/docs/design/dotify-v2-access-and-streaming.md b/docs/design/dotify-v2-access-and-streaming.md index 19bb0ab..8927c7c 100644 --- a/docs/design/dotify-v2-access-and-streaming.md +++ b/docs/design/dotify-v2-access-and-streaming.md @@ -390,7 +390,7 @@ Dotify mapping: | Product SDK / Host API | Replace bespoke chain, signing, storage, and permission glue only where the SDK gives equivalent or better behavior. | | Proof of Personhood | Replace the current admin/personhood mock with the live verified-human source for `human-free`. | | Coinage | Candidate future payment rail for paid access; EVM runtime remains the settlement record until Coinage design is explicit. | -| DotNS | Keep `dotify.dot.li` / `.dot` resolution aligned with the Bulletin single-file build. | +| DotNS | Publish the Product profile as `dotify.dot` / `https://dotify.dev-dot.li`; keep the legacy single-file path separate. | | Bulletin Chain | Continue as a publication and availability layer for product bundles and manifests. | | Statement Store | Future presence/chat/room-discovery layer; Socket.IO remains SDP/ICE relay until a separate migration is designed. | diff --git a/docs/explanation/architecture-overview.md b/docs/explanation/architecture-overview.md index 13d95e2..7816fe4 100644 --- a/docs/explanation/architecture-overview.md +++ b/docs/explanation/architecture-overview.md @@ -174,4 +174,7 @@ The signaling server is a lightweight Socket.IO process (`server/signaling.mjs`) - Your payments — they go directly to your EVM address via smart contract. - Your track records — they live on Paseo Asset Hub (and optionally Bulletin Chain). -The frontend is itself distributed via IPFS/DotNS at `dotify.dot.li`. +The standalone frontend is deployed through Netlify. The Product DevNet build +is publishable through Bulletin/DotNS as `dotify.dot` and resolves publicly at +`https://dotify.dev-dot.li`; the older `dotify.dot.li` artifact remains legacy +deployment evidence. diff --git a/docs/explanation/product-devnet-architecture.md b/docs/explanation/product-devnet-architecture.md new file mode 100644 index 0000000..b2c09fc --- /dev/null +++ b/docs/explanation/product-devnet-architecture.md @@ -0,0 +1,209 @@ +# Product DevNet Architecture + +## Decision + +Dotify uses an adaptive dual-host architecture: + +- the standalone Netlify app remains a complete public entry point; +- the Product DevNet build publishes the same listener and room experience as + `dotify.dot`; +- Product-host capabilities are added through explicit adapters; +- a missing or denied host capability never enables a demo secret, hidden + signer, or weaker access path. + +This keeps Dotify's north star intact. A guest can still follow a room link and +hear a host without first adopting wallet infrastructure. An artist's access +policy and protected source remain authoritative regardless of which frontend +host serves the app. + +## Why The Host Is An Adapter + +The Product environment and Dotify's existing runtime do not expose the same +signing contract. + +The Product SDK returns an app-scoped account and a PAPI `PolkadotSigner`. +Dotify's deployed contract writes and content-key requests currently use viem, +EIP-1193, and EIP-191. Treating those signers as interchangeable would either +fail at runtime or create an unverifiable access claim. + +The first Product adaptation therefore uses the host account for: + +- an explicit, user-initiated Product account connection; +- an SS58 account for display and future Product-native adapters; +- a derived H160 address for local room-name persistence and read-only + runtime/catalog correlation. + +It does not use that account for: + +- Classic payments; +- artist runtime creation or release publication; +- protected content-key requests; +- Bulletin artist publication through the existing PAPI v1 integration. + +Those actions continue to require the existing passkey or EVM wallet until the +chain and backend adapters described below are delivered. + +## Runtime Topology + +```text +Standalone browser Product host +https://muzinga.netlify.app https://dotify.dev-dot.li + | | + +---------------+----------------------+ + | + same Dotify frontend + | + +-----------+-----------+ + | | + dotify-api.fly.dev dotify-signal.fly.dev + catalog, uploads, room discovery, SDP/ICE, + access, content keys chat and presence + | | + +-----------+-----------+ + | + Product DevNet Asset Hub + existing Dotify runtimes +``` + +The Product build is a normal relative-path Vite bundle. `pad` publishes its +files to Bulletin and binds the result to DotNS. Keeping multiple static chunks +allows incremental uploads; the older single-file Bulletin build remains +available for its original workflow. + +The two frontend origins share the same Fly services. `API_ORIGINS` and +`SIGNAL_ORIGINS` are explicit comma-separated allowlists. This is required for +cross-origin catalog reads, key requests, Socket.IO, and WebRTC signaling. + +## Capability Matrix + +| Capability | Standalone | Product build now | Product-native target | +| --- | --- | --- | --- | +| Browse catalog | Fly cache + EVM RPC | Same | Host-routed read adapter where it improves reliability | +| Play Free track | No wallet | No wallet | Same | +| Join room link | No wallet | No wallet | Same | +| Host room | Socket.IO + WebRTC | Same | Keep until a multiparty replacement proves equivalent UX | +| Product identity | Not applicable | App-scoped SS58/H160 | Host identity with explicit capability grants | +| Classic payment | Passkey/EVM wallet | Passkey/EVM wallet | CDM/PAPI write adapter | +| Protected key request | EIP-191 | EIP-191 | Backend-verified Product signature scheme | +| Artist publication | viem/EVM | viem/EVM | Generated CDM contract adapter | +| Personhood | Current on-chain policy source | No new claim | Privacy-preserving Product proof after verification | +| Static delivery | Netlify | Bulletin + DotNS | Bulletin + DotNS | + +## Rooms Stay Host-Neutral + +Rooms are a product primitive, not a deployment detail. The current signaling +service supports anonymous discovery, one host with multiple listeners, +short-lived chat/reactions/requests, and WebRTC negotiation. Product messaging +and Statement Store do not currently provide a verified drop-in replacement +for that wallet-free multiparty flow. + +The Product build therefore keeps the Socket.IO/WebRTC room layer. It adds one +important boundary: `VITE_PUBLIC_APP_URL` makes every copied room link point to +the public `.dev-dot.li` origin rather than an internal container or content +gateway URL. + +A future Product-native presence spike may mirror a compact host-signed +heartbeat into Statement Store. It must not carry SDP, ICE candidates, audio, +durable chat, or source keys, and it must remain optional for guests. + +## Storage Boundaries + +Product static hosting replaces the web server for the Product build. It does +not replace: + +- Pinata-backed artist uploads; +- DAV2 audio encryption; +- backend-held `CONTENT_KEY_MASTER_SECRET`; +- server-side access verification; +- the durable catalog snapshot. + +Product cloud storage is host-scoped and experimental. Moving encrypted media +or key custody there requires a separate threat model, Range/startup evidence, +and a recovery plan. Until then, Fly remains the security boundary and IPFS +gateways remain the delivery boundary. + +## Proposed Contract Port + +The next contract phase should split the current integration into two typed +ports rather than add Product conditionals throughout feature hooks: + +```text +RuntimeReadPort + listArtists() + listReleases() + getAccessDecision() + getRoyaltyState() + +RuntimeWritePort + createArtistRuntime() + publishRelease() + setAccessMode() + payForAccess() +``` + +Adapters: + +- `ViemRuntimeAdapter`: current standalone EVM implementation; +- `ProductRuntimeAdapter`: generated CDM/ABI bindings submitted with the host + PAPI signer; +- `CatalogApiAdapter`: the existing server-side read model, shared by both + frontends. + +The backend authentication protocol must then gain an explicit signature +scheme field. A Product signature is accepted only after the server can bind +the signed payload, Product account public key, derived H160, chain, nonce, +purpose, and expiry. EIP-191 remains supported for standalone clients. Unknown +schemes fail closed. + +This avoids a second frontend business model and allows Product mode to replace +one infrastructure adapter at a time. + +## Permission And Failure Rules + +1. Host detection may run on startup; account access only runs after the user + chooses **Use Polkadot app**. +2. The integration does not request a username, identity proof, transaction + permission, or personhood proof before value is visible. +3. If the host is absent, catalog browsing, Free playback, and room links still + work. The wallet modal explains why the Product account is unavailable. +4. A Product account without an EVM signing adapter is not a protected + listener. Dotify passes no requester address to the key service. +5. A denied key, RPC failure, or unsupported signature never falls back to a + browser content secret. +6. The Product SDK and deploy tooling are prototype/reference dependencies. + Version changes require the compatibility checks below. + +## Compatibility Gate + +The initial baseline is: + +| Component | Pinned/target value | +| --- | --- | +| Node | 22 | +| `@parity/product-sdk` | `0.19.1` | +| `@polkadot-community-foundation/polkadot-app-deploy` | `0.13.1` in the deploy command | +| Product network | `devnet` | +| Product domain | `dotify.dot` | +| Public gateway | `https://dotify.dev-dot.li` | +| Asset Hub EVM chain ID | `420420417` | + +For every SDK or deploy-tool upgrade: + +1. verify host detection outside and inside the container; +2. connect the Product account only on explicit action; +3. verify SS58 and derived H160 stability; +4. run normal and Product builds; +5. join one room across Netlify and Product origins; +6. verify Free playback remains walletless; +7. verify protected actions still fail closed without a supported signer; +8. inspect the static bundle and npm audit delta; +9. update this document, the environment reference, and the deployment runbook. + +## Source References + +- [Product documentation](https://docs.polkadotcommunity.foundation/) +- [Build and publish guide](https://docs.polkadotcommunity.foundation/guides/build-and-publish/) +- [Platform Services SDK guide](https://docs.polkadotcommunity.foundation/guides/platform-services-sdk/) +- [Product network reference](https://docs.polkadotcommunity.foundation/reference/networks/) +- [Product identity architecture](https://docs.polkadotcommunity.foundation/architecture/identity/) +- [Product messaging architecture](https://docs.polkadotcommunity.foundation/architecture/messaging/) diff --git a/docs/index.html b/docs/index.html index 3b9ae43..ef25722 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1537,11 +1537,13 @@

Operate the spine and validate first sound

  • -

    Sequenced later

    -

    Product SDK, personhood, and cultural transmission

    +

    Adaptive Product path

    +

    Product DevNet now, sovereignty adapters next

    - Product SDK mode, Humanity/Individuality proofs, consented provenance, and ambassador - mechanics remain future work until the current APIs and privacy boundaries are proven. + Dotify now has a publishable dotify.dot build, explicit app-scoped Product + identity, and public room links that preserve wallet-free entry. CDM/PAPI contract writes, + Product-signed key requests, Humanity/Individuality proofs, consented provenance, and + ambassador mechanics remain sequenced behind verified security and privacy boundaries.

  • @@ -1601,11 +1603,20 @@

    Explore the project

    +
  • + + + Product DevNet architecture + What the Product host adapts now, what remains on Fly, and how contract signing ports next. + + + +
  • Product SDK roadmap - How Dotify aligns with Product SDK, Playground, Statement Store, and Humanity. + The delivered Product baseline and the remaining CDM, signature, presence, and Humanity work. diff --git a/docs/operations/deployment-configuration.md b/docs/operations/deployment-configuration.md index a6c239f..e825ebb 100644 --- a/docs/operations/deployment-configuration.md +++ b/docs/operations/deployment-configuration.md @@ -1,7 +1,7 @@ # Deployment Configuration Runbook This runbook is the operator checklist for Dotify's hosted configuration across -Netlify and Fly.io. Use it when changing dashboard values, deploy contexts, +Netlify, Product DevNet, and Fly.io. Use it when changing dashboard values, deploy contexts, `*.toml` settings, hosted origins, secrets, catalog persistence, or production smoke settings. @@ -30,16 +30,18 @@ Keep this document aligned with | Surface | Host | App/project | Source config | Purpose | | --- | --- | --- | --- | --- | | Frontend | Netlify | `muzinga` | `netlify.toml` | Static Vite web app | +| Product frontend | Bulletin + DotNS | `dotify.dot` | `web/.env.product-devnet`, `web/polkadot-app-deploy.config.ts` | Product-host static app | | Backend API | Fly.io | `dotify-api` | `services/api/fly.toml` | Uploads, key delivery, catalog read model, health | | Signaling | Fly.io | `dotify-signal` | `web/fly.signal.toml` | Socket.IO room discovery and WebRTC signaling | Production URLs currently assumed by the app and docs: ```txt -Frontend: https:// +Standalone: https://muzinga.netlify.app +Product: https://dotify.dev-dot.li Backend API: https://dotify-api.fly.dev Signaling: https://dotify-signal.fly.dev -IPFS gateway: https://paseo-ipfs.polkadot.io +Product IPFS: https://devnet-ipfs.api.polkadotcommunity.foundation Asset Hub RPC: https://eth-rpc-testnet.polkadot.io/ ``` @@ -94,6 +96,7 @@ Required production variables: | Key | Value | Notes | | --- | --- | --- | | `VITE_DOTIFY_DEPLOYMENT` | `production` | Enables fail-closed production env validation. | +| `VITE_DOTIFY_HOST_MODE` | `off` | Prevents the standalone build from probing Product host APIs. | | `VITE_SIGNAL_URL` | `https://dotify-signal.fly.dev` | Public Socket.IO signaling origin. | | `VITE_DOTIFY_API_URL` | `https://dotify-api.fly.dev` | Backend API for uploads, key delivery, and cached catalog reads. | | `VITE_PINATA_GATEWAY` | `https://paseo-ipfs.polkadot.io` | Primary browser read gateway. | @@ -115,10 +118,42 @@ Optional production variables: Deploy-preview note: Netlify deploy previews usually have their own origin. The signaling service -can allow multiple origins with `SIGNAL_ORIGINS`, but the backend API currently -accepts one `API_ORIGIN`. For PR evidence, use a stable frontend origin, a -dedicated staging site, or temporarily set `API_ORIGIN` to the deploy-preview -origin and restore it after validation. +and backend both allow multiple exact origins with `SIGNAL_ORIGINS` and +`API_ORIGINS`. Add only the specific preview origin needed for evidence, then +remove it after validation. Never use `*` on the backend. + +## Product DevNet Frontend + +The browser-safe Product build profile is tracked in +`web/.env.product-devnet`. The manifest is +`web/polkadot-app-deploy.config.ts`. + +Required Product values: + +| Key | Current value | +| --- | --- | +| `VITE_DOTIFY_DEPLOYMENT` | `production` | +| `VITE_DOTIFY_HOST_MODE` | `required` | +| `VITE_DOTIFY_PRODUCT_ID` | `dotify.dot` | +| `VITE_PUBLIC_APP_URL` | `https://dotify.dev-dot.li` | +| `VITE_DOTIFY_API_URL` | `https://dotify-api.fly.dev` | +| `VITE_SIGNAL_URL` | `https://dotify-signal.fly.dev` | + +`VITE_PINATA_JWT` and `VITE_CONTENT_SECRET` are explicitly empty in that +profile so a developer's generic local `.env` cannot leak demo credentials +into the Product bundle. + +Build and publication: + +```bash +cd web +npm run build:product-devnet +npm run deploy:product-devnet +``` + +Use +[`docs/operations/product-devnet-deployment.md`](product-devnet-deployment.md) +for authentication, publication, validation, and rollback. ## Fly Backend API @@ -136,6 +171,7 @@ Non-secret runtime values are tracked in `services/api/fly.toml`: | --- | --- | | `API_PORT` | `8790` | | `NODE_ENV` | `production` | +| `API_ORIGINS` | `https://muzinga.netlify.app,https://dotify.dev-dot.li` | | `PASEO_ASSET_HUB_RPC` | `https://eth-rpc-testnet.polkadot.io/` | | `DOTIFY_FACTORY_ADDRESS` | `0xbd1a11cfce8b5ef7a37e507bc5109895f8f42a72` | | `DOTIFY_DIRECTORY_ADDRESS` | `0xcf1534c6e2b0e43b9436c1e86a076466dc0f2108` | @@ -145,7 +181,6 @@ Set server-side values in the app's Secrets area: | Secret | Required | Notes | | --- | --- | --- | -| `API_ORIGIN` | Production | Exact frontend origin allowed by API CORS. One URL only. | | `PINATA_JWT` | Uploads | Backend-only Pinata token. Never expose in Netlify. | | `CONTENT_KEY_MASTER_SECRET` | Audio upload and key delivery | 64+ hex chars, at least 32 random bytes. Do not rotate casually. | | `GIT_COMMIT_SHA` | Optional | Set by CI/build automation when available; `/version` can fall back in dev checkouts. | @@ -188,12 +223,12 @@ Non-secret runtime values are tracked in `web/fly.signal.toml`: | `SIGNAL_ROOM_TTL_MS` | `21600000` | | `SIGNAL_HOST_TIMEOUT_MS` | `120000` | | `SIGNAL_MAX_LISTENERS` | `24` | +| `SIGNAL_ORIGINS` | `https://muzinga.netlify.app,https://dotify.dev-dot.li` | -Set hosted frontend origins in the app's Secrets area: - -| Secret | Value | -| --- | --- | -| `SIGNAL_ORIGINS` | Exact comma-separated frontend origins, for example `https://muzinga.netlify.app,https://` | +The production origins are public configuration tracked in +`web/fly.signal.toml`; they are not secrets. Temporary preview origins may be +set through Fly configuration, but the tracked production allowlist must be +restored after validation. Keep `dotify-signal` on one active machine until a shared Socket.IO adapter is added. Rooms, chat, reactions, request queues, and solo-presence aggregates are @@ -227,8 +262,13 @@ curl -s https://dotify-signal.fly.dev/status cd web npm run smoke:production-env npm run smoke:signal -- --url https://dotify-signal.fly.dev --origin https:// +npm run build:product-devnet ``` +6. For a Product release, complete the cross-origin room and host-account +checks in +[`docs/operations/product-devnet-deployment.md`](product-devnet-deployment.md). + 6. For explicit origin rejection evidence, include a denied origin: ```bash diff --git a/docs/operations/product-devnet-deployment.md b/docs/operations/product-devnet-deployment.md new file mode 100644 index 0000000..ffce4fc --- /dev/null +++ b/docs/operations/product-devnet-deployment.md @@ -0,0 +1,174 @@ +# Deploy Dotify To Product DevNet + +This runbook publishes the Product build to Bulletin/DotNS and connects it to +the existing Fly API and signaling services. It does not deploy contracts or +change production secrets. + +## Prerequisites + +- Node.js 22 and npm 10+ +- a clean build from the intended commit +- access to the `dotify.dot` deployment account +- Fly access for `dotify-api` and `dotify-signal` +- the current `@polkadot-community-foundation/polkadot-app-deploy` DevNet prerequisites + +The CLI is reference/experimental tooling. Do not store a mnemonic in the +repository, shell history, `.env` files, Netlify, or Fly. + +Before the first publish, the signing account also needs: + +- DevNet native tokens on Asset Hub; +- an EVM account mapping (`dotns account map --env devnet`); +- a live Bulletin storage authorization for the same SS58 account; +- ownership of `dotify.dot`, or eligibility to register it during deploy. + +Bulletin authorization is a finite quota and may expire. A deploy that starts +failing at the upload stage after previously working should recheck that quota. +See the official +[build and publish guide](https://docs.polkadotcommunity.foundation/guides/build-and-publish/) +for the current faucet, storage console, mapping, and DotNS registration steps. + +## 1. Verify The Fly Origin Boundary + +The tracked Fly configuration must contain: + +```txt +API_ORIGINS=https://muzinga.netlify.app,https://dotify.dev-dot.li +SIGNAL_ORIGINS=https://muzinga.netlify.app,https://dotify.dev-dot.li +``` + +Deploy both services before publishing the frontend: + +```bash +cd services/api +flyctl deploy -c fly.toml + +cd ../../web +flyctl deploy -c fly.signal.toml +``` + +Keep backend secrets unchanged. `API_ORIGINS` supersedes singular +`API_ORIGIN`; the latter remains only as a compatibility fallback. + +## 2. Verify The Browser-Safe Build Profile + +Review `web/.env.product-devnet`. It must contain only public endpoints and +identifiers. In particular: + +```txt +VITE_DOTIFY_HOST_MODE=required +VITE_DOTIFY_PRODUCT_ID=dotify.dot +VITE_PUBLIC_APP_URL=https://dotify.dev-dot.li +VITE_DOTIFY_API_URL=https://dotify-api.fly.dev +VITE_SIGNAL_URL=https://dotify-signal.fly.dev +VITE_PINATA_JWT= +VITE_CONTENT_SECRET= +``` + +`VITE_PUBLIC_APP_URL` is the URL copied for room invitations. Do not replace it +with an internal host URL or a raw CID gateway. + +## 3. Build Locally + +```bash +cd web +npm ci +npm run test:unit +npm run build:product-devnet +``` + +Expected output is `web/dist-product`. The production guard must fail if a +browser upload token or content secret is present. + +## 4. Authenticate The Deploy Tool + +The repository pins the CLI version in the npm deploy command but does not add +the experimental deploy tool to the application dependency tree. + +```bash +npx --yes --package @polkadot-community-foundation/polkadot-app-deploy@0.13.1 pad login --env devnet +npx --yes --package @polkadot-community-foundation/polkadot-app-deploy@0.13.1 pad whoami --env devnet +``` + +Follow the mobile-wallet flow. Confirm the selected account owns, or can +receive, `dotify.dot` and satisfies the DevNet registration/funding rules. + +## 5. Publish + +```bash +npm run deploy:product-devnet +``` + +The command: + +1. rebuilds `dist-product`; +2. validates `polkadot-app-deploy.config.ts`; +3. creates content-addressed chunks with the JavaScript merkle implementation; +4. uploads changed content to Product DevNet Bulletin; +5. binds `dotify.dot`; +6. writes the Product manifest and executable records. + +Publisher listing is deliberately not part of the default deploy. It requires +the current Product proof-of-personhood level and signer support, and the +0.13.1 CLI help still describes environment-specific limitations. After the +app URL is verified, follow the current official **List it in Browse** guide +and record that result separately. A listing failure must not obscure a +successful static deployment. + +Record the commit, CLI version, resulting CID, DotNS transaction references, +and final public URL in the release evidence. + +## 6. Validate + +Check service CORS from both origins: + +```bash +curl -s -D - -o /dev/null \ + -H 'Origin: https://dotify.dev-dot.li' \ + https://dotify-api.fly.dev/health + +curl -s -D - -o /dev/null \ + -H 'Origin: https://muzinga.netlify.app' \ + https://dotify-api.fly.dev/health +``` + +Then verify in the Product host: + +1. `https://dotify.dev-dot.li` opens and shows catalog tracks. +2. Free playback starts without connecting an account. +3. **Use Polkadot app** connects an app-scoped Product account only after the + button is selected. +4. A protected track asks for a passkey/EVM wallet; it does not release a key + through the Product identity. +5. A Product-origin host creates a room and copies a + `https://dotify.dev-dot.li/#/rooms/` link. +6. A wallet-free browser joins that link from outside the Product host. +7. A Netlify-origin host and Product-origin guest also connect. +8. Closing the host ends the room as before. + +Inspect the browser console and Fly logs for CORS, catalog, Socket.IO, and +WebRTC failures. + +## Rollback + +The Product deployment is static. To roll back: + +1. switch to the last known-good commit; +2. run `npm ci`; +3. run the full build and smoke checks; +4. republish with `npm run deploy:product-devnet`; +5. confirm DotNS resolves to the restored content; +6. record the replacement CID and incident reason. + +Do not roll back Fly origin allowlists while either public frontend remains +active. + +## Known Limits + +- Product account signing is identity/presence only in this phase. +- Contract writes and key requests still require passkey/EVM signing. +- Rooms still depend on one in-memory Fly signaling machine. +- Product-host cloud storage does not hold Dotify audio or content keys. +- Product personhood is not yet an access decision source. +- A durable `CATALOG_SNAPSHOT_PATH` remains recommended for production-grade + catalog recovery but is not required for API startup. diff --git a/docs/reference/environment-variables.md b/docs/reference/environment-variables.md index e255b55..1465ca3 100644 --- a/docs/reference/environment-variables.md +++ b/docs/reference/environment-variables.md @@ -36,6 +36,54 @@ production build contract without printing real secret values. --- +### `VITE_DOTIFY_HOST_MODE` + +| Property | Value | +| ------------ | ------------------------------ | +| **Type** | `off`, `auto`, or `required` | +| **Required** | Product builds | +| **Default** | `off` | +| **Example** | `required` | + +Controls Product host discovery. `off` keeps the standalone app independent +from the Product SDK. `auto` enables progressive host detection. `required` +marks a Product-targeted build but does not block catalog, Free playback, or +wallet-free room entry when opened outside the host. + +Host detection does not request an account. The account is requested only when +the listener selects **Use Polkadot app**. + +--- + +### `VITE_DOTIFY_PRODUCT_ID` + +| Property | Value | +| ------------ | ---------------------- | +| **Type** | Lowercase `.dot` name | +| **Required** | Host mode is not `off` | +| **Default** | `dotify.dot` | +| **Example** | `dotify.dot` | + +DotNS identifier used by the Product host to derive Dotify's app-scoped +account. Changing it changes the Product account boundary and requires an +identity/access migration review. + +--- + +### `VITE_PUBLIC_APP_URL` + +| Property | Value | +| ------------ | -------------------------------- | +| **Type** | HTTPS URL | +| **Required** | Product production builds | +| **Default** | Current browser URL | +| **Example** | `https://dotify.dev-dot.li` | + +Canonical public origin used when copying room links. Product builds must set +this so invitations never expose an internal host/container or raw gateway URL. + +--- + ### `VITE_DOTIFY_DEBUG_PANEL` | Property | Value | @@ -246,7 +294,7 @@ Network interface to bind. | **Type** | Comma-separated URL list or `*` | | **Required** | No | | **Default** | `*` | -| **Example** | `https://muzinga.netlify.app,https://dotify.dot.li` | +| **Example** | `https://muzinga.netlify.app,https://dotify.dev-dot.li` | CORS allowed origins for Socket.IO and status endpoints. Set explicit frontend origins in production. `SIGNAL_ORIGIN` is still accepted as a backwards-compatible @@ -327,7 +375,23 @@ Port the backend API listens on. | **Required** | Production | | **Default** | `http://localhost:5273` | -Frontend origin allowed by backend CORS. +Singular frontend origin allowed by backend CORS. This remains as a +backwards-compatible fallback when `API_ORIGINS` is not set. + +--- + +### `API_ORIGINS` + +| Property | Value | +| ------------ | -------------------------------------------------------- | +| **Type** | Comma-separated HTTPS origin list | +| **Required** | Multiple hosted frontends | +| **Default** | The single `API_ORIGIN` value | +| **Example** | `https://muzinga.netlify.app,https://dotify.dev-dot.li` | + +Exact frontend origins accepted by backend CORS. When set, it takes precedence +over `API_ORIGIN`. Do not use `*`: the API carries authenticated upload and +content-key routes. --- diff --git a/services/api/.env.example b/services/api/.env.example index b86aba5..8d58c7d 100644 --- a/services/api/.env.example +++ b/services/api/.env.example @@ -6,6 +6,8 @@ API_PORT=8790 # Frontend origin allowed by CORS. API_ORIGIN=http://localhost:5273 +# Comma-separated origins take precedence over API_ORIGIN when set. +# API_ORIGINS=https://muzinga.netlify.app,https://dotify.dev-dot.li # Paseo Asset Hub EVM RPC. Required for wallet-signed content-key requests: # the key route resolves the owning artist runtime via the directory and calls diff --git a/services/api/fly.toml b/services/api/fly.toml index 6b061eb..734f35a 100644 --- a/services/api/fly.toml +++ b/services/api/fly.toml @@ -10,6 +10,7 @@ primary_region = "ams" # checks target the owner-guarded factory/directory pair. API_PORT = "8790" NODE_ENV = "production" + API_ORIGINS = "https://muzinga.netlify.app,https://dotify.dev-dot.li" PASEO_ASSET_HUB_RPC = "https://eth-rpc-testnet.polkadot.io/" DOTIFY_FACTORY_ADDRESS = "0xbd1a11cfce8b5ef7a37e507bc5109895f8f42a72" DOTIFY_DIRECTORY_ADDRESS = "0xcf1534c6e2b0e43b9436c1e86a076466dc0f2108" diff --git a/services/api/package.json b/services/api/package.json index 65f0f21..72eefec 100644 --- a/services/api/package.json +++ b/services/api/package.json @@ -12,7 +12,7 @@ "start": "node dist/index.js", "catalog:reindex": "tsx src/scripts/reindexCatalog.ts", "typecheck": "tsc --noEmit", - "test": "node --import tsx --test src/services/audioV2.test.ts src/services/replayProtection.test.ts src/services/signatures.test.ts src/services/sessionTokens.test.ts src/services/catalog/readModel.test.ts src/routes/keys.test.ts src/routes/uploads.test.ts src/routes/auth.test.ts src/routes/health.test.ts src/routes/catalog.test.ts src/app.test.ts" + "test": "node --import tsx --test src/services/audioV2.test.ts src/services/replayProtection.test.ts src/services/signatures.test.ts src/services/sessionTokens.test.ts src/services/catalog/readModel.test.ts src/routes/keys.test.ts src/routes/uploads.test.ts src/routes/auth.test.ts src/routes/health.test.ts src/routes/catalog.test.ts src/app.test.ts src/cors.test.ts" }, "dependencies": { "@fastify/cors": "^11.2.0", diff --git a/services/api/src/app.ts b/services/api/src/app.ts index 89044c4..09a1111 100644 --- a/services/api/src/app.ts +++ b/services/api/src/app.ts @@ -39,6 +39,7 @@ export type BuildAppOptions = { // Tests disable logging; production always logs. logging?: boolean; catalog?: CatalogReadModel; + apiOrigins?: string[]; }; export async function buildApp(options: BuildAppOptions = {}): Promise { @@ -48,9 +49,9 @@ export async function buildApp(options: BuildAppOptions = {}): Promise + typeof value === 'string' + ? value + .split(',') + .map(origin => origin.trim()) + .filter(Boolean) + : value, + z.array(z.string().url()).min(1).optional(), +); + const envSchema = z.object({ API_PORT: z.coerce.number().int().min(1).max(65535).default(8790), API_ORIGIN: z.string().url().default('http://localhost:5273'), + API_ORIGINS: optionalOriginList, PASEO_ASSET_HUB_RPC: z.string().url().optional(), DOTIFY_FACTORY_ADDRESS: optionalNonEmptyString, DOTIFY_DIRECTORY_ADDRESS: optionalNonEmptyString, @@ -65,7 +77,10 @@ function parseEnv() { console.error(`[dotify-api] Invalid environment configuration:\n${issues}`); process.exit(1); } - return result.data; + return { + ...result.data, + API_ORIGINS: result.data.API_ORIGINS ?? [result.data.API_ORIGIN], + }; } export const config = parseEnv(); diff --git a/services/api/src/cors.test.ts b/services/api/src/cors.test.ts new file mode 100644 index 0000000..2d6f32c --- /dev/null +++ b/services/api/src/cors.test.ts @@ -0,0 +1,36 @@ +import assert from 'node:assert/strict'; +import { afterEach, describe, it } from 'node:test'; +import type { FastifyInstance } from 'fastify'; +import { buildApp } from './app.js'; + +let app: FastifyInstance | null = null; + +afterEach(async () => { + if (app) await app.close(); + app = null; +}); + +describe('frontend origin boundary', () => { + it('allows each configured Dotify frontend and rejects unrelated origins', async () => { + app = await buildApp({ + logging: false, + apiOrigins: ['https://muzinga.netlify.app', 'https://dotify.dev-dot.li'], + }); + + for (const origin of ['https://muzinga.netlify.app', 'https://dotify.dev-dot.li']) { + const response = await app.inject({ + method: 'GET', + url: '/health', + headers: { origin }, + }); + assert.equal(response.headers['access-control-allow-origin'], origin); + } + + const unrelated = await app.inject({ + method: 'GET', + url: '/health', + headers: { origin: 'https://unrelated.example' }, + }); + assert.equal(unrelated.headers['access-control-allow-origin'], undefined); + }); +}); diff --git a/spec.md b/spec.md index aa8fae0..7aabf3c 100644 --- a/spec.md +++ b/spec.md @@ -94,7 +94,7 @@ Individuality data. ## 4. System Architecture ```text -Browser (React + Vite) +Browser or Product host (React + Vite) ├── Player and catalog UI ├── WebRTC host-to-listener audio stream ├── Socket.IO signaling server for SDP/ICE and room discovery @@ -105,20 +105,20 @@ Browser (React + Vite) └── Paseo Asset Hub EVM contracts for artist runtimes and access policy ``` -The frontend is a static React/Vite app. It can be served locally by Vite or -built as a single-file Bulletin/IPFS-friendly artifact. +The frontend is a static React/Vite app. It can be served locally by Vite, +deployed to Netlify, built as a single-file Bulletin/IPFS-friendly artifact, +or published as the multi-file `dotify.dot` Product DevNet app. Production-sensitive upload and content-key operations live behind `services/api/`. Browser-side Pinata upload and `VITE_CONTENT_SECRET` key derivation remain local/demo paths only. -Product SDK / Playground / Humanity integration is a progressive enhancement -track, not a hard dependency for first sound. The current verified SDK snapshot -(`@parity/product-sdk` 0.17.0 at -`2f359bba28ca72855207a0a519d4118b37b4438c`) must be treated as -prototype/reference/unaudited until Dotify proves Host capability detection, -Product account signing, resource allocation, contract portability, and -Statement Store constraints against the current app. +Product SDK integration is an adaptive enhancement, not a hard dependency for +first sound. The Product build pins `@parity/product-sdk` 0.19.1, detects the +host, and requests an app-scoped account only after explicit user action. That +account is currently an identity/presence capability: Classic payments, artist +publication, and protected key requests still require the passkey/EVM path +until CDM/PAPI writes and backend Product-signature verification are delivered. ## 5. Repository Layout @@ -418,6 +418,9 @@ Important browser-exposed variables: | Variable | Purpose | | ------------------------- | ------------------------------------------------------------------------------------------ | | `VITE_DOTIFY_DEPLOYMENT` | build-time deployment safety mode; set `production` for public production builds | +| `VITE_DOTIFY_HOST_MODE` | Product host mode (`off`, `auto`, or `required`) | +| `VITE_DOTIFY_PRODUCT_ID` | `.dot` name used for app-scoped Product account derivation | +| `VITE_PUBLIC_APP_URL` | canonical public room-link origin for Product/container builds | | `VITE_DOTIFY_DEBUG_PANEL` | optional flag that shows the read-only Production readiness panel under `You` | | `VITE_SIGNAL_URL` | Socket.IO signaling server URL | | `VITE_LOCAL_WS_URL` | local Substrate websocket URL | @@ -436,7 +439,8 @@ Server/script variables: | `SIGNAL_PORT` | local signaling server port | | `SIGNAL_ORIGINS` | allowed frontend origins for signaling | | `API_PORT` | backend API port | -| `API_ORIGIN` | frontend origin allowed by backend CORS | +| `API_ORIGIN` | backwards-compatible singular frontend CORS origin | +| `API_ORIGINS` | comma-separated exact frontend CORS origins | | `PASEO_ASSET_HUB_RPC` | backend RPC endpoint for access checks | | `DOTIFY_DIRECTORY_ADDRESS` | backend ArtistDirectory address for runtime lookup | | `DOTIFY_CHAIN_ID` | chain ID expected in signed key requests | @@ -446,10 +450,12 @@ Server/script variables: ## 11. Wallet And Passkey Design -Dotify supports two wallet paths in the frontend design: +Dotify supports three account paths in the frontend design: - passkey-backed local key derivation through WebAuthn PRF; - browser wallet extension signing through Polkadot/EVM wallet providers. +- Product-host app-scoped identity for presence and rooms. It is not yet an + EIP-191 or EVM transaction signer. ### 11.1 Passkey Credential ID @@ -661,9 +667,9 @@ Priority improvements: Bulletin builds. 4. Finish security hardening for publish intents, auth chain binding, durable revocation, realtime reconnect, and short-lived TURN credentials. -5. Run Product SDK feasibility spikes for Host capability detection, Product - account signing, resource allocation, Playground/Bulletin/DotNS deployment, - Statement Store presence, and PolkaVM/CDM contract portability. +5. Validate the delivered Product host/account and Bulletin/DotNS deployment + baseline, then implement CDM/PAPI contract portability, backend Product + signature verification, and a bounded Statement Store presence spike. 6. Move the large catalog, session, artist, and player workflows behind domain ports and application use cases. 7. Validate the cacheable catalog API's warm/cold p75 budgets under public seed diff --git a/web/.env.example b/web/.env.example index daabd83..0b3c0a7 100644 --- a/web/.env.example +++ b/web/.env.example @@ -4,6 +4,12 @@ # Socket.IO signaling server used by shared listening rooms. VITE_SIGNAL_URL=http://localhost:8788 +# Product host integration is disabled for ordinary local/Netlify builds. +# The checked-in `.env.product-devnet` profile sets these for `dotify.dot`. +VITE_DOTIFY_HOST_MODE=off +# VITE_DOTIFY_PRODUCT_ID=dotify.dot +# VITE_PUBLIC_APP_URL=https://dotify.dev-dot.li + # Local development endpoints used when selecting the local network preset. VITE_LOCAL_WS_URL=ws://localhost:9944 VITE_LOCAL_ETH_RPC_URL=http://localhost:8545 diff --git a/web/.env.product-devnet b/web/.env.product-devnet new file mode 100644 index 0000000..84eea89 --- /dev/null +++ b/web/.env.product-devnet @@ -0,0 +1,22 @@ +# Checked-in browser-safe Product DevNet build profile. Never add secrets here. +VITE_DOTIFY_DEPLOYMENT=production +VITE_DOTIFY_HOST_MODE=required +VITE_DOTIFY_PRODUCT_ID=dotify.dot +VITE_PUBLIC_APP_URL=https://dotify.dev-dot.li + +VITE_SIGNAL_URL=https://dotify-signal.fly.dev +VITE_DOTIFY_API_URL=https://dotify-api.fly.dev + +# Existing Dotify contracts currently remain on the Product DevNet-compatible +# Asset Hub EVM endpoint while the write adapter is ported to CDM/PAPI. +VITE_ETH_RPC_URL=https://eth-rpc-testnet.polkadot.io/ +VITE_BULLETIN_WS_URL=wss://bulletin-paseo.tservices.es:8443 + +VITE_PINATA_GATEWAY=https://devnet-ipfs.api.polkadotcommunity.foundation +VITE_IPFS_READ_GATEWAYS=https://devnet-ipfs.api.polkadotcommunity.foundation,https://ipfs.io,https://dweb.link +VITE_BLOCKSCOUT_BASE_URL=https://blockscout-testnet.polkadot.io + +# Explicitly shadow any local demo values from `.env`; Product builds use the +# Fly API for uploads and key delivery. +VITE_PINATA_JWT= +VITE_CONTENT_SECRET= diff --git a/web/README.md b/web/README.md index f0096c0..c4cfa6a 100644 --- a/web/README.md +++ b/web/README.md @@ -35,6 +35,9 @@ Useful environment variables: wallet-signed content-key requests. - `VITE_DOTIFY_DEBUG_PANEL`: set to `true` to show the read-only Production readiness panel under the `You` tab. +- `VITE_DOTIFY_HOST_MODE`, `VITE_DOTIFY_PRODUCT_ID`, and + `VITE_PUBLIC_APP_URL`: Product-host detection, app-scoped account identifier, + and canonical room-link origin. - `VITE_LOCAL_WS_URL` / `VITE_LOCAL_ETH_RPC_URL`: local development endpoints. - `VITE_BULLETIN_WS_URL`: Paseo Bulletin Chain RPC. - `VITE_PINATA_JWT`: restricted browser-exposed Pinata JWT for demo uploads @@ -155,11 +158,26 @@ npm run codegen npm run build npm run build:bulletin npm run deploy:bulletin +npm run build:product-devnet +npm run deploy:product-devnet ``` `build:bulletin` produces a single-file build via `vite-plugin-singlefile` so it can be distributed from a flat IPFS CID / DotNS record. +`build:product-devnet` produces `dist-product` with the checked-in +`.env.product-devnet` profile. `deploy:product-devnet` uses +`@polkadot-community-foundation/polkadot-app-deploy@0.13.1` through `npx`, uploads static chunks to +Product DevNet Bulletin, and binds `dotify.dot`. Browse listing is a separate +operator step because it has its own signer/personhood boundary. The Product account currently +provides app-scoped identity for presence and rooms; contract writes and +protected key requests still require the existing passkey/EVM signer. + +See +[`docs/explanation/product-devnet-architecture.md`](../docs/explanation/product-devnet-architecture.md) +and +[`docs/operations/product-devnet-deployment.md`](../docs/operations/product-devnet-deployment.md). + ### Production Deploy: Netlify + Fly Dotify's production web app is a static Vite build, but listening rooms require diff --git a/web/eslint.config.js b/web/eslint.config.js index d591c6b..186ef82 100644 --- a/web/eslint.config.js +++ b/web/eslint.config.js @@ -5,7 +5,7 @@ import eslintConfigPrettier from "eslint-config-prettier"; export default tseslint.config( { - ignores: ["dist/**", "dist-bulletin/**", "node_modules/**", ".papi/**", "tsconfig.tsbuildinfo", "src/generated/**"], + ignores: ["dist/**", "dist-bulletin/**", "dist-product/**", "node_modules/**", ".papi/**", "tsconfig.tsbuildinfo", "src/generated/**"], }, js.configs.recommended, ...tseslint.configs.recommended, diff --git a/web/fly.signal.toml b/web/fly.signal.toml index c44532b..2b1b3a2 100644 --- a/web/fly.signal.toml +++ b/web/fly.signal.toml @@ -10,6 +10,7 @@ primary_region = "ams" SIGNAL_ROOM_TTL_MS = "21600000" SIGNAL_HOST_TIMEOUT_MS = "120000" SIGNAL_MAX_LISTENERS = "24" + SIGNAL_ORIGINS = "https://muzinga.netlify.app,https://dotify.dev-dot.li" [http_service] internal_port = 8788 diff --git a/web/package-lock.json b/web/package-lock.json index 27ea880..ea7aaf1 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -8,6 +8,7 @@ "name": "dotify-web", "version": "0.1.0", "dependencies": { + "@parity/product-sdk": "0.19.1", "@polkadot-api/descriptors": "file:.papi/descriptors", "@polkadot-apps/chain-client": "^2.0.5", "@polkadot-apps/descriptors": "^1.0.1", @@ -974,126 +975,3523 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@ipld/dag-pb": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@ipld/dag-pb/-/dag-pb-4.1.7.tgz", + "integrity": "sha512-/i/13trFihjWfDyXlylRwhuYjtzYjvOFw0vlRjYGnZuv7d7MOgA2lV/vRuL5RfeUajM03aZfFLdq4S7cTbbTRg==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "multiformats": "^14.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@ipld/dag-pb/node_modules/multiformats": { + "version": "14.0.5", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-14.0.5.tgz", + "integrity": "sha512-vbIm83F2yZ1pWJGS0yl0ysracIvv56LtbrIyiIQHoLdYDJOMoLfVFsXhh9DUH4SFdkdkFhucyWniihsNzVEjkQ==", + "license": "Apache-2.0 OR MIT" + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.2.0.tgz", + "integrity": "sha512-T/BoHgFXirb0ENSPBquzX0rcjXeM6Lo892a2jlYJkqk83LqZx0l1Of7DzlKJ6jkpvMrkHSnAcgb5JegL8SeIkQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "2.2.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", + "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@novasamatech/host-api": { + "version": "0.6.18", + "resolved": "https://registry.npmjs.org/@novasamatech/host-api/-/host-api-0.6.18.tgz", + "integrity": "sha512-5U5tYRbY/v49BqHH+iHPIP6OH7KJjXUMypaXSXtZK/J3IsQAqDLBlu/LqpDrNxHqEK1sKY5EyYla840mqmkwPg==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "@novasamatech/scale": "0.6.18", + "@polkadot-api/utils": "^0.2.0", + "nanoevents": "9.1.0", + "nanoid": "5.1.7", + "neverthrow": "^8.2.0", + "scale-ts": "1.6.1" + } + }, + "node_modules/@novasamatech/host-api/node_modules/@novasamatech/scale": { + "version": "0.6.18", + "resolved": "https://registry.npmjs.org/@novasamatech/scale/-/scale-0.6.18.tgz", + "integrity": "sha512-xRvBrzJSvCseQ62zLReS3EtiQjuiTY+c+yOyx6If9dBRzX5FL52OazFLsdSaq3wOe8441TPXL1vediotYFZlRg==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "@polkadot-api/utils": "^0.2.0", + "scale-ts": "1.6.1" + } + }, + "node_modules/@novasamatech/host-api/node_modules/nanoid": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.7.tgz", + "integrity": "sha512-ua3NDgISf6jdwezAheMOk4mbE1LXjm1DfMUDMuJf4AqxLFK3ccGpgWizwa5YV7Yz9EpXwEaWoRXSb/BnV0t5dQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "optional": true, + "peer": true, + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/@parity/product-sdk": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@parity/product-sdk/-/product-sdk-0.19.1.tgz", + "integrity": "sha512-vZnXh5FUc/KSXBeMYd5v5ZTit9f4PLlXkXD7rvvESdV7L2djTlDij4uOKkr1oWg9NrRmcH4cvkHD1wAbs2Zqzg==", + "license": "Apache-2.0", + "dependencies": { + "@parity/product-sdk-address": "0.1.1", + "@parity/product-sdk-chain-client": "0.9.1", + "@parity/product-sdk-cloud-storage": "0.8.1", + "@parity/product-sdk-contracts": "0.9.2", + "@parity/product-sdk-crypto": "0.1.1", + "@parity/product-sdk-errors": "0.2.0", + "@parity/product-sdk-host": "0.14.1", + "@parity/product-sdk-keys": "0.3.16", + "@parity/product-sdk-local-storage": "0.3.2", + "@parity/product-sdk-logger": "0.1.1", + "@parity/product-sdk-signer": "0.11.1", + "@parity/product-sdk-tx": "0.3.2", + "@parity/result": "0.2.0", + "polkadot-api": "^2.1.6" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, + "node_modules/@parity/product-sdk-address": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@parity/product-sdk-address/-/product-sdk-address-0.1.1.tgz", + "integrity": "sha512-sSymun3alNGdvawhdc0Ha0KEkuqMwBZui1bsUVeZIZRJAfWvQzrV1AVaf8aah5JFlcaRdg8FYyp7xL2eP+ZplA==", + "license": "Apache-2.0", + "dependencies": { + "@noble/hashes": "^1.7.1", + "@polkadot-api/substrate-bindings": "^0.12.0" + } + }, + "node_modules/@parity/product-sdk-address/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@parity/product-sdk-address/node_modules/@polkadot-api/substrate-bindings": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-bindings/-/substrate-bindings-0.12.0.tgz", + "integrity": "sha512-cIjDeJRHW6g3z+/55UzpoG4LG1N0HbT4x3NvZsQkYg4eoio9Sw7Pw2aZZX86pWemxc7vQbNw7WSz2Gz+ckdX6Q==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.8.0", + "@polkadot-api/utils": "0.1.2", + "@scure/base": "^1.2.5", + "scale-ts": "^1.6.1" + } + }, + "node_modules/@parity/product-sdk-address/node_modules/@polkadot-api/utils": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@polkadot-api/utils/-/utils-0.1.2.tgz", + "integrity": "sha512-yhs5k2a8N1SBJcz7EthZoazzLQUkZxbf+0271Xzu42C5AEM9K9uFLbsB+ojzHEM72O5X8lPtSwGKNmS7WQyDyg==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-address/node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@parity/product-sdk-chain-client": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@parity/product-sdk-chain-client/-/product-sdk-chain-client-0.9.1.tgz", + "integrity": "sha512-NXMJAYqLGdFp0VAbNfn2HeGhcP6n78jxtVEpcv9084ZlldhuwFKJLGwXOj81xbw2QHATbufCNLDY9IsTM+9Pew==", + "license": "Apache-2.0", + "dependencies": { + "@parity/product-sdk-descriptors": "0.8.0", + "@parity/product-sdk-host": "0.14.1", + "@parity/product-sdk-logger": "0.1.1", + "polkadot-api": "^2.1.6" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@commander-js/extra-typings": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commander-js/extra-typings/-/extra-typings-15.0.0.tgz", + "integrity": "sha512-yeJlba62xqmkgELUsn7356MEnzLLu/fw2x4lofFqGnXh6YysRdEs2BaLeLtg1+KU0AXvMeqQvTTp+3hBEBK+EA==", + "license": "MIT", + "peerDependencies": { + "commander": "~15.0.0" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/cli": { + "version": "0.21.9", + "resolved": "https://registry.npmjs.org/@polkadot-api/cli/-/cli-0.21.9.tgz", + "integrity": "sha512-9aVdF/ocF3DBb8b/gdkcicBIaQkak2kkU4EGW+TunXLIvbIj2X9hH5geOlx8uWNwt0O4O1DIHD/nkXvycG/AcA==", + "license": "MIT", + "dependencies": { + "@commander-js/extra-typings": "^15.0.0", + "@polkadot-api/codegen": "0.22.5", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/wasm-executor": "^0.2.3", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@types/node": "^25.9.4", + "commander": "^15.0.0", + "execa": "^9.6.1", + "fs.promises.exists": "^1.1.4", + "ora": "^9.4.1", + "read-pkg": "^10.1.0", + "rollup": "^4.62.2", + "rollup-plugin-esbuild": "^6.2.1", + "rxjs": "^7.8.2", + "tsc-prog": "^2.3.0", + "typescript": "^6.0.3", + "write-package": "^7.2.0" + }, + "bin": { + "papi": "dist/main/src/main.js", + "polkadot-api": "dist/main/src/main.js" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/codegen": { + "version": "0.22.5", + "resolved": "https://registry.npmjs.org/@polkadot-api/codegen/-/codegen-0.22.5.tgz", + "integrity": "sha512-zwZJAlviI211zhj5i6oXkrr0crrbO3GZjBd2vC9AshY1pRmyiNLV9DZsXw4E6l4JQwdAAyNWtPdnvvB9T3TpKg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/ink-contracts": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/ink-contracts/-/ink-contracts-0.6.3.tgz", + "integrity": "sha512-XqnM1VDzI5L62xgg+f8le2yEoz8QZbUKEfAfPnHMOgBj9tJiyF15FcOJmnLMO/vq3cGixqh18tzJekLG5YTxtA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/json-rpc-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider/-/json-rpc-provider-0.2.0.tgz", + "integrity": "sha512-lhkuBS/x06i3djQIN7p8jVkMnYuGsUAEMS6RhdWeEpz7X/8/APER4Wdih7MEBovCuwVSCTjOxl8f+alH7AZHZg==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/json-rpc-provider-proxy": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider-proxy/-/json-rpc-provider-proxy-0.4.1.tgz", + "integrity": "sha512-F1Hw01C60jn98KQ0vBbgcwAvEcMcKLsJ5kFzq600sgjc6Rnbn1VF/XjTdrjcIqvfpR9sXyGIrpImrov2Usbrsw==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/known-chains": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/known-chains/-/known-chains-0.12.1.tgz", + "integrity": "sha512-ZW9TYD2y5IhgNy28zi9sByMr0CaP2I9x8HcAI0pwZR2qDC0kysCG6brDlg1UoZKCjRO99SsKO/iU1o434JgMnQ==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/logs-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/logs-provider/-/logs-provider-0.2.0.tgz", + "integrity": "sha512-BH9YdxZu+ZBPPAUwGrvqHPn1hQStL2Im3MmTwYkwXOWW2HlGHULcF65QKvyK+T6/mj2vDvl3MgivnGkUw4pVxg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/merkleize-metadata": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/merkleize-metadata/-/merkleize-metadata-1.2.3.tgz", + "integrity": "sha512-WkPbz0p2XQ9c8yXagdnwCHEB70Gnm91okcsd6IXU393//3aPgkxKgb+/Efnz7C5/KQmg02P0zXo7q/n/W/yVCA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/metadata-builders": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-builders/-/metadata-builders-0.14.3.tgz", + "integrity": "sha512-m7CACsiqHzgVEh5WBZGkTV8AQ3CBQKR1YpPQMnlsJfCr/IkgKU0UyWM6WxCmBiReLFVkOfXMtGlpN8+GxpHmww==", + "license": "MIT", + "dependencies": { + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/metadata-compatibility": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-compatibility/-/metadata-compatibility-0.6.3.tgz", + "integrity": "sha512-/Y0uF8nDk60ijydp8Bd37YexPFdB8hBXJWwEgOJHsVlhiny8sVKXiMg+UkJ9BiEk2z+yMbZRCKmhNpTpizo7aw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/observable-client": { + "version": "0.18.7", + "resolved": "https://registry.npmjs.org/@polkadot-api/observable-client/-/observable-client-0.18.7.tgz", + "integrity": "sha512-/eQi3D8jbXLg/L1hZX4eX0/+nO3kTxkOfYeWEtFhtOvFdfqiiy2DdXG3Zg5QzgHmfG+11p4vSlLiPCC2UvS5Qw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/pjs-signer": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/pjs-signer/-/pjs-signer-0.7.3.tgz", + "integrity": "sha512-U7BLFZfnpFMxCh/scJoLXT6oSbfZtZgMTkiu+TbuWQljAb/1ttrQOfshub5VihNyD5rHajp/2Fq0ONZoL5N5PA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/raw-client": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/raw-client/-/raw-client-0.3.0.tgz", + "integrity": "sha512-u/wM9W7ugIXxBSOEV8+zvQI43b5vgSI0pvE0Rg8PV0G65BTLK0SMc2o2SQL0HtS5+bi5sw/gg4reBJ/0a4U0cw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/signer": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signer/-/signer-0.3.3.tgz", + "integrity": "sha512-bmEV65TwgwbMfiecl7ZQ3k5lfkCOx9FPwPYkVvALcPiqb/d3zYwT9LL/E00hj+EB6IKMlMelEQVuchcW5i/92w==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/merkleize-metadata": "1.2.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/signers-common": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signers-common/-/signers-common-0.2.3.tgz", + "integrity": "sha512-SzGLJMxug31Y1P8+0I809ICpDrayztUXFFh2TV02GuwjEnY6mDGnmX56wowZF5yCn+WteeRdcTJTK7Whk3AGYQ==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/sm-provider": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@polkadot-api/sm-provider/-/sm-provider-0.3.8.tgz", + "integrity": "sha512-jIvzBNsBsh6LIpCrUOa7miZdQPwLPns5IUQyz/8v84R3ON7URSIVbtywGSR8O83BZGyW/DmVkqa5lClLE2fkqw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1" + }, + "peerDependencies": { + "@polkadot-api/smoldot": ">=0.3" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/smoldot": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/@polkadot-api/smoldot/-/smoldot-0.4.6.tgz", + "integrity": "sha512-gOXMJ10fXOub0zPP1cGAYeyf29BA2fB+qukrjXGcGN9b0Ya+lDgV7A7Q7y9JOrlGLeKbd1YdrYLAe/F43V7b9Q==", + "license": "MIT", + "dependencies": { + "@types/node": "^25.9.4", + "smoldot": "~3.3.1" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/substrate-bindings": { + "version": "0.20.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-bindings/-/substrate-bindings-0.20.3.tgz", + "integrity": "sha512-9iqC71fx1ee9ld1NZV8PFime5vryi0kt1bKCSlvNgO6dqMc06sMZuZ8WPjOzWLCHiKHLuphdMs3rVBBaeCP3yg==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/utils": "0.4.0", + "@scure/base": "^2.2.0", + "scale-ts": "^1.6.1" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/substrate-client": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-client/-/substrate-client-0.7.0.tgz", + "integrity": "sha512-TWCc4MAMa5SLVQXmomLHknbj+bztQ/Yclgwm8ENBhz8hR7c9rw9FBAkCa02jMBMCAygPhp3ayGRq+UFcF8KIxQ==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/raw-client": "0.3.0", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/utils": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/utils/-/utils-0.4.0.tgz", + "integrity": "sha512-9b/hwRM0UloLWV7SfpNaSD/4k8UQAHoaACAk7Xe+1MlfAm2JtnmPiB1GfGrfTyBlsrJVUIBCZpEmbmxVMaIqBA==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/@polkadot-api/ws-provider": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/ws-provider/-/ws-provider-0.9.1.tgz", + "integrity": "sha512-Ft2QJEjLZgTyKiCEbz3urSOxNfMdqNkg+QKqJhRbOFB7JtR1qMTvLE3TjM+5d2mNlEpOc3j2KDK3APNSj7uQ2Q==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/polkadot-api": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/polkadot-api/-/polkadot-api-2.2.1.tgz", + "integrity": "sha512-eiZVUhI1gY4ycBtsCo/yaDXyohUeuqnyKun+bwj90ADSn+jlfjZ4sajAqIhJFwPxbCT75+Zzbln4ZjuZ5PWNWA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/cli": "0.21.9", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/logs-provider": "0.2.0", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/pjs-signer": "0.7.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signer": "0.3.3", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@rx-state/core": "^0.1.4" + }, + "bin": { + "papi": "bin/cli.js", + "polkadot-api": "bin/cli.js" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/smoldot": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/smoldot/-/smoldot-3.3.2.tgz", + "integrity": "sha512-Zl4h/0gsw8cfTZzuJ7LV7mtR6QjxltwYjMY7MsVw0oXBXrLK8zyOS6DS9Vjsy57pX1vBMg6UVhHxjbH3W905zA==", + "license": "GPL-3.0-or-later WITH Classpath-exception-2.0", + "dependencies": { + "ws": "^8.8.1" + } + }, + "node_modules/@parity/product-sdk-chain-client/node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@parity/product-sdk-cloud-storage": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@parity/product-sdk-cloud-storage/-/product-sdk-cloud-storage-0.8.1.tgz", + "integrity": "sha512-yRMY8stewHA/ImbJD+PX/ao7JGniLomj3PPyPE22+aGZXpCcYwXdxMcDFOJgNtDK69Fyr483ejaew9tAFRzXNQ==", + "license": "Apache-2.0", + "dependencies": { + "@parity/bulletin-sdk": "^0.3.0", + "@parity/product-sdk-chain-client": "0.9.1", + "@parity/product-sdk-descriptors": "0.8.0", + "@parity/product-sdk-errors": "0.2.0", + "@parity/product-sdk-host": "0.14.1", + "@parity/product-sdk-logger": "0.1.1", + "@parity/product-sdk-tx": "0.3.2", + "@parity/result": "0.2.0", + "multiformats": "^13.3.0", + "polkadot-api": "^2.1.6" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@commander-js/extra-typings": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commander-js/extra-typings/-/extra-typings-15.0.0.tgz", + "integrity": "sha512-yeJlba62xqmkgELUsn7356MEnzLLu/fw2x4lofFqGnXh6YysRdEs2BaLeLtg1+KU0AXvMeqQvTTp+3hBEBK+EA==", + "license": "MIT", + "peerDependencies": { + "commander": "~15.0.0" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@parity/bulletin-sdk": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@parity/bulletin-sdk/-/bulletin-sdk-0.3.0.tgz", + "integrity": "sha512-sxVwBzyH/egXze1muPXbaGwQuOkP8efVB4Lxunshixf18gJ6WT2tedgUy08QOfQ1848BDQS4wVpRRQfPfb09/g==", + "license": "GPL-3.0-or-later WITH Classpath-exception-2.0", + "dependencies": { + "@ipld/dag-pb": "^4.1.3", + "@noble/hashes": "^2.2.0", + "@polkadot-labs/hdkd-helpers": "^0.0.29", + "ipfs-unixfs": "^12.0.0" + }, + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "multiformats": "^13.4.1", + "polkadot-api": "^2.1.2" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/cli": { + "version": "0.21.9", + "resolved": "https://registry.npmjs.org/@polkadot-api/cli/-/cli-0.21.9.tgz", + "integrity": "sha512-9aVdF/ocF3DBb8b/gdkcicBIaQkak2kkU4EGW+TunXLIvbIj2X9hH5geOlx8uWNwt0O4O1DIHD/nkXvycG/AcA==", + "license": "MIT", + "dependencies": { + "@commander-js/extra-typings": "^15.0.0", + "@polkadot-api/codegen": "0.22.5", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/wasm-executor": "^0.2.3", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@types/node": "^25.9.4", + "commander": "^15.0.0", + "execa": "^9.6.1", + "fs.promises.exists": "^1.1.4", + "ora": "^9.4.1", + "read-pkg": "^10.1.0", + "rollup": "^4.62.2", + "rollup-plugin-esbuild": "^6.2.1", + "rxjs": "^7.8.2", + "tsc-prog": "^2.3.0", + "typescript": "^6.0.3", + "write-package": "^7.2.0" + }, + "bin": { + "papi": "dist/main/src/main.js", + "polkadot-api": "dist/main/src/main.js" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/codegen": { + "version": "0.22.5", + "resolved": "https://registry.npmjs.org/@polkadot-api/codegen/-/codegen-0.22.5.tgz", + "integrity": "sha512-zwZJAlviI211zhj5i6oXkrr0crrbO3GZjBd2vC9AshY1pRmyiNLV9DZsXw4E6l4JQwdAAyNWtPdnvvB9T3TpKg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/ink-contracts": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/ink-contracts/-/ink-contracts-0.6.3.tgz", + "integrity": "sha512-XqnM1VDzI5L62xgg+f8le2yEoz8QZbUKEfAfPnHMOgBj9tJiyF15FcOJmnLMO/vq3cGixqh18tzJekLG5YTxtA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/json-rpc-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider/-/json-rpc-provider-0.2.0.tgz", + "integrity": "sha512-lhkuBS/x06i3djQIN7p8jVkMnYuGsUAEMS6RhdWeEpz7X/8/APER4Wdih7MEBovCuwVSCTjOxl8f+alH7AZHZg==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/json-rpc-provider-proxy": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider-proxy/-/json-rpc-provider-proxy-0.4.1.tgz", + "integrity": "sha512-F1Hw01C60jn98KQ0vBbgcwAvEcMcKLsJ5kFzq600sgjc6Rnbn1VF/XjTdrjcIqvfpR9sXyGIrpImrov2Usbrsw==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/known-chains": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/known-chains/-/known-chains-0.12.1.tgz", + "integrity": "sha512-ZW9TYD2y5IhgNy28zi9sByMr0CaP2I9x8HcAI0pwZR2qDC0kysCG6brDlg1UoZKCjRO99SsKO/iU1o434JgMnQ==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/logs-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/logs-provider/-/logs-provider-0.2.0.tgz", + "integrity": "sha512-BH9YdxZu+ZBPPAUwGrvqHPn1hQStL2Im3MmTwYkwXOWW2HlGHULcF65QKvyK+T6/mj2vDvl3MgivnGkUw4pVxg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/merkleize-metadata": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/merkleize-metadata/-/merkleize-metadata-1.2.3.tgz", + "integrity": "sha512-WkPbz0p2XQ9c8yXagdnwCHEB70Gnm91okcsd6IXU393//3aPgkxKgb+/Efnz7C5/KQmg02P0zXo7q/n/W/yVCA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/metadata-builders": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-builders/-/metadata-builders-0.14.3.tgz", + "integrity": "sha512-m7CACsiqHzgVEh5WBZGkTV8AQ3CBQKR1YpPQMnlsJfCr/IkgKU0UyWM6WxCmBiReLFVkOfXMtGlpN8+GxpHmww==", + "license": "MIT", + "dependencies": { + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/metadata-compatibility": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-compatibility/-/metadata-compatibility-0.6.3.tgz", + "integrity": "sha512-/Y0uF8nDk60ijydp8Bd37YexPFdB8hBXJWwEgOJHsVlhiny8sVKXiMg+UkJ9BiEk2z+yMbZRCKmhNpTpizo7aw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/observable-client": { + "version": "0.18.7", + "resolved": "https://registry.npmjs.org/@polkadot-api/observable-client/-/observable-client-0.18.7.tgz", + "integrity": "sha512-/eQi3D8jbXLg/L1hZX4eX0/+nO3kTxkOfYeWEtFhtOvFdfqiiy2DdXG3Zg5QzgHmfG+11p4vSlLiPCC2UvS5Qw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/pjs-signer": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/pjs-signer/-/pjs-signer-0.7.3.tgz", + "integrity": "sha512-U7BLFZfnpFMxCh/scJoLXT6oSbfZtZgMTkiu+TbuWQljAb/1ttrQOfshub5VihNyD5rHajp/2Fq0ONZoL5N5PA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/raw-client": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/raw-client/-/raw-client-0.3.0.tgz", + "integrity": "sha512-u/wM9W7ugIXxBSOEV8+zvQI43b5vgSI0pvE0Rg8PV0G65BTLK0SMc2o2SQL0HtS5+bi5sw/gg4reBJ/0a4U0cw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/signer": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signer/-/signer-0.3.3.tgz", + "integrity": "sha512-bmEV65TwgwbMfiecl7ZQ3k5lfkCOx9FPwPYkVvALcPiqb/d3zYwT9LL/E00hj+EB6IKMlMelEQVuchcW5i/92w==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/merkleize-metadata": "1.2.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/signers-common": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signers-common/-/signers-common-0.2.3.tgz", + "integrity": "sha512-SzGLJMxug31Y1P8+0I809ICpDrayztUXFFh2TV02GuwjEnY6mDGnmX56wowZF5yCn+WteeRdcTJTK7Whk3AGYQ==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/sm-provider": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@polkadot-api/sm-provider/-/sm-provider-0.3.8.tgz", + "integrity": "sha512-jIvzBNsBsh6LIpCrUOa7miZdQPwLPns5IUQyz/8v84R3ON7URSIVbtywGSR8O83BZGyW/DmVkqa5lClLE2fkqw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1" + }, + "peerDependencies": { + "@polkadot-api/smoldot": ">=0.3" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/smoldot": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/@polkadot-api/smoldot/-/smoldot-0.4.6.tgz", + "integrity": "sha512-gOXMJ10fXOub0zPP1cGAYeyf29BA2fB+qukrjXGcGN9b0Ya+lDgV7A7Q7y9JOrlGLeKbd1YdrYLAe/F43V7b9Q==", + "license": "MIT", + "dependencies": { + "@types/node": "^25.9.4", + "smoldot": "~3.3.1" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/substrate-bindings": { + "version": "0.20.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-bindings/-/substrate-bindings-0.20.3.tgz", + "integrity": "sha512-9iqC71fx1ee9ld1NZV8PFime5vryi0kt1bKCSlvNgO6dqMc06sMZuZ8WPjOzWLCHiKHLuphdMs3rVBBaeCP3yg==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/utils": "0.4.0", + "@scure/base": "^2.2.0", + "scale-ts": "^1.6.1" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/substrate-client": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-client/-/substrate-client-0.7.0.tgz", + "integrity": "sha512-TWCc4MAMa5SLVQXmomLHknbj+bztQ/Yclgwm8ENBhz8hR7c9rw9FBAkCa02jMBMCAygPhp3ayGRq+UFcF8KIxQ==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/raw-client": "0.3.0", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/utils": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/utils/-/utils-0.4.0.tgz", + "integrity": "sha512-9b/hwRM0UloLWV7SfpNaSD/4k8UQAHoaACAk7Xe+1MlfAm2JtnmPiB1GfGrfTyBlsrJVUIBCZpEmbmxVMaIqBA==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-api/ws-provider": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/ws-provider/-/ws-provider-0.9.1.tgz", + "integrity": "sha512-Ft2QJEjLZgTyKiCEbz3urSOxNfMdqNkg+QKqJhRbOFB7JtR1qMTvLE3TjM+5d2mNlEpOc3j2KDK3APNSj7uQ2Q==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/@polkadot-labs/hdkd-helpers": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@polkadot-labs/hdkd-helpers/-/hdkd-helpers-0.0.29.tgz", + "integrity": "sha512-yiLm1Gj3j5NrQV+VFMlFzkBgcRBNfq2Sd/U3S8iau2bzhDwgsn4gy6FDt94TRPD5xLxOzi1I3wSLOrgOs2eLVw==", + "license": "MIT", + "dependencies": { + "@noble/curves": "^2.2.0", + "@noble/hashes": "^2.2.0", + "@scure/base": "^2.0.0", + "@scure/sr25519": "^1.0.0", + "scale-ts": "^1.6.1" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/polkadot-api": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/polkadot-api/-/polkadot-api-2.2.1.tgz", + "integrity": "sha512-eiZVUhI1gY4ycBtsCo/yaDXyohUeuqnyKun+bwj90ADSn+jlfjZ4sajAqIhJFwPxbCT75+Zzbln4ZjuZ5PWNWA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/cli": "0.21.9", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/logs-provider": "0.2.0", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/pjs-signer": "0.7.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signer": "0.3.3", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@rx-state/core": "^0.1.4" + }, + "bin": { + "papi": "bin/cli.js", + "polkadot-api": "bin/cli.js" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/smoldot": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/smoldot/-/smoldot-3.3.2.tgz", + "integrity": "sha512-Zl4h/0gsw8cfTZzuJ7LV7mtR6QjxltwYjMY7MsVw0oXBXrLK8zyOS6DS9Vjsy57pX1vBMg6UVhHxjbH3W905zA==", + "license": "GPL-3.0-or-later WITH Classpath-exception-2.0", + "dependencies": { + "ws": "^8.8.1" + } + }, + "node_modules/@parity/product-sdk-cloud-storage/node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@parity/product-sdk-contracts": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@parity/product-sdk-contracts/-/product-sdk-contracts-0.9.2.tgz", + "integrity": "sha512-4svBhyBOoNfV4K5f9feizZSPl1Hn5frYpJvf5hjR9z7zp+t+1ruM/DjUM5QCgwrAmwkpfw7oxHDFTN3SlBo0tw==", + "license": "Apache-2.0", + "dependencies": { + "@parity/product-sdk-address": "0.1.1", + "@parity/product-sdk-errors": "0.2.0", + "@parity/product-sdk-keys": "0.3.16", + "@parity/product-sdk-logger": "0.1.1", + "@parity/product-sdk-signer": "0.11.1", + "@parity/product-sdk-tx": "0.3.2", + "@parity/result": "0.2.0", + "@polkadot-labs/hdkd-helpers": "^0.0.30", + "polkadot-api": "^2.1.6", + "viem": "^2.52.0" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@commander-js/extra-typings": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commander-js/extra-typings/-/extra-typings-15.0.0.tgz", + "integrity": "sha512-yeJlba62xqmkgELUsn7356MEnzLLu/fw2x4lofFqGnXh6YysRdEs2BaLeLtg1+KU0AXvMeqQvTTp+3hBEBK+EA==", + "license": "MIT", + "peerDependencies": { + "commander": "~15.0.0" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/cli": { + "version": "0.21.9", + "resolved": "https://registry.npmjs.org/@polkadot-api/cli/-/cli-0.21.9.tgz", + "integrity": "sha512-9aVdF/ocF3DBb8b/gdkcicBIaQkak2kkU4EGW+TunXLIvbIj2X9hH5geOlx8uWNwt0O4O1DIHD/nkXvycG/AcA==", + "license": "MIT", + "dependencies": { + "@commander-js/extra-typings": "^15.0.0", + "@polkadot-api/codegen": "0.22.5", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/wasm-executor": "^0.2.3", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@types/node": "^25.9.4", + "commander": "^15.0.0", + "execa": "^9.6.1", + "fs.promises.exists": "^1.1.4", + "ora": "^9.4.1", + "read-pkg": "^10.1.0", + "rollup": "^4.62.2", + "rollup-plugin-esbuild": "^6.2.1", + "rxjs": "^7.8.2", + "tsc-prog": "^2.3.0", + "typescript": "^6.0.3", + "write-package": "^7.2.0" + }, + "bin": { + "papi": "dist/main/src/main.js", + "polkadot-api": "dist/main/src/main.js" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/codegen": { + "version": "0.22.5", + "resolved": "https://registry.npmjs.org/@polkadot-api/codegen/-/codegen-0.22.5.tgz", + "integrity": "sha512-zwZJAlviI211zhj5i6oXkrr0crrbO3GZjBd2vC9AshY1pRmyiNLV9DZsXw4E6l4JQwdAAyNWtPdnvvB9T3TpKg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/ink-contracts": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/ink-contracts/-/ink-contracts-0.6.3.tgz", + "integrity": "sha512-XqnM1VDzI5L62xgg+f8le2yEoz8QZbUKEfAfPnHMOgBj9tJiyF15FcOJmnLMO/vq3cGixqh18tzJekLG5YTxtA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/json-rpc-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider/-/json-rpc-provider-0.2.0.tgz", + "integrity": "sha512-lhkuBS/x06i3djQIN7p8jVkMnYuGsUAEMS6RhdWeEpz7X/8/APER4Wdih7MEBovCuwVSCTjOxl8f+alH7AZHZg==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/json-rpc-provider-proxy": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider-proxy/-/json-rpc-provider-proxy-0.4.1.tgz", + "integrity": "sha512-F1Hw01C60jn98KQ0vBbgcwAvEcMcKLsJ5kFzq600sgjc6Rnbn1VF/XjTdrjcIqvfpR9sXyGIrpImrov2Usbrsw==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/known-chains": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/known-chains/-/known-chains-0.12.1.tgz", + "integrity": "sha512-ZW9TYD2y5IhgNy28zi9sByMr0CaP2I9x8HcAI0pwZR2qDC0kysCG6brDlg1UoZKCjRO99SsKO/iU1o434JgMnQ==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/logs-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/logs-provider/-/logs-provider-0.2.0.tgz", + "integrity": "sha512-BH9YdxZu+ZBPPAUwGrvqHPn1hQStL2Im3MmTwYkwXOWW2HlGHULcF65QKvyK+T6/mj2vDvl3MgivnGkUw4pVxg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/merkleize-metadata": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/merkleize-metadata/-/merkleize-metadata-1.2.3.tgz", + "integrity": "sha512-WkPbz0p2XQ9c8yXagdnwCHEB70Gnm91okcsd6IXU393//3aPgkxKgb+/Efnz7C5/KQmg02P0zXo7q/n/W/yVCA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/metadata-builders": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-builders/-/metadata-builders-0.14.3.tgz", + "integrity": "sha512-m7CACsiqHzgVEh5WBZGkTV8AQ3CBQKR1YpPQMnlsJfCr/IkgKU0UyWM6WxCmBiReLFVkOfXMtGlpN8+GxpHmww==", + "license": "MIT", + "dependencies": { + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/metadata-compatibility": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-compatibility/-/metadata-compatibility-0.6.3.tgz", + "integrity": "sha512-/Y0uF8nDk60ijydp8Bd37YexPFdB8hBXJWwEgOJHsVlhiny8sVKXiMg+UkJ9BiEk2z+yMbZRCKmhNpTpizo7aw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/observable-client": { + "version": "0.18.7", + "resolved": "https://registry.npmjs.org/@polkadot-api/observable-client/-/observable-client-0.18.7.tgz", + "integrity": "sha512-/eQi3D8jbXLg/L1hZX4eX0/+nO3kTxkOfYeWEtFhtOvFdfqiiy2DdXG3Zg5QzgHmfG+11p4vSlLiPCC2UvS5Qw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/pjs-signer": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/pjs-signer/-/pjs-signer-0.7.3.tgz", + "integrity": "sha512-U7BLFZfnpFMxCh/scJoLXT6oSbfZtZgMTkiu+TbuWQljAb/1ttrQOfshub5VihNyD5rHajp/2Fq0ONZoL5N5PA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/raw-client": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/raw-client/-/raw-client-0.3.0.tgz", + "integrity": "sha512-u/wM9W7ugIXxBSOEV8+zvQI43b5vgSI0pvE0Rg8PV0G65BTLK0SMc2o2SQL0HtS5+bi5sw/gg4reBJ/0a4U0cw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/signer": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signer/-/signer-0.3.3.tgz", + "integrity": "sha512-bmEV65TwgwbMfiecl7ZQ3k5lfkCOx9FPwPYkVvALcPiqb/d3zYwT9LL/E00hj+EB6IKMlMelEQVuchcW5i/92w==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/merkleize-metadata": "1.2.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/signers-common": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signers-common/-/signers-common-0.2.3.tgz", + "integrity": "sha512-SzGLJMxug31Y1P8+0I809ICpDrayztUXFFh2TV02GuwjEnY6mDGnmX56wowZF5yCn+WteeRdcTJTK7Whk3AGYQ==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/sm-provider": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@polkadot-api/sm-provider/-/sm-provider-0.3.8.tgz", + "integrity": "sha512-jIvzBNsBsh6LIpCrUOa7miZdQPwLPns5IUQyz/8v84R3ON7URSIVbtywGSR8O83BZGyW/DmVkqa5lClLE2fkqw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1" + }, + "peerDependencies": { + "@polkadot-api/smoldot": ">=0.3" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/smoldot": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/@polkadot-api/smoldot/-/smoldot-0.4.6.tgz", + "integrity": "sha512-gOXMJ10fXOub0zPP1cGAYeyf29BA2fB+qukrjXGcGN9b0Ya+lDgV7A7Q7y9JOrlGLeKbd1YdrYLAe/F43V7b9Q==", + "license": "MIT", + "dependencies": { + "@types/node": "^25.9.4", + "smoldot": "~3.3.1" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/substrate-bindings": { + "version": "0.20.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-bindings/-/substrate-bindings-0.20.3.tgz", + "integrity": "sha512-9iqC71fx1ee9ld1NZV8PFime5vryi0kt1bKCSlvNgO6dqMc06sMZuZ8WPjOzWLCHiKHLuphdMs3rVBBaeCP3yg==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/utils": "0.4.0", + "@scure/base": "^2.2.0", + "scale-ts": "^1.6.1" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/substrate-client": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-client/-/substrate-client-0.7.0.tgz", + "integrity": "sha512-TWCc4MAMa5SLVQXmomLHknbj+bztQ/Yclgwm8ENBhz8hR7c9rw9FBAkCa02jMBMCAygPhp3ayGRq+UFcF8KIxQ==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/raw-client": "0.3.0", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/utils": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/utils/-/utils-0.4.0.tgz", + "integrity": "sha512-9b/hwRM0UloLWV7SfpNaSD/4k8UQAHoaACAk7Xe+1MlfAm2JtnmPiB1GfGrfTyBlsrJVUIBCZpEmbmxVMaIqBA==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-api/ws-provider": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/ws-provider/-/ws-provider-0.9.1.tgz", + "integrity": "sha512-Ft2QJEjLZgTyKiCEbz3urSOxNfMdqNkg+QKqJhRbOFB7JtR1qMTvLE3TjM+5d2mNlEpOc3j2KDK3APNSj7uQ2Q==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/@polkadot-labs/hdkd-helpers": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@polkadot-labs/hdkd-helpers/-/hdkd-helpers-0.0.30.tgz", + "integrity": "sha512-qWmmD6ayj14RenDuDFfjF3sHS7ObqPzwIIMPcSVoDeKFSeQV7RY0HwyhC5CG4i6FoguMzak2dbtjYpNN5XQiwQ==", + "license": "MIT", + "dependencies": { + "@noble/curves": "^2.2.0", + "@noble/hashes": "^2.2.0", + "@scure/base": "^2.2.0", + "@scure/sr25519": "^1.0.0", + "scale-ts": "^1.6.1" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/polkadot-api": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/polkadot-api/-/polkadot-api-2.2.1.tgz", + "integrity": "sha512-eiZVUhI1gY4ycBtsCo/yaDXyohUeuqnyKun+bwj90ADSn+jlfjZ4sajAqIhJFwPxbCT75+Zzbln4ZjuZ5PWNWA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/cli": "0.21.9", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/logs-provider": "0.2.0", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/pjs-signer": "0.7.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signer": "0.3.3", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@rx-state/core": "^0.1.4" + }, + "bin": { + "papi": "bin/cli.js", + "polkadot-api": "bin/cli.js" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/smoldot": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/smoldot/-/smoldot-3.3.2.tgz", + "integrity": "sha512-Zl4h/0gsw8cfTZzuJ7LV7mtR6QjxltwYjMY7MsVw0oXBXrLK8zyOS6DS9Vjsy57pX1vBMg6UVhHxjbH3W905zA==", + "license": "GPL-3.0-or-later WITH Classpath-exception-2.0", + "dependencies": { + "ws": "^8.8.1" + } + }, + "node_modules/@parity/product-sdk-contracts/node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@parity/product-sdk-crypto": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@parity/product-sdk-crypto/-/product-sdk-crypto-0.1.1.tgz", + "integrity": "sha512-No6AyTLw1Nv3ym8SDdXh/tnezdClNOL9pJgaciVr9Ny6hIL5rs6MQiXsP0+1bc1Nwymz5Q4FqsYg/htE4lejNg==", + "license": "Apache-2.0", + "dependencies": { + "@noble/ciphers": "^1.2.1", + "@noble/curves": "^1.8.0", + "@noble/hashes": "^1.7.1", + "tweetnacl": "^1.0.3" + } + }, + "node_modules/@parity/product-sdk-crypto/node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@parity/product-sdk-crypto/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@parity/product-sdk-descriptors": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@parity/product-sdk-descriptors/-/product-sdk-descriptors-0.8.0.tgz", + "integrity": "sha512-DfdrtzjBqiS4A/fnqoDOyW+KiBVKkOtfDDl1/BLHtvYxp3TanPkS952Sd28F7v1Rk/0xnqm8d7shD06/XoLqhg==", + "license": "Apache-2.0", + "dependencies": { + "polkadot-api": "^2.1.6" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@commander-js/extra-typings": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commander-js/extra-typings/-/extra-typings-15.0.0.tgz", + "integrity": "sha512-yeJlba62xqmkgELUsn7356MEnzLLu/fw2x4lofFqGnXh6YysRdEs2BaLeLtg1+KU0AXvMeqQvTTp+3hBEBK+EA==", + "license": "MIT", + "peerDependencies": { + "commander": "~15.0.0" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/cli": { + "version": "0.21.9", + "resolved": "https://registry.npmjs.org/@polkadot-api/cli/-/cli-0.21.9.tgz", + "integrity": "sha512-9aVdF/ocF3DBb8b/gdkcicBIaQkak2kkU4EGW+TunXLIvbIj2X9hH5geOlx8uWNwt0O4O1DIHD/nkXvycG/AcA==", + "license": "MIT", + "dependencies": { + "@commander-js/extra-typings": "^15.0.0", + "@polkadot-api/codegen": "0.22.5", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/wasm-executor": "^0.2.3", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@types/node": "^25.9.4", + "commander": "^15.0.0", + "execa": "^9.6.1", + "fs.promises.exists": "^1.1.4", + "ora": "^9.4.1", + "read-pkg": "^10.1.0", + "rollup": "^4.62.2", + "rollup-plugin-esbuild": "^6.2.1", + "rxjs": "^7.8.2", + "tsc-prog": "^2.3.0", + "typescript": "^6.0.3", + "write-package": "^7.2.0" + }, + "bin": { + "papi": "dist/main/src/main.js", + "polkadot-api": "dist/main/src/main.js" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/codegen": { + "version": "0.22.5", + "resolved": "https://registry.npmjs.org/@polkadot-api/codegen/-/codegen-0.22.5.tgz", + "integrity": "sha512-zwZJAlviI211zhj5i6oXkrr0crrbO3GZjBd2vC9AshY1pRmyiNLV9DZsXw4E6l4JQwdAAyNWtPdnvvB9T3TpKg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/ink-contracts": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/ink-contracts/-/ink-contracts-0.6.3.tgz", + "integrity": "sha512-XqnM1VDzI5L62xgg+f8le2yEoz8QZbUKEfAfPnHMOgBj9tJiyF15FcOJmnLMO/vq3cGixqh18tzJekLG5YTxtA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/json-rpc-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider/-/json-rpc-provider-0.2.0.tgz", + "integrity": "sha512-lhkuBS/x06i3djQIN7p8jVkMnYuGsUAEMS6RhdWeEpz7X/8/APER4Wdih7MEBovCuwVSCTjOxl8f+alH7AZHZg==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/json-rpc-provider-proxy": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider-proxy/-/json-rpc-provider-proxy-0.4.1.tgz", + "integrity": "sha512-F1Hw01C60jn98KQ0vBbgcwAvEcMcKLsJ5kFzq600sgjc6Rnbn1VF/XjTdrjcIqvfpR9sXyGIrpImrov2Usbrsw==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/known-chains": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/known-chains/-/known-chains-0.12.1.tgz", + "integrity": "sha512-ZW9TYD2y5IhgNy28zi9sByMr0CaP2I9x8HcAI0pwZR2qDC0kysCG6brDlg1UoZKCjRO99SsKO/iU1o434JgMnQ==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/logs-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/logs-provider/-/logs-provider-0.2.0.tgz", + "integrity": "sha512-BH9YdxZu+ZBPPAUwGrvqHPn1hQStL2Im3MmTwYkwXOWW2HlGHULcF65QKvyK+T6/mj2vDvl3MgivnGkUw4pVxg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/merkleize-metadata": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/merkleize-metadata/-/merkleize-metadata-1.2.3.tgz", + "integrity": "sha512-WkPbz0p2XQ9c8yXagdnwCHEB70Gnm91okcsd6IXU393//3aPgkxKgb+/Efnz7C5/KQmg02P0zXo7q/n/W/yVCA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/metadata-builders": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-builders/-/metadata-builders-0.14.3.tgz", + "integrity": "sha512-m7CACsiqHzgVEh5WBZGkTV8AQ3CBQKR1YpPQMnlsJfCr/IkgKU0UyWM6WxCmBiReLFVkOfXMtGlpN8+GxpHmww==", + "license": "MIT", + "dependencies": { + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/metadata-compatibility": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-compatibility/-/metadata-compatibility-0.6.3.tgz", + "integrity": "sha512-/Y0uF8nDk60ijydp8Bd37YexPFdB8hBXJWwEgOJHsVlhiny8sVKXiMg+UkJ9BiEk2z+yMbZRCKmhNpTpizo7aw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/observable-client": { + "version": "0.18.7", + "resolved": "https://registry.npmjs.org/@polkadot-api/observable-client/-/observable-client-0.18.7.tgz", + "integrity": "sha512-/eQi3D8jbXLg/L1hZX4eX0/+nO3kTxkOfYeWEtFhtOvFdfqiiy2DdXG3Zg5QzgHmfG+11p4vSlLiPCC2UvS5Qw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/pjs-signer": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/pjs-signer/-/pjs-signer-0.7.3.tgz", + "integrity": "sha512-U7BLFZfnpFMxCh/scJoLXT6oSbfZtZgMTkiu+TbuWQljAb/1ttrQOfshub5VihNyD5rHajp/2Fq0ONZoL5N5PA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/raw-client": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/raw-client/-/raw-client-0.3.0.tgz", + "integrity": "sha512-u/wM9W7ugIXxBSOEV8+zvQI43b5vgSI0pvE0Rg8PV0G65BTLK0SMc2o2SQL0HtS5+bi5sw/gg4reBJ/0a4U0cw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/signer": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signer/-/signer-0.3.3.tgz", + "integrity": "sha512-bmEV65TwgwbMfiecl7ZQ3k5lfkCOx9FPwPYkVvALcPiqb/d3zYwT9LL/E00hj+EB6IKMlMelEQVuchcW5i/92w==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/merkleize-metadata": "1.2.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/signers-common": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signers-common/-/signers-common-0.2.3.tgz", + "integrity": "sha512-SzGLJMxug31Y1P8+0I809ICpDrayztUXFFh2TV02GuwjEnY6mDGnmX56wowZF5yCn+WteeRdcTJTK7Whk3AGYQ==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/sm-provider": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@polkadot-api/sm-provider/-/sm-provider-0.3.8.tgz", + "integrity": "sha512-jIvzBNsBsh6LIpCrUOa7miZdQPwLPns5IUQyz/8v84R3ON7URSIVbtywGSR8O83BZGyW/DmVkqa5lClLE2fkqw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1" + }, + "peerDependencies": { + "@polkadot-api/smoldot": ">=0.3" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/smoldot": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/@polkadot-api/smoldot/-/smoldot-0.4.6.tgz", + "integrity": "sha512-gOXMJ10fXOub0zPP1cGAYeyf29BA2fB+qukrjXGcGN9b0Ya+lDgV7A7Q7y9JOrlGLeKbd1YdrYLAe/F43V7b9Q==", + "license": "MIT", + "dependencies": { + "@types/node": "^25.9.4", + "smoldot": "~3.3.1" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/substrate-bindings": { + "version": "0.20.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-bindings/-/substrate-bindings-0.20.3.tgz", + "integrity": "sha512-9iqC71fx1ee9ld1NZV8PFime5vryi0kt1bKCSlvNgO6dqMc06sMZuZ8WPjOzWLCHiKHLuphdMs3rVBBaeCP3yg==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/utils": "0.4.0", + "@scure/base": "^2.2.0", + "scale-ts": "^1.6.1" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/substrate-client": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-client/-/substrate-client-0.7.0.tgz", + "integrity": "sha512-TWCc4MAMa5SLVQXmomLHknbj+bztQ/Yclgwm8ENBhz8hR7c9rw9FBAkCa02jMBMCAygPhp3ayGRq+UFcF8KIxQ==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/raw-client": "0.3.0", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/utils": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/utils/-/utils-0.4.0.tgz", + "integrity": "sha512-9b/hwRM0UloLWV7SfpNaSD/4k8UQAHoaACAk7Xe+1MlfAm2JtnmPiB1GfGrfTyBlsrJVUIBCZpEmbmxVMaIqBA==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/@polkadot-api/ws-provider": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/ws-provider/-/ws-provider-0.9.1.tgz", + "integrity": "sha512-Ft2QJEjLZgTyKiCEbz3urSOxNfMdqNkg+QKqJhRbOFB7JtR1qMTvLE3TjM+5d2mNlEpOc3j2KDK3APNSj7uQ2Q==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/polkadot-api": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/polkadot-api/-/polkadot-api-2.2.1.tgz", + "integrity": "sha512-eiZVUhI1gY4ycBtsCo/yaDXyohUeuqnyKun+bwj90ADSn+jlfjZ4sajAqIhJFwPxbCT75+Zzbln4ZjuZ5PWNWA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/cli": "0.21.9", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/logs-provider": "0.2.0", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/pjs-signer": "0.7.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signer": "0.3.3", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@rx-state/core": "^0.1.4" + }, + "bin": { + "papi": "bin/cli.js", + "polkadot-api": "bin/cli.js" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/smoldot": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/smoldot/-/smoldot-3.3.2.tgz", + "integrity": "sha512-Zl4h/0gsw8cfTZzuJ7LV7mtR6QjxltwYjMY7MsVw0oXBXrLK8zyOS6DS9Vjsy57pX1vBMg6UVhHxjbH3W905zA==", + "license": "GPL-3.0-or-later WITH Classpath-exception-2.0", + "dependencies": { + "ws": "^8.8.1" + } + }, + "node_modules/@parity/product-sdk-descriptors/node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@parity/product-sdk-errors": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@parity/product-sdk-errors/-/product-sdk-errors-0.2.0.tgz", + "integrity": "sha512-2rvJV0iJyNAxSjm+RHcoch3GRGYgfMDd2wCha+LmykIDZ06oUfFo+wY6Jf8z56ZMMqHvBvDO1ZNrstVgUZxlEQ==", + "license": "Apache-2.0" + }, + "node_modules/@parity/product-sdk-host": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@parity/product-sdk-host/-/product-sdk-host-0.14.1.tgz", + "integrity": "sha512-PF87O0Kb35TyZo+sDlcYo9ZvaUedR8NNbcZvfBf8PBL65Yck10jIDuXE386hl9pgpgOn6o0Y1z6iJfEolhNXsg==", + "license": "Apache-2.0", + "dependencies": { + "@parity/product-sdk-errors": "0.2.0", + "@parity/product-sdk-logger": "0.1.1", + "@parity/result": "0.2.0", + "@parity/truapi": "^0.5.0", + "@polkadot-api/json-rpc-provider": "^0.2.0", + "@polkadot-api/substrate-bindings": "^0.20.3", + "neverthrow": "^8.2.0", + "polkadot-api": "^2.1.6" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@commander-js/extra-typings": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commander-js/extra-typings/-/extra-typings-15.0.0.tgz", + "integrity": "sha512-yeJlba62xqmkgELUsn7356MEnzLLu/fw2x4lofFqGnXh6YysRdEs2BaLeLtg1+KU0AXvMeqQvTTp+3hBEBK+EA==", + "license": "MIT", + "peerDependencies": { + "commander": "~15.0.0" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/cli": { + "version": "0.21.9", + "resolved": "https://registry.npmjs.org/@polkadot-api/cli/-/cli-0.21.9.tgz", + "integrity": "sha512-9aVdF/ocF3DBb8b/gdkcicBIaQkak2kkU4EGW+TunXLIvbIj2X9hH5geOlx8uWNwt0O4O1DIHD/nkXvycG/AcA==", + "license": "MIT", + "dependencies": { + "@commander-js/extra-typings": "^15.0.0", + "@polkadot-api/codegen": "0.22.5", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/wasm-executor": "^0.2.3", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@types/node": "^25.9.4", + "commander": "^15.0.0", + "execa": "^9.6.1", + "fs.promises.exists": "^1.1.4", + "ora": "^9.4.1", + "read-pkg": "^10.1.0", + "rollup": "^4.62.2", + "rollup-plugin-esbuild": "^6.2.1", + "rxjs": "^7.8.2", + "tsc-prog": "^2.3.0", + "typescript": "^6.0.3", + "write-package": "^7.2.0" + }, + "bin": { + "papi": "dist/main/src/main.js", + "polkadot-api": "dist/main/src/main.js" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/codegen": { + "version": "0.22.5", + "resolved": "https://registry.npmjs.org/@polkadot-api/codegen/-/codegen-0.22.5.tgz", + "integrity": "sha512-zwZJAlviI211zhj5i6oXkrr0crrbO3GZjBd2vC9AshY1pRmyiNLV9DZsXw4E6l4JQwdAAyNWtPdnvvB9T3TpKg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/ink-contracts": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/ink-contracts/-/ink-contracts-0.6.3.tgz", + "integrity": "sha512-XqnM1VDzI5L62xgg+f8le2yEoz8QZbUKEfAfPnHMOgBj9tJiyF15FcOJmnLMO/vq3cGixqh18tzJekLG5YTxtA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/json-rpc-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider/-/json-rpc-provider-0.2.0.tgz", + "integrity": "sha512-lhkuBS/x06i3djQIN7p8jVkMnYuGsUAEMS6RhdWeEpz7X/8/APER4Wdih7MEBovCuwVSCTjOxl8f+alH7AZHZg==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/json-rpc-provider-proxy": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider-proxy/-/json-rpc-provider-proxy-0.4.1.tgz", + "integrity": "sha512-F1Hw01C60jn98KQ0vBbgcwAvEcMcKLsJ5kFzq600sgjc6Rnbn1VF/XjTdrjcIqvfpR9sXyGIrpImrov2Usbrsw==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/known-chains": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/known-chains/-/known-chains-0.12.1.tgz", + "integrity": "sha512-ZW9TYD2y5IhgNy28zi9sByMr0CaP2I9x8HcAI0pwZR2qDC0kysCG6brDlg1UoZKCjRO99SsKO/iU1o434JgMnQ==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/logs-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/logs-provider/-/logs-provider-0.2.0.tgz", + "integrity": "sha512-BH9YdxZu+ZBPPAUwGrvqHPn1hQStL2Im3MmTwYkwXOWW2HlGHULcF65QKvyK+T6/mj2vDvl3MgivnGkUw4pVxg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/merkleize-metadata": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/merkleize-metadata/-/merkleize-metadata-1.2.3.tgz", + "integrity": "sha512-WkPbz0p2XQ9c8yXagdnwCHEB70Gnm91okcsd6IXU393//3aPgkxKgb+/Efnz7C5/KQmg02P0zXo7q/n/W/yVCA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/metadata-builders": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-builders/-/metadata-builders-0.14.3.tgz", + "integrity": "sha512-m7CACsiqHzgVEh5WBZGkTV8AQ3CBQKR1YpPQMnlsJfCr/IkgKU0UyWM6WxCmBiReLFVkOfXMtGlpN8+GxpHmww==", + "license": "MIT", + "dependencies": { + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/metadata-compatibility": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-compatibility/-/metadata-compatibility-0.6.3.tgz", + "integrity": "sha512-/Y0uF8nDk60ijydp8Bd37YexPFdB8hBXJWwEgOJHsVlhiny8sVKXiMg+UkJ9BiEk2z+yMbZRCKmhNpTpizo7aw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/observable-client": { + "version": "0.18.7", + "resolved": "https://registry.npmjs.org/@polkadot-api/observable-client/-/observable-client-0.18.7.tgz", + "integrity": "sha512-/eQi3D8jbXLg/L1hZX4eX0/+nO3kTxkOfYeWEtFhtOvFdfqiiy2DdXG3Zg5QzgHmfG+11p4vSlLiPCC2UvS5Qw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/pjs-signer": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/pjs-signer/-/pjs-signer-0.7.3.tgz", + "integrity": "sha512-U7BLFZfnpFMxCh/scJoLXT6oSbfZtZgMTkiu+TbuWQljAb/1ttrQOfshub5VihNyD5rHajp/2Fq0ONZoL5N5PA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/raw-client": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/raw-client/-/raw-client-0.3.0.tgz", + "integrity": "sha512-u/wM9W7ugIXxBSOEV8+zvQI43b5vgSI0pvE0Rg8PV0G65BTLK0SMc2o2SQL0HtS5+bi5sw/gg4reBJ/0a4U0cw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/signer": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signer/-/signer-0.3.3.tgz", + "integrity": "sha512-bmEV65TwgwbMfiecl7ZQ3k5lfkCOx9FPwPYkVvALcPiqb/d3zYwT9LL/E00hj+EB6IKMlMelEQVuchcW5i/92w==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/merkleize-metadata": "1.2.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/signers-common": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signers-common/-/signers-common-0.2.3.tgz", + "integrity": "sha512-SzGLJMxug31Y1P8+0I809ICpDrayztUXFFh2TV02GuwjEnY6mDGnmX56wowZF5yCn+WteeRdcTJTK7Whk3AGYQ==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/sm-provider": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@polkadot-api/sm-provider/-/sm-provider-0.3.8.tgz", + "integrity": "sha512-jIvzBNsBsh6LIpCrUOa7miZdQPwLPns5IUQyz/8v84R3ON7URSIVbtywGSR8O83BZGyW/DmVkqa5lClLE2fkqw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1" + }, + "peerDependencies": { + "@polkadot-api/smoldot": ">=0.3" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/smoldot": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/@polkadot-api/smoldot/-/smoldot-0.4.6.tgz", + "integrity": "sha512-gOXMJ10fXOub0zPP1cGAYeyf29BA2fB+qukrjXGcGN9b0Ya+lDgV7A7Q7y9JOrlGLeKbd1YdrYLAe/F43V7b9Q==", + "license": "MIT", + "dependencies": { + "@types/node": "^25.9.4", + "smoldot": "~3.3.1" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/substrate-bindings": { + "version": "0.20.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-bindings/-/substrate-bindings-0.20.3.tgz", + "integrity": "sha512-9iqC71fx1ee9ld1NZV8PFime5vryi0kt1bKCSlvNgO6dqMc06sMZuZ8WPjOzWLCHiKHLuphdMs3rVBBaeCP3yg==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/utils": "0.4.0", + "@scure/base": "^2.2.0", + "scale-ts": "^1.6.1" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/substrate-client": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-client/-/substrate-client-0.7.0.tgz", + "integrity": "sha512-TWCc4MAMa5SLVQXmomLHknbj+bztQ/Yclgwm8ENBhz8hR7c9rw9FBAkCa02jMBMCAygPhp3ayGRq+UFcF8KIxQ==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/raw-client": "0.3.0", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/utils": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/utils/-/utils-0.4.0.tgz", + "integrity": "sha512-9b/hwRM0UloLWV7SfpNaSD/4k8UQAHoaACAk7Xe+1MlfAm2JtnmPiB1GfGrfTyBlsrJVUIBCZpEmbmxVMaIqBA==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-host/node_modules/@polkadot-api/ws-provider": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/ws-provider/-/ws-provider-0.9.1.tgz", + "integrity": "sha512-Ft2QJEjLZgTyKiCEbz3urSOxNfMdqNkg+QKqJhRbOFB7JtR1qMTvLE3TjM+5d2mNlEpOc3j2KDK3APNSj7uQ2Q==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/polkadot-api": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/polkadot-api/-/polkadot-api-2.2.1.tgz", + "integrity": "sha512-eiZVUhI1gY4ycBtsCo/yaDXyohUeuqnyKun+bwj90ADSn+jlfjZ4sajAqIhJFwPxbCT75+Zzbln4ZjuZ5PWNWA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/cli": "0.21.9", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/logs-provider": "0.2.0", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/pjs-signer": "0.7.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signer": "0.3.3", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@rx-state/core": "^0.1.4" + }, + "bin": { + "papi": "bin/cli.js", + "polkadot-api": "bin/cli.js" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/smoldot": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/smoldot/-/smoldot-3.3.2.tgz", + "integrity": "sha512-Zl4h/0gsw8cfTZzuJ7LV7mtR6QjxltwYjMY7MsVw0oXBXrLK8zyOS6DS9Vjsy57pX1vBMg6UVhHxjbH3W905zA==", + "license": "GPL-3.0-or-later WITH Classpath-exception-2.0", + "dependencies": { + "ws": "^8.8.1" + } + }, + "node_modules/@parity/product-sdk-host/node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@parity/product-sdk-keys": { + "version": "0.3.16", + "resolved": "https://registry.npmjs.org/@parity/product-sdk-keys/-/product-sdk-keys-0.3.16.tgz", + "integrity": "sha512-dnaHPQVOyxE7yEET/NsHi/0l8rI+vkH0m1OaZQ+qMkv4zwrFqXbhcXO7z6Kj+RHp5hswkmrcpEmjl4DeV5Z2xQ==", + "license": "Apache-2.0", + "dependencies": { + "@parity/product-sdk-address": "0.1.1", + "@parity/product-sdk-crypto": "0.1.1", + "@parity/product-sdk-local-storage": "0.3.2", + "@polkadot-labs/hdkd": "^0.0.28", + "@polkadot-labs/hdkd-helpers": "^0.0.30", + "@scure/sr25519": "^2.2.0", + "polkadot-api": "^2.1.6", + "scale-ts": "^1.6.1" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@commander-js/extra-typings": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commander-js/extra-typings/-/extra-typings-15.0.0.tgz", + "integrity": "sha512-yeJlba62xqmkgELUsn7356MEnzLLu/fw2x4lofFqGnXh6YysRdEs2BaLeLtg1+KU0AXvMeqQvTTp+3hBEBK+EA==", + "license": "MIT", + "peerDependencies": { + "commander": "~15.0.0" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/cli": { + "version": "0.21.9", + "resolved": "https://registry.npmjs.org/@polkadot-api/cli/-/cli-0.21.9.tgz", + "integrity": "sha512-9aVdF/ocF3DBb8b/gdkcicBIaQkak2kkU4EGW+TunXLIvbIj2X9hH5geOlx8uWNwt0O4O1DIHD/nkXvycG/AcA==", + "license": "MIT", + "dependencies": { + "@commander-js/extra-typings": "^15.0.0", + "@polkadot-api/codegen": "0.22.5", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/wasm-executor": "^0.2.3", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@types/node": "^25.9.4", + "commander": "^15.0.0", + "execa": "^9.6.1", + "fs.promises.exists": "^1.1.4", + "ora": "^9.4.1", + "read-pkg": "^10.1.0", + "rollup": "^4.62.2", + "rollup-plugin-esbuild": "^6.2.1", + "rxjs": "^7.8.2", + "tsc-prog": "^2.3.0", + "typescript": "^6.0.3", + "write-package": "^7.2.0" + }, + "bin": { + "papi": "dist/main/src/main.js", + "polkadot-api": "dist/main/src/main.js" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/codegen": { + "version": "0.22.5", + "resolved": "https://registry.npmjs.org/@polkadot-api/codegen/-/codegen-0.22.5.tgz", + "integrity": "sha512-zwZJAlviI211zhj5i6oXkrr0crrbO3GZjBd2vC9AshY1pRmyiNLV9DZsXw4E6l4JQwdAAyNWtPdnvvB9T3TpKg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/ink-contracts": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/ink-contracts/-/ink-contracts-0.6.3.tgz", + "integrity": "sha512-XqnM1VDzI5L62xgg+f8le2yEoz8QZbUKEfAfPnHMOgBj9tJiyF15FcOJmnLMO/vq3cGixqh18tzJekLG5YTxtA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/json-rpc-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider/-/json-rpc-provider-0.2.0.tgz", + "integrity": "sha512-lhkuBS/x06i3djQIN7p8jVkMnYuGsUAEMS6RhdWeEpz7X/8/APER4Wdih7MEBovCuwVSCTjOxl8f+alH7AZHZg==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/json-rpc-provider-proxy": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider-proxy/-/json-rpc-provider-proxy-0.4.1.tgz", + "integrity": "sha512-F1Hw01C60jn98KQ0vBbgcwAvEcMcKLsJ5kFzq600sgjc6Rnbn1VF/XjTdrjcIqvfpR9sXyGIrpImrov2Usbrsw==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/known-chains": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/known-chains/-/known-chains-0.12.1.tgz", + "integrity": "sha512-ZW9TYD2y5IhgNy28zi9sByMr0CaP2I9x8HcAI0pwZR2qDC0kysCG6brDlg1UoZKCjRO99SsKO/iU1o434JgMnQ==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/logs-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/logs-provider/-/logs-provider-0.2.0.tgz", + "integrity": "sha512-BH9YdxZu+ZBPPAUwGrvqHPn1hQStL2Im3MmTwYkwXOWW2HlGHULcF65QKvyK+T6/mj2vDvl3MgivnGkUw4pVxg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/merkleize-metadata": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/merkleize-metadata/-/merkleize-metadata-1.2.3.tgz", + "integrity": "sha512-WkPbz0p2XQ9c8yXagdnwCHEB70Gnm91okcsd6IXU393//3aPgkxKgb+/Efnz7C5/KQmg02P0zXo7q/n/W/yVCA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/metadata-builders": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-builders/-/metadata-builders-0.14.3.tgz", + "integrity": "sha512-m7CACsiqHzgVEh5WBZGkTV8AQ3CBQKR1YpPQMnlsJfCr/IkgKU0UyWM6WxCmBiReLFVkOfXMtGlpN8+GxpHmww==", + "license": "MIT", + "dependencies": { + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/metadata-compatibility": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-compatibility/-/metadata-compatibility-0.6.3.tgz", + "integrity": "sha512-/Y0uF8nDk60ijydp8Bd37YexPFdB8hBXJWwEgOJHsVlhiny8sVKXiMg+UkJ9BiEk2z+yMbZRCKmhNpTpizo7aw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/observable-client": { + "version": "0.18.7", + "resolved": "https://registry.npmjs.org/@polkadot-api/observable-client/-/observable-client-0.18.7.tgz", + "integrity": "sha512-/eQi3D8jbXLg/L1hZX4eX0/+nO3kTxkOfYeWEtFhtOvFdfqiiy2DdXG3Zg5QzgHmfG+11p4vSlLiPCC2UvS5Qw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/pjs-signer": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/pjs-signer/-/pjs-signer-0.7.3.tgz", + "integrity": "sha512-U7BLFZfnpFMxCh/scJoLXT6oSbfZtZgMTkiu+TbuWQljAb/1ttrQOfshub5VihNyD5rHajp/2Fq0ONZoL5N5PA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/raw-client": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/raw-client/-/raw-client-0.3.0.tgz", + "integrity": "sha512-u/wM9W7ugIXxBSOEV8+zvQI43b5vgSI0pvE0Rg8PV0G65BTLK0SMc2o2SQL0HtS5+bi5sw/gg4reBJ/0a4U0cw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/signer": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signer/-/signer-0.3.3.tgz", + "integrity": "sha512-bmEV65TwgwbMfiecl7ZQ3k5lfkCOx9FPwPYkVvALcPiqb/d3zYwT9LL/E00hj+EB6IKMlMelEQVuchcW5i/92w==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/merkleize-metadata": "1.2.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/signers-common": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signers-common/-/signers-common-0.2.3.tgz", + "integrity": "sha512-SzGLJMxug31Y1P8+0I809ICpDrayztUXFFh2TV02GuwjEnY6mDGnmX56wowZF5yCn+WteeRdcTJTK7Whk3AGYQ==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/sm-provider": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@polkadot-api/sm-provider/-/sm-provider-0.3.8.tgz", + "integrity": "sha512-jIvzBNsBsh6LIpCrUOa7miZdQPwLPns5IUQyz/8v84R3ON7URSIVbtywGSR8O83BZGyW/DmVkqa5lClLE2fkqw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1" + }, + "peerDependencies": { + "@polkadot-api/smoldot": ">=0.3" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/smoldot": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/@polkadot-api/smoldot/-/smoldot-0.4.6.tgz", + "integrity": "sha512-gOXMJ10fXOub0zPP1cGAYeyf29BA2fB+qukrjXGcGN9b0Ya+lDgV7A7Q7y9JOrlGLeKbd1YdrYLAe/F43V7b9Q==", + "license": "MIT", + "dependencies": { + "@types/node": "^25.9.4", + "smoldot": "~3.3.1" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/substrate-bindings": { + "version": "0.20.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-bindings/-/substrate-bindings-0.20.3.tgz", + "integrity": "sha512-9iqC71fx1ee9ld1NZV8PFime5vryi0kt1bKCSlvNgO6dqMc06sMZuZ8WPjOzWLCHiKHLuphdMs3rVBBaeCP3yg==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/utils": "0.4.0", + "@scure/base": "^2.2.0", + "scale-ts": "^1.6.1" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/substrate-client": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-client/-/substrate-client-0.7.0.tgz", + "integrity": "sha512-TWCc4MAMa5SLVQXmomLHknbj+bztQ/Yclgwm8ENBhz8hR7c9rw9FBAkCa02jMBMCAygPhp3ayGRq+UFcF8KIxQ==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/raw-client": "0.3.0", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/utils": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/utils/-/utils-0.4.0.tgz", + "integrity": "sha512-9b/hwRM0UloLWV7SfpNaSD/4k8UQAHoaACAk7Xe+1MlfAm2JtnmPiB1GfGrfTyBlsrJVUIBCZpEmbmxVMaIqBA==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-api/ws-provider": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/ws-provider/-/ws-provider-0.9.1.tgz", + "integrity": "sha512-Ft2QJEjLZgTyKiCEbz3urSOxNfMdqNkg+QKqJhRbOFB7JtR1qMTvLE3TjM+5d2mNlEpOc3j2KDK3APNSj7uQ2Q==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-labs/hdkd": { + "version": "0.0.28", + "resolved": "https://registry.npmjs.org/@polkadot-labs/hdkd/-/hdkd-0.0.28.tgz", + "integrity": "sha512-LpdqtQRpcgZQ5Mr8J0ddMA5ZufsbI4W3KuJkVdoYMnSmWs4179LigDb1rTYAOtyCg2jWUjf7rWP0mGxQQvNrHw==", + "license": "MIT", + "dependencies": { + "@polkadot-labs/hdkd-helpers": "~0.0.29" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-labs/hdkd-helpers": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@polkadot-labs/hdkd-helpers/-/hdkd-helpers-0.0.30.tgz", + "integrity": "sha512-qWmmD6ayj14RenDuDFfjF3sHS7ObqPzwIIMPcSVoDeKFSeQV7RY0HwyhC5CG4i6FoguMzak2dbtjYpNN5XQiwQ==", + "license": "MIT", + "dependencies": { + "@noble/curves": "^2.2.0", + "@noble/hashes": "^2.2.0", + "@scure/base": "^2.2.0", + "@scure/sr25519": "^1.0.0", + "scale-ts": "^1.6.1" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-labs/hdkd-helpers/node_modules/@scure/sr25519": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@scure/sr25519/-/sr25519-1.0.0.tgz", + "integrity": "sha512-b+uhK5akMINXZP95F3gJGcb5CMKYxf+q55fwMl0GoBwZDbWolmGNi1FrBSwuaZX5AhqS2byHiAueZgtDNpot2A==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~2.0.0", + "@noble/hashes": "~2.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-labs/hdkd-helpers/node_modules/@scure/sr25519/node_modules/@noble/curves": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.0.1.tgz", + "integrity": "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "2.0.1" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@polkadot-labs/hdkd-helpers/node_modules/@scure/sr25519/node_modules/@noble/hashes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", + "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/@scure/sr25519": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@scure/sr25519/-/sr25519-2.2.0.tgz", + "integrity": "sha512-UTOZb6Hzw44REQdl2SWNBhBFIoqOIhMLNIz3zYyVQLbqdshhuyuuxYoibKHlDg9oqdwdCHQe5LkTsevugPpUbw==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~2.2.0", + "@noble/hashes": "~2.2.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/polkadot-api": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/polkadot-api/-/polkadot-api-2.2.1.tgz", + "integrity": "sha512-eiZVUhI1gY4ycBtsCo/yaDXyohUeuqnyKun+bwj90ADSn+jlfjZ4sajAqIhJFwPxbCT75+Zzbln4ZjuZ5PWNWA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/cli": "0.21.9", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/logs-provider": "0.2.0", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/pjs-signer": "0.7.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signer": "0.3.3", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@rx-state/core": "^0.1.4" + }, + "bin": { + "papi": "bin/cli.js", + "polkadot-api": "bin/cli.js" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/smoldot": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/smoldot/-/smoldot-3.3.2.tgz", + "integrity": "sha512-Zl4h/0gsw8cfTZzuJ7LV7mtR6QjxltwYjMY7MsVw0oXBXrLK8zyOS6DS9Vjsy57pX1vBMg6UVhHxjbH3W905zA==", + "license": "GPL-3.0-or-later WITH Classpath-exception-2.0", + "dependencies": { + "ws": "^8.8.1" + } + }, + "node_modules/@parity/product-sdk-keys/node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@parity/product-sdk-local-storage": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@parity/product-sdk-local-storage/-/product-sdk-local-storage-0.3.2.tgz", + "integrity": "sha512-1KJGOZrf6pj1P19j8AVbVC5NTmQe5KGE2VJ0gzJDYCHGWPYECtm7Fc0zfq6AAZbyPJkgsuZz/K4+MRijf4lf2A==", + "license": "Apache-2.0", + "dependencies": { + "@parity/product-sdk-host": "0.14.1", + "@parity/product-sdk-logger": "0.1.1" + } + }, + "node_modules/@parity/product-sdk-logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@parity/product-sdk-logger/-/product-sdk-logger-0.1.1.tgz", + "integrity": "sha512-AiSV3TTNlMZJftLQsO78BZsEymGFuJtGMSpGrJ+vUtqaZavWaW/Hc6MICBLnEYgeCrdNpv7QBso3dRsTfnAZXQ==", + "license": "Apache-2.0" + }, + "node_modules/@parity/product-sdk-signer": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/@parity/product-sdk-signer/-/product-sdk-signer-0.11.1.tgz", + "integrity": "sha512-9wGaazcmqVaSkJckcZhHFkhpPQJSNVgvFRbH2qIXkvAmxKMfW9xzdplsEoMnxRcvUree6I1YK2m3kn61/dBpjw==", + "license": "Apache-2.0", + "dependencies": { + "@parity/product-sdk-address": "0.1.1", + "@parity/product-sdk-errors": "0.2.0", + "@parity/product-sdk-host": "0.14.1", + "@parity/product-sdk-keys": "0.3.16", + "@parity/product-sdk-logger": "0.1.1", + "@parity/result": "0.2.0", + "polkadot-api": "^2.1.6" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@commander-js/extra-typings": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commander-js/extra-typings/-/extra-typings-15.0.0.tgz", + "integrity": "sha512-yeJlba62xqmkgELUsn7356MEnzLLu/fw2x4lofFqGnXh6YysRdEs2BaLeLtg1+KU0AXvMeqQvTTp+3hBEBK+EA==", + "license": "MIT", + "peerDependencies": { + "commander": "~15.0.0" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/cli": { + "version": "0.21.9", + "resolved": "https://registry.npmjs.org/@polkadot-api/cli/-/cli-0.21.9.tgz", + "integrity": "sha512-9aVdF/ocF3DBb8b/gdkcicBIaQkak2kkU4EGW+TunXLIvbIj2X9hH5geOlx8uWNwt0O4O1DIHD/nkXvycG/AcA==", + "license": "MIT", + "dependencies": { + "@commander-js/extra-typings": "^15.0.0", + "@polkadot-api/codegen": "0.22.5", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/wasm-executor": "^0.2.3", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@types/node": "^25.9.4", + "commander": "^15.0.0", + "execa": "^9.6.1", + "fs.promises.exists": "^1.1.4", + "ora": "^9.4.1", + "read-pkg": "^10.1.0", + "rollup": "^4.62.2", + "rollup-plugin-esbuild": "^6.2.1", + "rxjs": "^7.8.2", + "tsc-prog": "^2.3.0", + "typescript": "^6.0.3", + "write-package": "^7.2.0" + }, + "bin": { + "papi": "dist/main/src/main.js", + "polkadot-api": "dist/main/src/main.js" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/codegen": { + "version": "0.22.5", + "resolved": "https://registry.npmjs.org/@polkadot-api/codegen/-/codegen-0.22.5.tgz", + "integrity": "sha512-zwZJAlviI211zhj5i6oXkrr0crrbO3GZjBd2vC9AshY1pRmyiNLV9DZsXw4E6l4JQwdAAyNWtPdnvvB9T3TpKg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/ink-contracts": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/ink-contracts/-/ink-contracts-0.6.3.tgz", + "integrity": "sha512-XqnM1VDzI5L62xgg+f8le2yEoz8QZbUKEfAfPnHMOgBj9tJiyF15FcOJmnLMO/vq3cGixqh18tzJekLG5YTxtA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/json-rpc-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider/-/json-rpc-provider-0.2.0.tgz", + "integrity": "sha512-lhkuBS/x06i3djQIN7p8jVkMnYuGsUAEMS6RhdWeEpz7X/8/APER4Wdih7MEBovCuwVSCTjOxl8f+alH7AZHZg==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/json-rpc-provider-proxy": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider-proxy/-/json-rpc-provider-proxy-0.4.1.tgz", + "integrity": "sha512-F1Hw01C60jn98KQ0vBbgcwAvEcMcKLsJ5kFzq600sgjc6Rnbn1VF/XjTdrjcIqvfpR9sXyGIrpImrov2Usbrsw==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/known-chains": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/known-chains/-/known-chains-0.12.1.tgz", + "integrity": "sha512-ZW9TYD2y5IhgNy28zi9sByMr0CaP2I9x8HcAI0pwZR2qDC0kysCG6brDlg1UoZKCjRO99SsKO/iU1o434JgMnQ==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/logs-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/logs-provider/-/logs-provider-0.2.0.tgz", + "integrity": "sha512-BH9YdxZu+ZBPPAUwGrvqHPn1hQStL2Im3MmTwYkwXOWW2HlGHULcF65QKvyK+T6/mj2vDvl3MgivnGkUw4pVxg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/merkleize-metadata": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/merkleize-metadata/-/merkleize-metadata-1.2.3.tgz", + "integrity": "sha512-WkPbz0p2XQ9c8yXagdnwCHEB70Gnm91okcsd6IXU393//3aPgkxKgb+/Efnz7C5/KQmg02P0zXo7q/n/W/yVCA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/metadata-builders": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-builders/-/metadata-builders-0.14.3.tgz", + "integrity": "sha512-m7CACsiqHzgVEh5WBZGkTV8AQ3CBQKR1YpPQMnlsJfCr/IkgKU0UyWM6WxCmBiReLFVkOfXMtGlpN8+GxpHmww==", + "license": "MIT", + "dependencies": { + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/metadata-compatibility": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-compatibility/-/metadata-compatibility-0.6.3.tgz", + "integrity": "sha512-/Y0uF8nDk60ijydp8Bd37YexPFdB8hBXJWwEgOJHsVlhiny8sVKXiMg+UkJ9BiEk2z+yMbZRCKmhNpTpizo7aw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/observable-client": { + "version": "0.18.7", + "resolved": "https://registry.npmjs.org/@polkadot-api/observable-client/-/observable-client-0.18.7.tgz", + "integrity": "sha512-/eQi3D8jbXLg/L1hZX4eX0/+nO3kTxkOfYeWEtFhtOvFdfqiiy2DdXG3Zg5QzgHmfG+11p4vSlLiPCC2UvS5Qw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/pjs-signer": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/pjs-signer/-/pjs-signer-0.7.3.tgz", + "integrity": "sha512-U7BLFZfnpFMxCh/scJoLXT6oSbfZtZgMTkiu+TbuWQljAb/1ttrQOfshub5VihNyD5rHajp/2Fq0ONZoL5N5PA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/raw-client": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/raw-client/-/raw-client-0.3.0.tgz", + "integrity": "sha512-u/wM9W7ugIXxBSOEV8+zvQI43b5vgSI0pvE0Rg8PV0G65BTLK0SMc2o2SQL0HtS5+bi5sw/gg4reBJ/0a4U0cw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/signer": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signer/-/signer-0.3.3.tgz", + "integrity": "sha512-bmEV65TwgwbMfiecl7ZQ3k5lfkCOx9FPwPYkVvALcPiqb/d3zYwT9LL/E00hj+EB6IKMlMelEQVuchcW5i/92w==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/merkleize-metadata": "1.2.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/signers-common": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signers-common/-/signers-common-0.2.3.tgz", + "integrity": "sha512-SzGLJMxug31Y1P8+0I809ICpDrayztUXFFh2TV02GuwjEnY6mDGnmX56wowZF5yCn+WteeRdcTJTK7Whk3AGYQ==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/sm-provider": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@polkadot-api/sm-provider/-/sm-provider-0.3.8.tgz", + "integrity": "sha512-jIvzBNsBsh6LIpCrUOa7miZdQPwLPns5IUQyz/8v84R3ON7URSIVbtywGSR8O83BZGyW/DmVkqa5lClLE2fkqw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1" + }, + "peerDependencies": { + "@polkadot-api/smoldot": ">=0.3" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/smoldot": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/@polkadot-api/smoldot/-/smoldot-0.4.6.tgz", + "integrity": "sha512-gOXMJ10fXOub0zPP1cGAYeyf29BA2fB+qukrjXGcGN9b0Ya+lDgV7A7Q7y9JOrlGLeKbd1YdrYLAe/F43V7b9Q==", + "license": "MIT", + "dependencies": { + "@types/node": "^25.9.4", + "smoldot": "~3.3.1" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/substrate-bindings": { + "version": "0.20.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-bindings/-/substrate-bindings-0.20.3.tgz", + "integrity": "sha512-9iqC71fx1ee9ld1NZV8PFime5vryi0kt1bKCSlvNgO6dqMc06sMZuZ8WPjOzWLCHiKHLuphdMs3rVBBaeCP3yg==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/utils": "0.4.0", + "@scure/base": "^2.2.0", + "scale-ts": "^1.6.1" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/substrate-client": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-client/-/substrate-client-0.7.0.tgz", + "integrity": "sha512-TWCc4MAMa5SLVQXmomLHknbj+bztQ/Yclgwm8ENBhz8hR7c9rw9FBAkCa02jMBMCAygPhp3ayGRq+UFcF8KIxQ==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/raw-client": "0.3.0", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/utils": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/utils/-/utils-0.4.0.tgz", + "integrity": "sha512-9b/hwRM0UloLWV7SfpNaSD/4k8UQAHoaACAk7Xe+1MlfAm2JtnmPiB1GfGrfTyBlsrJVUIBCZpEmbmxVMaIqBA==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-signer/node_modules/@polkadot-api/ws-provider": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/ws-provider/-/ws-provider-0.9.1.tgz", + "integrity": "sha512-Ft2QJEjLZgTyKiCEbz3urSOxNfMdqNkg+QKqJhRbOFB7JtR1qMTvLE3TjM+5d2mNlEpOc3j2KDK3APNSj7uQ2Q==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/polkadot-api": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/polkadot-api/-/polkadot-api-2.2.1.tgz", + "integrity": "sha512-eiZVUhI1gY4ycBtsCo/yaDXyohUeuqnyKun+bwj90ADSn+jlfjZ4sajAqIhJFwPxbCT75+Zzbln4ZjuZ5PWNWA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/cli": "0.21.9", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/logs-provider": "0.2.0", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/pjs-signer": "0.7.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signer": "0.3.3", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@rx-state/core": "^0.1.4" + }, + "bin": { + "papi": "bin/cli.js", + "polkadot-api": "bin/cli.js" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/smoldot": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/smoldot/-/smoldot-3.3.2.tgz", + "integrity": "sha512-Zl4h/0gsw8cfTZzuJ7LV7mtR6QjxltwYjMY7MsVw0oXBXrLK8zyOS6DS9Vjsy57pX1vBMg6UVhHxjbH3W905zA==", + "license": "GPL-3.0-or-later WITH Classpath-exception-2.0", + "dependencies": { + "ws": "^8.8.1" + } + }, + "node_modules/@parity/product-sdk-signer/node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@parity/product-sdk-tx": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@parity/product-sdk-tx/-/product-sdk-tx-0.3.2.tgz", + "integrity": "sha512-Y10Sw/ZluIAA6+zB9Ty+y0bSwbrEVIeBKN3umrQXHyseDfBmxWEXkwlhjCxnusJ44wtUgrIN9BsNRGI/51ffKQ==", + "license": "Apache-2.0", + "dependencies": { + "@parity/product-sdk-errors": "0.2.0", + "@parity/product-sdk-keys": "0.3.16", + "@parity/product-sdk-logger": "0.1.1", + "@parity/result": "0.2.0", + "@polkadot-labs/hdkd-helpers": "^0.0.30", + "polkadot-api": "^2.1.6" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@commander-js/extra-typings": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commander-js/extra-typings/-/extra-typings-15.0.0.tgz", + "integrity": "sha512-yeJlba62xqmkgELUsn7356MEnzLLu/fw2x4lofFqGnXh6YysRdEs2BaLeLtg1+KU0AXvMeqQvTTp+3hBEBK+EA==", + "license": "MIT", + "peerDependencies": { + "commander": "~15.0.0" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/cli": { + "version": "0.21.9", + "resolved": "https://registry.npmjs.org/@polkadot-api/cli/-/cli-0.21.9.tgz", + "integrity": "sha512-9aVdF/ocF3DBb8b/gdkcicBIaQkak2kkU4EGW+TunXLIvbIj2X9hH5geOlx8uWNwt0O4O1DIHD/nkXvycG/AcA==", + "license": "MIT", + "dependencies": { + "@commander-js/extra-typings": "^15.0.0", + "@polkadot-api/codegen": "0.22.5", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/wasm-executor": "^0.2.3", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@types/node": "^25.9.4", + "commander": "^15.0.0", + "execa": "^9.6.1", + "fs.promises.exists": "^1.1.4", + "ora": "^9.4.1", + "read-pkg": "^10.1.0", + "rollup": "^4.62.2", + "rollup-plugin-esbuild": "^6.2.1", + "rxjs": "^7.8.2", + "tsc-prog": "^2.3.0", + "typescript": "^6.0.3", + "write-package": "^7.2.0" + }, + "bin": { + "papi": "dist/main/src/main.js", + "polkadot-api": "dist/main/src/main.js" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/codegen": { + "version": "0.22.5", + "resolved": "https://registry.npmjs.org/@polkadot-api/codegen/-/codegen-0.22.5.tgz", + "integrity": "sha512-zwZJAlviI211zhj5i6oXkrr0crrbO3GZjBd2vC9AshY1pRmyiNLV9DZsXw4E6l4JQwdAAyNWtPdnvvB9T3TpKg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/ink-contracts": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/ink-contracts/-/ink-contracts-0.6.3.tgz", + "integrity": "sha512-XqnM1VDzI5L62xgg+f8le2yEoz8QZbUKEfAfPnHMOgBj9tJiyF15FcOJmnLMO/vq3cGixqh18tzJekLG5YTxtA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/json-rpc-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider/-/json-rpc-provider-0.2.0.tgz", + "integrity": "sha512-lhkuBS/x06i3djQIN7p8jVkMnYuGsUAEMS6RhdWeEpz7X/8/APER4Wdih7MEBovCuwVSCTjOxl8f+alH7AZHZg==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/json-rpc-provider-proxy": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider-proxy/-/json-rpc-provider-proxy-0.4.1.tgz", + "integrity": "sha512-F1Hw01C60jn98KQ0vBbgcwAvEcMcKLsJ5kFzq600sgjc6Rnbn1VF/XjTdrjcIqvfpR9sXyGIrpImrov2Usbrsw==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/known-chains": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/known-chains/-/known-chains-0.12.1.tgz", + "integrity": "sha512-ZW9TYD2y5IhgNy28zi9sByMr0CaP2I9x8HcAI0pwZR2qDC0kysCG6brDlg1UoZKCjRO99SsKO/iU1o434JgMnQ==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/logs-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/logs-provider/-/logs-provider-0.2.0.tgz", + "integrity": "sha512-BH9YdxZu+ZBPPAUwGrvqHPn1hQStL2Im3MmTwYkwXOWW2HlGHULcF65QKvyK+T6/mj2vDvl3MgivnGkUw4pVxg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/merkleize-metadata": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/merkleize-metadata/-/merkleize-metadata-1.2.3.tgz", + "integrity": "sha512-WkPbz0p2XQ9c8yXagdnwCHEB70Gnm91okcsd6IXU393//3aPgkxKgb+/Efnz7C5/KQmg02P0zXo7q/n/W/yVCA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/metadata-builders": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-builders/-/metadata-builders-0.14.3.tgz", + "integrity": "sha512-m7CACsiqHzgVEh5WBZGkTV8AQ3CBQKR1YpPQMnlsJfCr/IkgKU0UyWM6WxCmBiReLFVkOfXMtGlpN8+GxpHmww==", + "license": "MIT", + "dependencies": { + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/metadata-compatibility": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-compatibility/-/metadata-compatibility-0.6.3.tgz", + "integrity": "sha512-/Y0uF8nDk60ijydp8Bd37YexPFdB8hBXJWwEgOJHsVlhiny8sVKXiMg+UkJ9BiEk2z+yMbZRCKmhNpTpizo7aw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/observable-client": { + "version": "0.18.7", + "resolved": "https://registry.npmjs.org/@polkadot-api/observable-client/-/observable-client-0.18.7.tgz", + "integrity": "sha512-/eQi3D8jbXLg/L1hZX4eX0/+nO3kTxkOfYeWEtFhtOvFdfqiiy2DdXG3Zg5QzgHmfG+11p4vSlLiPCC2UvS5Qw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/pjs-signer": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/pjs-signer/-/pjs-signer-0.7.3.tgz", + "integrity": "sha512-U7BLFZfnpFMxCh/scJoLXT6oSbfZtZgMTkiu+TbuWQljAb/1ttrQOfshub5VihNyD5rHajp/2Fq0ONZoL5N5PA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/raw-client": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/raw-client/-/raw-client-0.3.0.tgz", + "integrity": "sha512-u/wM9W7ugIXxBSOEV8+zvQI43b5vgSI0pvE0Rg8PV0G65BTLK0SMc2o2SQL0HtS5+bi5sw/gg4reBJ/0a4U0cw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/signer": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signer/-/signer-0.3.3.tgz", + "integrity": "sha512-bmEV65TwgwbMfiecl7ZQ3k5lfkCOx9FPwPYkVvALcPiqb/d3zYwT9LL/E00hj+EB6IKMlMelEQVuchcW5i/92w==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/merkleize-metadata": "1.2.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/signers-common": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signers-common/-/signers-common-0.2.3.tgz", + "integrity": "sha512-SzGLJMxug31Y1P8+0I809ICpDrayztUXFFh2TV02GuwjEnY6mDGnmX56wowZF5yCn+WteeRdcTJTK7Whk3AGYQ==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/sm-provider": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@polkadot-api/sm-provider/-/sm-provider-0.3.8.tgz", + "integrity": "sha512-jIvzBNsBsh6LIpCrUOa7miZdQPwLPns5IUQyz/8v84R3ON7URSIVbtywGSR8O83BZGyW/DmVkqa5lClLE2fkqw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1" + }, + "peerDependencies": { + "@polkadot-api/smoldot": ">=0.3" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/smoldot": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/@polkadot-api/smoldot/-/smoldot-0.4.6.tgz", + "integrity": "sha512-gOXMJ10fXOub0zPP1cGAYeyf29BA2fB+qukrjXGcGN9b0Ya+lDgV7A7Q7y9JOrlGLeKbd1YdrYLAe/F43V7b9Q==", + "license": "MIT", + "dependencies": { + "@types/node": "^25.9.4", + "smoldot": "~3.3.1" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/substrate-bindings": { + "version": "0.20.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-bindings/-/substrate-bindings-0.20.3.tgz", + "integrity": "sha512-9iqC71fx1ee9ld1NZV8PFime5vryi0kt1bKCSlvNgO6dqMc06sMZuZ8WPjOzWLCHiKHLuphdMs3rVBBaeCP3yg==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/utils": "0.4.0", + "@scure/base": "^2.2.0", + "scale-ts": "^1.6.1" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/substrate-client": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-client/-/substrate-client-0.7.0.tgz", + "integrity": "sha512-TWCc4MAMa5SLVQXmomLHknbj+bztQ/Yclgwm8ENBhz8hR7c9rw9FBAkCa02jMBMCAygPhp3ayGRq+UFcF8KIxQ==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/raw-client": "0.3.0", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/utils": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/utils/-/utils-0.4.0.tgz", + "integrity": "sha512-9b/hwRM0UloLWV7SfpNaSD/4k8UQAHoaACAk7Xe+1MlfAm2JtnmPiB1GfGrfTyBlsrJVUIBCZpEmbmxVMaIqBA==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-api/ws-provider": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/ws-provider/-/ws-provider-0.9.1.tgz", + "integrity": "sha512-Ft2QJEjLZgTyKiCEbz3urSOxNfMdqNkg+QKqJhRbOFB7JtR1qMTvLE3TjM+5d2mNlEpOc3j2KDK3APNSj7uQ2Q==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/@polkadot-labs/hdkd-helpers": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@polkadot-labs/hdkd-helpers/-/hdkd-helpers-0.0.30.tgz", + "integrity": "sha512-qWmmD6ayj14RenDuDFfjF3sHS7ObqPzwIIMPcSVoDeKFSeQV7RY0HwyhC5CG4i6FoguMzak2dbtjYpNN5XQiwQ==", + "license": "MIT", + "dependencies": { + "@noble/curves": "^2.2.0", + "@noble/hashes": "^2.2.0", + "@scure/base": "^2.2.0", + "@scure/sr25519": "^1.0.0", + "scale-ts": "^1.6.1" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/polkadot-api": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/polkadot-api/-/polkadot-api-2.2.1.tgz", + "integrity": "sha512-eiZVUhI1gY4ycBtsCo/yaDXyohUeuqnyKun+bwj90ADSn+jlfjZ4sajAqIhJFwPxbCT75+Zzbln4ZjuZ5PWNWA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/cli": "0.21.9", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/logs-provider": "0.2.0", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/pjs-signer": "0.7.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signer": "0.3.3", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@rx-state/core": "^0.1.4" + }, + "bin": { + "papi": "bin/cli.js", + "polkadot-api": "bin/cli.js" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/smoldot": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/smoldot/-/smoldot-3.3.2.tgz", + "integrity": "sha512-Zl4h/0gsw8cfTZzuJ7LV7mtR6QjxltwYjMY7MsVw0oXBXrLK8zyOS6DS9Vjsy57pX1vBMg6UVhHxjbH3W905zA==", + "license": "GPL-3.0-or-later WITH Classpath-exception-2.0", + "dependencies": { + "ws": "^8.8.1" + } + }, + "node_modules/@parity/product-sdk-tx/node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@parity/product-sdk/node_modules/@commander-js/extra-typings": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@commander-js/extra-typings/-/extra-typings-15.0.0.tgz", + "integrity": "sha512-yeJlba62xqmkgELUsn7356MEnzLLu/fw2x4lofFqGnXh6YysRdEs2BaLeLtg1+KU0AXvMeqQvTTp+3hBEBK+EA==", + "license": "MIT", + "peerDependencies": { + "commander": "~15.0.0" + } + }, + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/cli": { + "version": "0.21.9", + "resolved": "https://registry.npmjs.org/@polkadot-api/cli/-/cli-0.21.9.tgz", + "integrity": "sha512-9aVdF/ocF3DBb8b/gdkcicBIaQkak2kkU4EGW+TunXLIvbIj2X9hH5geOlx8uWNwt0O4O1DIHD/nkXvycG/AcA==", + "license": "MIT", + "dependencies": { + "@commander-js/extra-typings": "^15.0.0", + "@polkadot-api/codegen": "0.22.5", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/wasm-executor": "^0.2.3", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@types/node": "^25.9.4", + "commander": "^15.0.0", + "execa": "^9.6.1", + "fs.promises.exists": "^1.1.4", + "ora": "^9.4.1", + "read-pkg": "^10.1.0", + "rollup": "^4.62.2", + "rollup-plugin-esbuild": "^6.2.1", + "rxjs": "^7.8.2", + "tsc-prog": "^2.3.0", + "typescript": "^6.0.3", + "write-package": "^7.2.0" + }, + "bin": { + "papi": "dist/main/src/main.js", + "polkadot-api": "dist/main/src/main.js" + } + }, + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/codegen": { + "version": "0.22.5", + "resolved": "https://registry.npmjs.org/@polkadot-api/codegen/-/codegen-0.22.5.tgz", + "integrity": "sha512-zwZJAlviI211zhj5i6oXkrr0crrbO3GZjBd2vC9AshY1pRmyiNLV9DZsXw4E6l4JQwdAAyNWtPdnvvB9T3TpKg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/ink-contracts": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/ink-contracts/-/ink-contracts-0.6.3.tgz", + "integrity": "sha512-XqnM1VDzI5L62xgg+f8le2yEoz8QZbUKEfAfPnHMOgBj9tJiyF15FcOJmnLMO/vq3cGixqh18tzJekLG5YTxtA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/json-rpc-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider/-/json-rpc-provider-0.2.0.tgz", + "integrity": "sha512-lhkuBS/x06i3djQIN7p8jVkMnYuGsUAEMS6RhdWeEpz7X/8/APER4Wdih7MEBovCuwVSCTjOxl8f+alH7AZHZg==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/json-rpc-provider-proxy": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider-proxy/-/json-rpc-provider-proxy-0.4.1.tgz", + "integrity": "sha512-F1Hw01C60jn98KQ0vBbgcwAvEcMcKLsJ5kFzq600sgjc6Rnbn1VF/XjTdrjcIqvfpR9sXyGIrpImrov2Usbrsw==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/known-chains": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/known-chains/-/known-chains-0.12.1.tgz", + "integrity": "sha512-ZW9TYD2y5IhgNy28zi9sByMr0CaP2I9x8HcAI0pwZR2qDC0kysCG6brDlg1UoZKCjRO99SsKO/iU1o434JgMnQ==", + "license": "MIT" + }, + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/logs-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/logs-provider/-/logs-provider-0.2.0.tgz", + "integrity": "sha512-BH9YdxZu+ZBPPAUwGrvqHPn1hQStL2Im3MmTwYkwXOWW2HlGHULcF65QKvyK+T6/mj2vDvl3MgivnGkUw4pVxg==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/merkleize-metadata": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/merkleize-metadata/-/merkleize-metadata-1.2.3.tgz", + "integrity": "sha512-WkPbz0p2XQ9c8yXagdnwCHEB70Gnm91okcsd6IXU393//3aPgkxKgb+/Efnz7C5/KQmg02P0zXo7q/n/W/yVCA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/metadata-builders": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-builders/-/metadata-builders-0.14.3.tgz", + "integrity": "sha512-m7CACsiqHzgVEh5WBZGkTV8AQ3CBQKR1YpPQMnlsJfCr/IkgKU0UyWM6WxCmBiReLFVkOfXMtGlpN8+GxpHmww==", + "license": "MIT", + "dependencies": { + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/metadata-compatibility": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/metadata-compatibility/-/metadata-compatibility-0.6.3.tgz", + "integrity": "sha512-/Y0uF8nDk60ijydp8Bd37YexPFdB8hBXJWwEgOJHsVlhiny8sVKXiMg+UkJ9BiEk2z+yMbZRCKmhNpTpizo7aw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3" + } + }, + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/observable-client": { + "version": "0.18.7", + "resolved": "https://registry.npmjs.org/@polkadot-api/observable-client/-/observable-client-0.18.7.tgz", + "integrity": "sha512-/eQi3D8jbXLg/L1hZX4eX0/+nO3kTxkOfYeWEtFhtOvFdfqiiy2DdXG3Zg5QzgHmfG+11p4vSlLiPCC2UvS5Qw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/pjs-signer": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/pjs-signer/-/pjs-signer-0.7.3.tgz", + "integrity": "sha512-U7BLFZfnpFMxCh/scJoLXT6oSbfZtZgMTkiu+TbuWQljAb/1ttrQOfshub5VihNyD5rHajp/2Fq0ONZoL5N5PA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/raw-client": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/raw-client/-/raw-client-0.3.0.tgz", + "integrity": "sha512-u/wM9W7ugIXxBSOEV8+zvQI43b5vgSI0pvE0Rg8PV0G65BTLK0SMc2o2SQL0HtS5+bi5sw/gg4reBJ/0a4U0cw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/signer": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signer/-/signer-0.3.3.tgz", + "integrity": "sha512-bmEV65TwgwbMfiecl7ZQ3k5lfkCOx9FPwPYkVvALcPiqb/d3zYwT9LL/E00hj+EB6IKMlMelEQVuchcW5i/92w==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/merkleize-metadata": "1.2.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signers-common": "0.2.3", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/signers-common": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/signers-common/-/signers-common-0.2.3.tgz", + "integrity": "sha512-SzGLJMxug31Y1P8+0I809ICpDrayztUXFFh2TV02GuwjEnY6mDGnmX56wowZF5yCn+WteeRdcTJTK7Whk3AGYQ==", + "license": "MIT", + "dependencies": { + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + } + }, + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/sm-provider": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@polkadot-api/sm-provider/-/sm-provider-0.3.8.tgz", + "integrity": "sha512-jIvzBNsBsh6LIpCrUOa7miZdQPwLPns5IUQyz/8v84R3ON7URSIVbtywGSR8O83BZGyW/DmVkqa5lClLE2fkqw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1" + }, + "peerDependencies": { + "@polkadot-api/smoldot": ">=0.3" + } + }, + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/smoldot": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/@polkadot-api/smoldot/-/smoldot-0.4.6.tgz", + "integrity": "sha512-gOXMJ10fXOub0zPP1cGAYeyf29BA2fB+qukrjXGcGN9b0Ya+lDgV7A7Q7y9JOrlGLeKbd1YdrYLAe/F43V7b9Q==", + "license": "MIT", + "dependencies": { + "@types/node": "^25.9.4", + "smoldot": "~3.3.1" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/substrate-bindings": { + "version": "0.20.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-bindings/-/substrate-bindings-0.20.3.tgz", + "integrity": "sha512-9iqC71fx1ee9ld1NZV8PFime5vryi0kt1bKCSlvNgO6dqMc06sMZuZ8WPjOzWLCHiKHLuphdMs3rVBBaeCP3yg==", "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "@noble/hashes": "^2.2.0", + "@polkadot-api/utils": "0.4.0", + "@scure/base": "^2.2.0", + "scale-ts": "^1.6.1" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/substrate-client": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-client/-/substrate-client-0.7.0.tgz", + "integrity": "sha512-TWCc4MAMa5SLVQXmomLHknbj+bztQ/Yclgwm8ENBhz8hR7c9rw9FBAkCa02jMBMCAygPhp3ayGRq+UFcF8KIxQ==", "license": "MIT", - "engines": { - "node": ">=6.0.0" + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/raw-client": "0.3.0", + "@polkadot-api/utils": "0.4.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/utils": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/utils/-/utils-0.4.0.tgz", + "integrity": "sha512-9b/hwRM0UloLWV7SfpNaSD/4k8UQAHoaACAk7Xe+1MlfAm2JtnmPiB1GfGrfTyBlsrJVUIBCZpEmbmxVMaIqBA==", "license": "MIT" }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "node_modules/@parity/product-sdk/node_modules/@polkadot-api/ws-provider": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/ws-provider/-/ws-provider-0.9.1.tgz", + "integrity": "sha512-Ft2QJEjLZgTyKiCEbz3urSOxNfMdqNkg+QKqJhRbOFB7JtR1qMTvLE3TjM+5d2mNlEpOc3j2KDK3APNSj7uQ2Q==", "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" } }, - "node_modules/@noble/ciphers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", - "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", + "node_modules/@parity/product-sdk/node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", "license": "MIT", "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "node": ">=22.12.0" } }, - "node_modules/@noble/curves": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.2.0.tgz", - "integrity": "sha512-T/BoHgFXirb0ENSPBquzX0rcjXeM6Lo892a2jlYJkqk83LqZx0l1Of7DzlKJ6jkpvMrkHSnAcgb5JegL8SeIkQ==", + "node_modules/@parity/product-sdk/node_modules/polkadot-api": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/polkadot-api/-/polkadot-api-2.2.1.tgz", + "integrity": "sha512-eiZVUhI1gY4ycBtsCo/yaDXyohUeuqnyKun+bwj90ADSn+jlfjZ4sajAqIhJFwPxbCT75+Zzbln4ZjuZ5PWNWA==", "license": "MIT", "dependencies": { - "@noble/hashes": "2.2.0" + "@polkadot-api/cli": "0.21.9", + "@polkadot-api/ink-contracts": "0.6.3", + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/known-chains": "0.12.1", + "@polkadot-api/logs-provider": "0.2.0", + "@polkadot-api/metadata-builders": "0.14.3", + "@polkadot-api/metadata-compatibility": "0.6.3", + "@polkadot-api/observable-client": "0.18.7", + "@polkadot-api/pjs-signer": "0.7.3", + "@polkadot-api/polkadot-signer": "0.1.6", + "@polkadot-api/signer": "0.3.3", + "@polkadot-api/sm-provider": "0.3.8", + "@polkadot-api/smoldot": "0.4.6", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/substrate-client": "0.7.0", + "@polkadot-api/utils": "0.4.0", + "@polkadot-api/ws-middleware": "0.3.6", + "@polkadot-api/ws-provider": "0.9.1", + "@rx-state/core": "^0.1.4" }, - "engines": { - "node": ">= 20.19.0" + "bin": { + "papi": "bin/cli.js", + "polkadot-api": "bin/cli.js" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "rxjs": ">=7.8.0" } }, - "node_modules/@noble/hashes": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", - "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "node_modules/@parity/product-sdk/node_modules/smoldot": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/smoldot/-/smoldot-3.3.2.tgz", + "integrity": "sha512-Zl4h/0gsw8cfTZzuJ7LV7mtR6QjxltwYjMY7MsVw0oXBXrLK8zyOS6DS9Vjsy57pX1vBMg6UVhHxjbH3W905zA==", + "license": "GPL-3.0-or-later WITH Classpath-exception-2.0", + "dependencies": { + "ws": "^8.8.1" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "node_modules/@parity/product-sdk/node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, "engines": { - "node": ">= 8" + "node": ">=14.17" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } + "node_modules/@parity/result": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@parity/result/-/result-0.2.0.tgz", + "integrity": "sha512-QCrhYPeVVaPIjnlsfBIk5GHPRqfuCjy6MjqKkoCP4kwS1LIo5YtJCSFeB5mGtvMG7hiaRNl4lHQcd5YqDfJ1tQ==", + "license": "Apache-2.0" }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, + "node_modules/@parity/truapi": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@parity/truapi/-/truapi-0.5.1.tgz", + "integrity": "sha512-5AV6YoqnUKXj2wJ/qt/J2i3jpFawhEVkY165V5fSDccGkgK2oVHxlSfLwscXpZp4DxwFTL1FmvkhwhuqPDIdtA==", "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" + "@noble/hashes": "^2.2.0", + "neverthrow": "^8.2.0", + "scale-ts": "^1.6.1" } }, "node_modules/@playwright/test": { @@ -1416,6 +4814,61 @@ "integrity": "sha512-B2h1o+Qlo9idpASaHvMSoViB2I5ko5OAfwfhYF8LQDkTADK0B+SeStzNj1Qn+FG34wqTuv7HzBCdjaUgzYINJQ==", "license": "MIT" }, + "node_modules/@polkadot-api/ws-middleware": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@polkadot-api/ws-middleware/-/ws-middleware-0.3.6.tgz", + "integrity": "sha512-IMoJB572DdSYPshCQa2JmmehUEzX2Uwg5vKQafubbTMEFacXbifc6LTTVvi9Ue67rBuDy2VOWXBAm3BBpfKpDA==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0", + "@polkadot-api/json-rpc-provider-proxy": "0.4.1", + "@polkadot-api/raw-client": "0.3.0", + "@polkadot-api/substrate-bindings": "0.20.3", + "@polkadot-api/utils": "0.4.0" + }, + "peerDependencies": { + "rxjs": ">=7.8.0" + } + }, + "node_modules/@polkadot-api/ws-middleware/node_modules/@polkadot-api/json-rpc-provider": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider/-/json-rpc-provider-0.2.0.tgz", + "integrity": "sha512-lhkuBS/x06i3djQIN7p8jVkMnYuGsUAEMS6RhdWeEpz7X/8/APER4Wdih7MEBovCuwVSCTjOxl8f+alH7AZHZg==", + "license": "MIT" + }, + "node_modules/@polkadot-api/ws-middleware/node_modules/@polkadot-api/json-rpc-provider-proxy": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@polkadot-api/json-rpc-provider-proxy/-/json-rpc-provider-proxy-0.4.1.tgz", + "integrity": "sha512-F1Hw01C60jn98KQ0vBbgcwAvEcMcKLsJ5kFzq600sgjc6Rnbn1VF/XjTdrjcIqvfpR9sXyGIrpImrov2Usbrsw==", + "license": "MIT" + }, + "node_modules/@polkadot-api/ws-middleware/node_modules/@polkadot-api/raw-client": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/raw-client/-/raw-client-0.3.0.tgz", + "integrity": "sha512-u/wM9W7ugIXxBSOEV8+zvQI43b5vgSI0pvE0Rg8PV0G65BTLK0SMc2o2SQL0HtS5+bi5sw/gg4reBJ/0a4U0cw==", + "license": "MIT", + "dependencies": { + "@polkadot-api/json-rpc-provider": "0.2.0" + } + }, + "node_modules/@polkadot-api/ws-middleware/node_modules/@polkadot-api/substrate-bindings": { + "version": "0.20.3", + "resolved": "https://registry.npmjs.org/@polkadot-api/substrate-bindings/-/substrate-bindings-0.20.3.tgz", + "integrity": "sha512-9iqC71fx1ee9ld1NZV8PFime5vryi0kt1bKCSlvNgO6dqMc06sMZuZ8WPjOzWLCHiKHLuphdMs3rVBBaeCP3yg==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.2.0", + "@polkadot-api/utils": "0.4.0", + "@scure/base": "^2.2.0", + "scale-ts": "^1.6.1" + } + }, + "node_modules/@polkadot-api/ws-middleware/node_modules/@polkadot-api/utils": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@polkadot-api/utils/-/utils-0.4.0.tgz", + "integrity": "sha512-9b/hwRM0UloLWV7SfpNaSD/4k8UQAHoaACAk7Xe+1MlfAm2JtnmPiB1GfGrfTyBlsrJVUIBCZpEmbmxVMaIqBA==", + "license": "MIT" + }, "node_modules/@polkadot-api/ws-provider": { "version": "0.7.5", "resolved": "https://registry.npmjs.org/@polkadot-api/ws-provider/-/ws-provider-0.7.5.tgz", @@ -1583,9 +5036,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.2.tgz", - "integrity": "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.3.tgz", + "integrity": "sha512-c0wdcekXtQvvn5Tsrk/+op/gUArrbWaFduBnTLP2l1cKLSQs4diMWjJw3m6A0DdzT8dAAX95KpkJ3qynCePbmw==", "cpu": [ "arm" ], @@ -1596,9 +5049,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.2.tgz", - "integrity": "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.3.tgz", + "integrity": "sha512-3YjElDdWN+qXAFbJ/CzPV+0wspLqh54k/I6GfdYtEJRqg7buSgc1yPM3B+93j1M4neobtkATHZTmxK2AMVGfnA==", "cpu": [ "arm64" ], @@ -1609,9 +5062,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.2.tgz", - "integrity": "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.3.tgz", + "integrity": "sha512-Pch2pFNOxxz1hTjypIdPyRTR6riiwRl84+VcN9djS680fw+Co1nAJINrdpqp7KV0NvyuU8ilZXZCjd7ykJl1GQ==", "cpu": [ "arm64" ], @@ -1622,9 +5075,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.2.tgz", - "integrity": "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.3.tgz", + "integrity": "sha512-LEuncFUHFiF8t4yZVZvvZA1wk0pjAscRnsrn1EfTEmN4HXotBi2YtcnLRyaK6UbuczW7xZS5ES+81Rdz8Z0T6g==", "cpu": [ "x64" ], @@ -1635,9 +5088,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.2.tgz", - "integrity": "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.3.tgz", + "integrity": "sha512-zvBUvsQUpOWALdDsk6qbS8bXf2VxmPisuudNDrY7x0p0jBdsoZl8HsHczIOgkQiZldmcacMKtBzpoGVNeIe2bQ==", "cpu": [ "arm64" ], @@ -1648,9 +5101,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.2.tgz", - "integrity": "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.3.tgz", + "integrity": "sha512-C2KmNrcSem/AMg984H/dev+si0lieQGdXdR/lYGJnuumXnFb9Y7QdiI62obFdLlxRYLBv4P0eUVIDbD4c1vVvw==", "cpu": [ "x64" ], @@ -1661,9 +5114,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.2.tgz", - "integrity": "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.3.tgz", + "integrity": "sha512-ggXnsTAEzNQx74XpunRsiZ9aBZDsI7XIa0hm2nzR9f4WzH5/f/d73ZSDaC5ejJ8YLY4NW+V3wr0tjOaeCq8hqA==", "cpu": [ "arm" ], @@ -1674,9 +5127,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.2.tgz", - "integrity": "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.3.tgz", + "integrity": "sha512-2vng+FlzNUhKZxtej3IUqJgbZoQk2M/dwQM20+ULV0R/E/8tr9/P6uEf2iiGIk4HL0zMKh5Jry7mUHdUOvyGgA==", "cpu": [ "arm" ], @@ -1687,9 +5140,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.2.tgz", - "integrity": "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.3.tgz", + "integrity": "sha512-LLLFZKt4/Nraf9rxDkhiU8QVgLF4WmCkfr0L4fj0fPfIZFBib0DeiFk1hhaYKd03LFAFJcxHslhDFlNJLylf5Q==", "cpu": [ "arm64" ], @@ -1700,9 +5153,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.2.tgz", - "integrity": "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.3.tgz", + "integrity": "sha512-WJkdQCvS9sWNOUBJZfQRKpZGFBztRzcowI+nndmflKgU4XY+3a420FgTOSKTsVqJbnzSxeT4vaJalpOaPo2YCQ==", "cpu": [ "arm64" ], @@ -1713,9 +5166,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.2.tgz", - "integrity": "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.3.tgz", + "integrity": "sha512-PwHXCCS2n64/1Ot6rP1YEYA02MGYBcQlr8CSZZyrUG2O7NH6NklYmvr9v3Jy+5e/eDeNchc/ukmKJi9LuflMIQ==", "cpu": [ "loong64" ], @@ -1726,9 +5179,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.2.tgz", - "integrity": "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.3.tgz", + "integrity": "sha512-vUjxINQu3RC8NZS3ykk1gN65gIz8pAopOq2HXuZhiIxHdx7TFvDG+jgrdSgInu1Eza4/Rfi2VzZgyIgEH4WOaw==", "cpu": [ "loong64" ], @@ -1739,9 +5192,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.2.tgz", - "integrity": "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.3.tgz", + "integrity": "sha512-wzko4aJ13+0G3kGnviCg5gnXFKd40izKsrf2uOw12US4XqprkDrmwOpeW14aSNa37V8bfPcz5Fkob6LZ3BAPmA==", "cpu": [ "ppc64" ], @@ -1752,9 +5205,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.2.tgz", - "integrity": "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.3.tgz", + "integrity": "sha512-8120ue0JUMSwy11stlwnfdX3pPd+WZYGCDBwEHWtIHi6pOpZmsEF5QKB7a/UN+XFdqvobxz98kv8RTqikyCEBw==", "cpu": [ "ppc64" ], @@ -1765,9 +5218,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.2.tgz", - "integrity": "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.3.tgz", + "integrity": "sha512-XLFHnR3tXMjbOCh2vtVJHmxt+995uJsTERQyseFDRA0xxMxyTZPLa3OIUlyFaO4mF/Lu0FjmWHCuPXJT1n/IOg==", "cpu": [ "riscv64" ], @@ -1778,9 +5231,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.2.tgz", - "integrity": "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.3.tgz", + "integrity": "sha512-se6yXvNGMIl0f+RQzyh7XAmia8/9kplQx424wnG2w0C1oi6XgO6Y8otKhdXFHbHs88Ihavzmvh1NWjuovE76BQ==", "cpu": [ "riscv64" ], @@ -1791,9 +5244,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.2.tgz", - "integrity": "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.3.tgz", + "integrity": "sha512-gNoxRefktVIiGflpONuxWWXZAzIQG++z9qHO3xKwk4WdDMuQja3JHGfE1u0i3PfPDyvhypdk+WrgIJqLhGG7sg==", "cpu": [ "s390x" ], @@ -1804,9 +5257,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz", - "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.3.tgz", + "integrity": "sha512-V4KtWtQfAFMU7+9/A/VDps/VI8CHd3cYz0L8sgJzz8qK7eY7wI4ruFD82UYIYvW9Z4DtlTfhQcsl4XyPHW5uSg==", "cpu": [ "x64" ], @@ -1817,9 +5270,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.2.tgz", - "integrity": "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.3.tgz", + "integrity": "sha512-LBx9LYXvj2CBkMkjLdNAWLwH0MLMin7do2VcVo9kVPibGLkY0BQQut2fv7NVqkXqZ/CrAu9LqDHVV1xHCMpCPw==", "cpu": [ "x64" ], @@ -1830,9 +5283,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.2.tgz", - "integrity": "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.3.tgz", + "integrity": "sha512-ABVf3Q0RCu7NcyCCOZQI0pJ3GuSdfSl8EXcy88QtdceIMIoCUdfhsJChZ64L9zVM2aJHjde1Bhn5uqSRcX9ySA==", "cpu": [ "x64" ], @@ -1843,9 +5296,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.2.tgz", - "integrity": "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.3.tgz", + "integrity": "sha512-+2Cy/ldweGBLlPIKsQLF8U5N44a0KDdbrk1rAjHOM9M2K+kGdIVjHLmmrZIcx+9Ny3ke/1JomCsDI1ocb11+sg==", "cpu": [ "arm64" ], @@ -1856,9 +5309,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.2.tgz", - "integrity": "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.3.tgz", + "integrity": "sha512-dtZvzc8BedpSaFNy75x6uiWwAGTH+aZHDtdrqP6qk+WcLJrfti6sGje1ZJ9UxyzDLF23d/mV+PaMwuC0hL7UVA==", "cpu": [ "arm64" ], @@ -1869,9 +5322,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.2.tgz", - "integrity": "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.3.tgz", + "integrity": "sha512-Rj8Ra4noo+aYy7sKBggCx0407mws34kAb1ySyWuq5DAtFBQdkSwnsjCgPrhPe9cvgBKZIukpE+CVHvORCS93kQ==", "cpu": [ "ia32" ], @@ -1882,9 +5335,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.2.tgz", - "integrity": "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.3.tgz", + "integrity": "sha512-vp7N084ew/odXn2gi/mzm9mUkQu9l6AiN6dt4IeUM2Uvm9o+cVmP+YkqbMOteLbiGgqBBlJZjIMYVCfOOIVbVQ==", "cpu": [ "x64" ], @@ -1895,9 +5348,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.2.tgz", - "integrity": "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.3.tgz", + "integrity": "sha512-MOG/3gTOn4Fwf574RVOaY61I5o6P90legkFADiTyn1hyjNydT+cerU2rLUwPdZkKKyJ+iT+K9p7WXK4LM1Ka6g==", "cpu": [ "x64" ], @@ -2145,9 +5598,9 @@ "license": "MIT" }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "license": "MIT" }, "node_modules/@types/json-schema": { @@ -2158,12 +5611,12 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.6.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", - "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", + "version": "25.9.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.5.tgz", + "integrity": "sha512-OScDchr2fwuUmWdf4kZ9h7PcJiYDVInhJizG/biAq3cAvqwYktuy/TYGGdZNMtNTFUP7rnb0NU4TUdm82kt4Rg==", "license": "MIT", "dependencies": { - "undici-types": "~7.19.0" + "undici-types": ">=7.24.0 <7.24.7" } }, "node_modules/@types/normalize-package-data": { @@ -2407,29 +5860,6 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { "version": "10.2.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", @@ -2831,11 +6261,14 @@ } }, "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/base64id": { "version": "2.0.0", @@ -2872,14 +6305,16 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", + "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" } }, "node_modules/braces": { @@ -3203,23 +6638,16 @@ "node": ">=20" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, "node_modules/concurrently": { - "version": "9.2.3", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.3.tgz", - "integrity": "sha512-ihjs0E2SxvDgq/MK418hX6YycQgKhsqxpbZuZbHo0yKfqDWdymWMjWYIpCIzqDDLLKClHlXev8whW/8WXmJ0BA==", + "version": "9.2.4", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.4.tgz", + "integrity": "sha512-TZ0CEhyzvFjgtAvHTusDMgj7wNdihCh7LLLrzdUOXIhdlnL2JBBGA9eJxR24rtqgmdjh3OA3hrN1rCHj6HM8qA==", "dev": true, "license": "MIT", "dependencies": { "chalk": "4.1.2", "rxjs": "7.8.2", - "shell-quote": "1.8.4", + "shell-quote": "1.9.0", "supports-color": "8.1.1", "tree-kill": "1.2.2", "yargs": "17.7.2" @@ -3474,7 +6902,6 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "dev": true, "license": "MIT" }, "node_modules/esbuild": { @@ -4026,6 +7453,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-tsconfig": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -4170,6 +7609,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ipfs-unixfs": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/ipfs-unixfs/-/ipfs-unixfs-12.0.2.tgz", + "integrity": "sha512-uZ3rutVVZZ+tw52P+sgDSgOSK6ztExJVlfCjKvSD+NIEVlWQPDeKgdSFm+Kxchmgp7t6g1h+dzir+NgY+VsQXg==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "protons-runtime": "^6.0.1", + "uint8arraylist": "^2.4.8" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -4336,9 +7785,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", - "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", "dev": true, "funding": [ { @@ -4633,6 +8082,12 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/multiformats": { + "version": "13.4.2", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.4.2.tgz", + "integrity": "sha512-eh6eHCrRi1+POZ3dA+Dq1C6jhP1GNtr9CRINMb67OKzqW9I5DUuZM/3jLPlzhgpGeiNUlEGEbkCYChXMCc/8DQ==", + "license": "Apache-2.0 OR MIT" + }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -4644,10 +8099,21 @@ "thenify-all": "^1.0.0" } }, + "node_modules/nanoevents": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/nanoevents/-/nanoevents-9.1.0.tgz", + "integrity": "sha512-Jd0fILWG44a9luj8v5kED4WI+zfkkgwKyRQKItTtlPfEsh7Lznfi1kr8/iZ+XAIss4Qq5GqRB0qtWbaz9ceO/A==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", "funding": [ { "type": "github", @@ -4678,6 +8144,18 @@ "node": ">= 0.6" } }, + "node_modules/neverthrow": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/neverthrow/-/neverthrow-8.2.0.tgz", + "integrity": "sha512-kOCT/1MCPAxY5iUV3wytNFUMUolzuwd/VF/1KCx7kf6CutrOsTie+84zTGTpgQycjvfLdBBdvBvFLqFD2c0wkQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@rollup/rollup-linux-x64-gnu": "^4.24.0" + } + }, "node_modules/node-releases": { "version": "2.0.37", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", @@ -4801,9 +8279,9 @@ } }, "node_modules/ora": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-9.3.0.tgz", - "integrity": "sha512-lBX72MWFduWEf7v7uWf5DHp9Jn5BI8bNPGuFgtXMmr2uDz2Gz2749y3am3agSDdkhHPHYmmxEGSKH85ZLGzgXw==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-9.4.1.tgz", + "integrity": "sha512-6VlU9MLXbjVQD04AZCMX28hVtA5bUoadvUqO76MUCVA0ilwJbMiHsITRPfyVm6p/BC0Av/BXMujx39WCe1LEqw==", "license": "MIT", "dependencies": { "chalk": "^5.6.2", @@ -4812,7 +8290,7 @@ "is-interactive": "^2.0.0", "is-unicode-supported": "^2.1.0", "log-symbols": "^7.0.1", - "stdin-discarder": "^0.3.1", + "stdin-discarder": "^0.3.2", "string-width": "^8.1.0" }, "engines": { @@ -5188,9 +8666,9 @@ } }, "node_modules/postcss": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", - "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", + "version": "8.5.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz", + "integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==", "funding": [ { "type": "opencollective", @@ -5207,7 +8685,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -5389,6 +8867,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/protons-runtime": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-6.0.2.tgz", + "integrity": "sha512-hiyjyANwGcgmzc+tXc1/ZcSZhKnl5MDjaVNWkISHBgadaU0sjTgKIKZMZ62d9J9zlSTyKHCs/osPkQ/3Z+7yeA==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "uint8-varint": "^2.0.4", + "uint8arraylist": "^2.4.8", + "uint8arrays": "^5.1.0" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -5724,6 +9213,15 @@ "node": ">=4" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/restore-cursor": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", @@ -5752,12 +9250,12 @@ } }, "node_modules/rollup": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.2.tgz", - "integrity": "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==", + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.3.tgz", + "integrity": "sha512-Gu0c0iH9FzgX1L1t7ByIbbS3Vmdz+6KHm/EsqmmC71gUQ82yvZRkTK6XzrFObSka91WUVdynqp6nsfilzr5k6Q==", "license": "MIT", "dependencies": { - "@types/estree": "1.0.8" + "@types/estree": "1.0.9" }, "bin": { "rollup": "dist/bin/rollup" @@ -5767,34 +9265,53 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.60.2", - "@rollup/rollup-android-arm64": "4.60.2", - "@rollup/rollup-darwin-arm64": "4.60.2", - "@rollup/rollup-darwin-x64": "4.60.2", - "@rollup/rollup-freebsd-arm64": "4.60.2", - "@rollup/rollup-freebsd-x64": "4.60.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.60.2", - "@rollup/rollup-linux-arm-musleabihf": "4.60.2", - "@rollup/rollup-linux-arm64-gnu": "4.60.2", - "@rollup/rollup-linux-arm64-musl": "4.60.2", - "@rollup/rollup-linux-loong64-gnu": "4.60.2", - "@rollup/rollup-linux-loong64-musl": "4.60.2", - "@rollup/rollup-linux-ppc64-gnu": "4.60.2", - "@rollup/rollup-linux-ppc64-musl": "4.60.2", - "@rollup/rollup-linux-riscv64-gnu": "4.60.2", - "@rollup/rollup-linux-riscv64-musl": "4.60.2", - "@rollup/rollup-linux-s390x-gnu": "4.60.2", - "@rollup/rollup-linux-x64-gnu": "4.60.2", - "@rollup/rollup-linux-x64-musl": "4.60.2", - "@rollup/rollup-openbsd-x64": "4.60.2", - "@rollup/rollup-openharmony-arm64": "4.60.2", - "@rollup/rollup-win32-arm64-msvc": "4.60.2", - "@rollup/rollup-win32-ia32-msvc": "4.60.2", - "@rollup/rollup-win32-x64-gnu": "4.60.2", - "@rollup/rollup-win32-x64-msvc": "4.60.2", + "@rollup/rollup-android-arm-eabi": "4.62.3", + "@rollup/rollup-android-arm64": "4.62.3", + "@rollup/rollup-darwin-arm64": "4.62.3", + "@rollup/rollup-darwin-x64": "4.62.3", + "@rollup/rollup-freebsd-arm64": "4.62.3", + "@rollup/rollup-freebsd-x64": "4.62.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.3", + "@rollup/rollup-linux-arm-musleabihf": "4.62.3", + "@rollup/rollup-linux-arm64-gnu": "4.62.3", + "@rollup/rollup-linux-arm64-musl": "4.62.3", + "@rollup/rollup-linux-loong64-gnu": "4.62.3", + "@rollup/rollup-linux-loong64-musl": "4.62.3", + "@rollup/rollup-linux-ppc64-gnu": "4.62.3", + "@rollup/rollup-linux-ppc64-musl": "4.62.3", + "@rollup/rollup-linux-riscv64-gnu": "4.62.3", + "@rollup/rollup-linux-riscv64-musl": "4.62.3", + "@rollup/rollup-linux-s390x-gnu": "4.62.3", + "@rollup/rollup-linux-x64-gnu": "4.62.3", + "@rollup/rollup-linux-x64-musl": "4.62.3", + "@rollup/rollup-openbsd-x64": "4.62.3", + "@rollup/rollup-openharmony-arm64": "4.62.3", + "@rollup/rollup-win32-arm64-msvc": "4.62.3", + "@rollup/rollup-win32-ia32-msvc": "4.62.3", + "@rollup/rollup-win32-x64-gnu": "4.62.3", + "@rollup/rollup-win32-x64-msvc": "4.62.3", "fsevents": "~2.3.2" } }, + "node_modules/rollup-plugin-esbuild": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-esbuild/-/rollup-plugin-esbuild-6.2.1.tgz", + "integrity": "sha512-jTNOMGoMRhs0JuueJrJqbW8tOwxumaWYq+V5i+PD+8ecSCVkuX27tGW7BXqDgoULQ55rO7IdNxPcnsWtshz3AA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "es-module-lexer": "^1.6.0", + "get-tsconfig": "^4.10.0", + "unplugin-utils": "^0.2.4" + }, + "engines": { + "node": ">=14.18.0" + }, + "peerDependencies": { + "esbuild": ">=0.18.0", + "rollup": "^1.20.0 || ^2.0.0 || ^3.0.0 || ^4.0.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -5880,9 +9397,9 @@ } }, "node_modules/shell-quote": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz", - "integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.9.0.tgz", + "integrity": "sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA==", "dev": true, "license": "MIT", "engines": { @@ -6599,10 +10116,38 @@ "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", "license": "MIT" }, + "node_modules/uint8-varint": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/uint8-varint/-/uint8-varint-2.0.5.tgz", + "integrity": "sha512-jeFLbL/x30wBRnWjKE1qVBXeumG46r7XmYkpis955lTQ+blccGKFrOsSMHlxePwYB1pI7L8YPHz1t4jLxEs3nA==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "uint8arraylist": "^2.0.0", + "uint8arrays": "^5.0.0" + } + }, + "node_modules/uint8arraylist": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/uint8arraylist/-/uint8arraylist-2.4.9.tgz", + "integrity": "sha512-KxWjyEFzchzik3aoQlK66oaoxIReoMo5bQRm1fcjBUZvE8xv/tyR3CTKhjh6K/faV8VaF6hd5pjr45CzbwuwkA==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "uint8arrays": "^5.0.1" + } + }, + "node_modules/uint8arrays": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.1.1.tgz", + "integrity": "sha512-9muQwa4wZG4dKi9gMAIBtnk2Pw87SRpvWTH6lOGm19V2Uqxr4uomUf2PGqPnWc+qs06sN8owUU4jfcoWOcfwVQ==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "multiformats": "^13.0.0" + } + }, "node_modules/undici-types": { - "version": "7.19.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", - "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", "license": "MIT" }, "node_modules/unicorn-magic": { @@ -6617,6 +10162,34 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/unplugin-utils": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.2.5.tgz", + "integrity": "sha512-gwXJnPRewT4rT7sBi/IvxKTjsms7jX7QIDLOClApuZwR49SXbrB1z2NLUZ+vDHyqCj/n58OzRRqaW+B8OZi8vg==", + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/unplugin-utils/node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", @@ -7277,6 +10850,23 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "license": "ISC" }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/web/package.json b/web/package.json index e221bc7..f073684 100644 --- a/web/package.json +++ b/web/package.json @@ -16,7 +16,9 @@ "dev:listen": "concurrently -n signal,web -c magenta,cyan \"npm:signal\" \"npm:dev\"", "build": "tsc -b && vite build", "build:bulletin": "tsc -b && vite build --config vite.bulletin.config.ts", + "build:product-devnet": "tsc -b && vite build --config vite.product.config.ts --mode product-devnet", "deploy:bulletin": "node scripts/deploy-bulletin.cjs", + "deploy:product-devnet": "npm run build:product-devnet && npx --yes --package @polkadot-community-foundation/polkadot-app-deploy@0.13.1 pad ./dist-product dotify.dot --env devnet --js-merkle --config ./polkadot-app-deploy.config.ts", "smoke:production-env": "node scripts/production-env-smoke.mjs", "smoke:signal": "node scripts/signaling-smoke.mjs", "lint": "eslint .", @@ -27,6 +29,7 @@ "preview": "vite preview --host 0.0.0.0 --port 4273" }, "dependencies": { + "@parity/product-sdk": "0.19.1", "@polkadot-api/descriptors": "file:.papi/descriptors", "@polkadot-apps/chain-client": "^2.0.5", "@polkadot-apps/descriptors": "^1.0.1", @@ -45,6 +48,7 @@ "viem": "^2.53.1" }, "overrides": { + "brace-expansion": "5.0.8", "ws": "8.21.0" }, "devDependencies": { diff --git a/web/polkadot-app-deploy.config.ts b/web/polkadot-app-deploy.config.ts new file mode 100644 index 0000000..b0dc1e8 --- /dev/null +++ b/web/polkadot-app-deploy.config.ts @@ -0,0 +1,16 @@ +export default { + domain: 'dotify.dot', + displayName: 'Dotify', + description: 'Shared musical presence with artist-owned access and value flows.', + icon: { + path: './product-icon.png', + format: 'png' + }, + executables: [ + { + kind: 'app', + path: './dist-product', + appVersion: [0, 1, 0] + } + ] +}; diff --git a/web/product-icon.png b/web/product-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..24c57db6a3da752d85996df78601b4f3dcd7fca7 GIT binary patch literal 23535 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 FzW|VN&M^Q0 literal 0 HcmV?d00001 diff --git a/web/product-icon.svg b/web/product-icon.svg new file mode 100644 index 0000000..5827921 --- /dev/null +++ b/web/product-icon.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/web/src/app/providers/SessionProvider.tsx b/web/src/app/providers/SessionProvider.tsx index 49c01fa..968b4ca 100644 --- a/web/src/app/providers/SessionProvider.tsx +++ b/web/src/app/providers/SessionProvider.tsx @@ -13,19 +13,21 @@ import { useNavigation } from './NavigationProvider'; import { useCatalogContext } from './CatalogProvider'; const signalUrl = import.meta.env.VITE_SIGNAL_URL ?? `${window.location.protocol}//${window.location.hostname}:8788`; +const publicAppUrl = import.meta.env.VITE_PUBLIC_APP_URL?.trim() || null; type SessionValue = ReturnType; const SessionContext = createContext(null); export function SessionProvider({ children }: { children: ReactNode }) { - const { listenerEvmAddress } = useWalletContext(); + const { activeIdentityAddress } = useWalletContext(); const { navigateToView } = useNavigation(); const catalog = useCatalogContext(); const session = useSession({ signalUrl, - identityAddress: listenerEvmAddress, + publicAppUrl, + identityAddress: activeIdentityAddress, audioSource: catalog.audioSource, trackInfo: catalog.trackInfo, setTrackInfo: catalog.setTrackInfo, @@ -50,7 +52,7 @@ export function SessionProvider({ children }: { children: ReactNode }) { useEffect(() => { const initialRoomCode = getInitialRoomCode(); if (!initialRoomCode || session.roomId) return; - const remembered = getStoredDisplayName(listenerEvmAddress); + const remembered = getStoredDisplayName(activeIdentityAddress); if (!remembered) return; session.setDisplayName(remembered); session.joinRoom(initialRoomCode, { displayName: remembered }); @@ -68,11 +70,11 @@ export function SessionProvider({ children }: { children: ReactNode }) { // write a partial name to storage on every keystroke. const setDisplayName = session.setDisplayName; useEffect(() => { - const stored = getStoredDisplayName(listenerEvmAddress); + const stored = getStoredDisplayName(activeIdentityAddress); if (stored) setDisplayName(stored); // Re-run only when the connected address changes. // eslint-disable-next-line react-hooks/exhaustive-deps - }, [listenerEvmAddress]); + }, [activeIdentityAddress]); return {children}; } diff --git a/web/src/app/providers/WalletProvider.tsx b/web/src/app/providers/WalletProvider.tsx index aef0e7d..9be0100 100644 --- a/web/src/app/providers/WalletProvider.tsx +++ b/web/src/app/providers/WalletProvider.tsx @@ -18,6 +18,7 @@ import { devAccounts, type DevAccount } from '../../hooks/useDevAccounts'; import { getDefaultEthRpcUrl } from '../../shared/config/network'; import { resolveEvmChain, getWalletClient } from '../../shared/config/contracts'; import { chainMismatchMessage } from '../../features/wallet/network'; +import type { ProductHostMode, ProductHostStatus } from '../../features/productHost/productHost'; import { useUiFeedback } from './UiFeedbackProvider'; type WalletContextValue = { @@ -25,6 +26,7 @@ type WalletContextValue = { connectedWallet: ConnectedWallet | null; activeEvmAddress: `0x${string}`; listenerEvmAddress: `0x${string}` | null; + activeIdentityAddress: string | null; activeSubstrateAddress: string | null; activeSubstrateSigner: PolkadotSigner | null; currentBulletinAccount: DevAccount; @@ -37,10 +39,13 @@ type WalletContextValue = { switchNetwork: () => Promise; connectPasskey: () => Promise; connectExtension: () => Promise; + connectProductHost: () => Promise; disconnect: () => void; forgetPasskey: () => void; hasPrfSupport: boolean; hasStoredPasskey: boolean; + productHostMode: ProductHostMode; + productHostStatus: ProductHostStatus; }; const WalletContext = createContext(null); @@ -51,11 +56,14 @@ export function WalletProvider({ children }: { children: ReactNode }) { state: walletState, connectPasskey, connectExtension, + connectProductHost, switchExtensionNetwork, disconnect: disconnectWalletOnly, hasPrfSupport, hasStoredPasskey, - forgetPasskey + forgetPasskey, + productHostMode, + productHostStatus } = useWallet(); const [ethRpcUrl] = useState(getDefaultEthRpcUrl); @@ -68,7 +76,7 @@ export function WalletProvider({ children }: { children: ReactNode }) { // Disconnecting the wallet also signs out of the Dotify session (ticket 24 // P2): revoke the server-side token and forget the stored one, so a shared // machine does not keep listening rights after the wallet leaves. - const connectedAddress = connectedWallet?.evmAddress; + const connectedAddress = connectedWallet?.createEvmClient ? connectedWallet.evmAddress : undefined; const lastConnectedAddressRef = useRef<`0x${string}` | null>(null); const disconnect = useCallback(() => { if (connectedAddress) void signOutOfDotifySession(connectedAddress); @@ -88,7 +96,10 @@ export function WalletProvider({ children }: { children: ReactNode }) { const currentBulletinAccount = devAccounts[bulletinAccountIndex]; const activeEvmAddress = connectedWallet?.evmAddress ?? zeroAddress; - const listenerEvmAddress = connectedWallet?.evmAddress ?? null; + const listenerEvmAddress = connectedWallet?.createEvmClient ? connectedWallet.evmAddress : null; + // Local room-name persistence lowercases its key, so use the H160 identity + // for both EVM wallets and Product accounts rather than case-sensitive SS58. + const activeIdentityAddress = connectedWallet?.evmAddress ?? null; const devBulletinFallback = import.meta.env.DEV ? currentBulletinAccount : null; const activeSubstrateAddress = connectedWallet ? (connectedWallet.substrateAddress ?? null) : (devBulletinFallback?.address ?? null); const activeSubstrateSigner = connectedWallet ? (connectedWallet.substrateSigner ?? null) : (devBulletinFallback?.signer ?? null); @@ -97,6 +108,9 @@ export function WalletProvider({ children }: { children: ReactNode }) { if (!connectedWallet) { throw new Error('Connect a wallet before signing this transaction.'); } + if (!connectedWallet.createEvmClient) { + throw new Error('This action still requires a passkey or EVM wallet while Dotify contracts are being ported to the Product DevNet host signer.'); + } const chain = await resolveEvmChain(ethRpcUrl); if (connectedWallet.chainId !== undefined && connectedWallet.chainId !== chain.id) { throw new Error(chainMismatchMessage(chain.id, connectedWallet.chainId)); @@ -166,6 +180,7 @@ export function WalletProvider({ children }: { children: ReactNode }) { connectedWallet, activeEvmAddress, listenerEvmAddress, + activeIdentityAddress, activeSubstrateAddress, activeSubstrateSigner, currentBulletinAccount, @@ -178,16 +193,20 @@ export function WalletProvider({ children }: { children: ReactNode }) { switchNetwork, connectPasskey, connectExtension, + connectProductHost, disconnect, forgetPasskey, hasPrfSupport, - hasStoredPasskey + hasStoredPasskey, + productHostMode, + productHostStatus }), [ walletState, connectedWallet, activeEvmAddress, listenerEvmAddress, + activeIdentityAddress, activeSubstrateAddress, activeSubstrateSigner, currentBulletinAccount, @@ -199,10 +218,13 @@ export function WalletProvider({ children }: { children: ReactNode }) { switchNetwork, connectPasskey, connectExtension, + connectProductHost, disconnect, forgetPasskey, hasPrfSupport, - hasStoredPasskey + hasStoredPasskey, + productHostMode, + productHostStatus ] ); diff --git a/web/src/components/WalletModal.tsx b/web/src/components/WalletModal.tsx index 989d2e1..cae1226 100644 --- a/web/src/components/WalletModal.tsx +++ b/web/src/components/WalletModal.tsx @@ -1,4 +1,4 @@ -import { ExternalLink, KeyRound, LockKeyhole, Music2, Power, RefreshCw, Users, Wallet, X } from 'lucide-react'; +import { Box, ExternalLink, KeyRound, LockKeyhole, Music2, Power, RefreshCw, Users, Wallet, X } from 'lucide-react'; import { Dialog } from './Dialog'; import type { WalletState } from '../hooks/useWallet'; import type { CatalogTrack } from '../shared/types'; @@ -58,6 +58,9 @@ export function WalletModal({ isSwitchingNetwork, connectPasskey, connectExtension, + connectProductHost, + productHostMode, + productHostStatus, switchNetwork, forgetPasskey: onForgetPasskey, disconnect: onDisconnect @@ -69,6 +72,7 @@ export function WalletModal({ const onClose = () => setShowWalletModal(false); const onPasskey = () => void connectPasskey(); const onExtension = () => void connectExtension(); + const onProductHost = () => void connectProductHost(); const onSwitchNetwork = () => void switchNetwork(); if (state.status === 'connected') { @@ -95,7 +99,7 @@ export function WalletModal({
    {wallet.label} - {wallet.evmAddress ? ( + {wallet.method !== 'product-host' ? ( {shortenAddress(identityAddress)} @@ -108,7 +112,15 @@ export function WalletModal({
    Connection - {walletChainMismatch ? 'Needs attention' : wallet.method === 'passkey' ? 'This device' : 'Wallet app'} + + {walletChainMismatch + ? 'Needs attention' + : wallet.method === 'passkey' + ? 'This device' + : wallet.method === 'product-host' + ? 'Product host' + : 'Wallet app'} + {walletChainMismatch && Choose the right network to continue} {walletChainMismatch && wallet.method === 'extension' && onSwitchNetwork && (
    + {wallet.method === 'product-host' && ( + <> +

    + Your app-scoped Polkadot identity is active for presence and rooms. Paid access, protected playback, and artist publishing still require an EVM + signer during the contract port. +

    +
    + {hasPrfSupport && ( + + )} + +
    + + )} +
    {unlockedCount} @@ -254,15 +297,39 @@ export function WalletModal({ {state.status === 'error' &&

    {state.message}

    } {state.status === 'connecting' && ( -

    {state.via === 'passkey' ? 'Check your browser prompt to continue.' : 'Check your wallet to approve the connection.'}

    +

    + {state.via === 'passkey' + ? 'Check your browser prompt to continue.' + : state.via === 'product-host' + ? 'Check the Polkadot Product host to continue.' + : 'Check your wallet to approve the connection.'} +

    )} {state.status === 'needs-reconnect' && state.via === 'passkey' && (

    Your saved passkey is ready. Use passkey to reconnect when you are ready.

    )}
    + {productHostMode !== 'off' && ( + + )} + {hasPrfSupport && ( -
  • @@ -1607,7 +1608,7 @@

    Explore the project

    Product DevNet architecture - What the Product host adapts now, what remains on Fly, and how contract signing ports next. + What the Product host adapts now, what remains on Fly, and how runtime ports prepare CDM/PAPI. diff --git a/web/src/features/runtime/runtimePorts.ts b/web/src/features/runtime/runtimePorts.ts new file mode 100644 index 0000000..b79e9e3 --- /dev/null +++ b/web/src/features/runtime/runtimePorts.ts @@ -0,0 +1,69 @@ +import type { Address, Hash } from 'viem'; +import type { OnchainTrackRecord, RoyaltySplit } from '../../shared/types'; + +export type RuntimeDirectoryEntry = { + artist: Address; + runtime: Address; +}; + +export type RuntimeTrackSnapshot = { + hash: Hash; + record: OnchainTrackRecord; + royaltySplits: Array>; +}; + +export type RuntimeRoyaltyPaymentLog = { + trackHash: Hash; + listener: Address; + amountWei: bigint; + paidAtMs: number | null; + transactionHash: Hash; + blockNumber: bigint; + logIndex: number; +}; + +export type RuntimeTrackRegistration = { + contentHash: Hash; + title: string; + artistName: string; + description: string; + imageRef: string; + audioRef: string; + metadataRef: string; + artistContractRef: string; + accessMode: number; + pricePlanck: bigint; + requiredPersonhood: number; + royaltyRecipients: Address[]; + royaltyShares: number[]; +}; + +export type RuntimeAccessPolicyUpdate = { + contentHash: Hash; + accessMode: number; + pricePlanck: bigint; + requiredPersonhood: number; +}; + +export interface RuntimeReadPort { + ensureContract(address: Address): Promise; + resolveArtistRuntime(directoryAddress: Address, artistAddress: Address): Promise
    ; + getArtistCount(directoryAddress: Address): Promise; + listArtistRuntimes(directoryAddress: Address, artistCount: bigint): Promise; + listRuntimeTracks(runtimeAddress: Address): Promise; + canAccess(runtimeAddress: Address, contentHash: Hash, listenerAddress: Address): Promise; + hasPaid(runtimeAddress: Address, contentHash: Hash, listenerAddress: Address): Promise; + pendingRuntimeOf(factoryAddress: Address, artistAddress: Address): Promise
    ; + pendingRuntimeStageOf(factoryAddress: Address, artistAddress: Address): Promise; + listRoyaltyPaymentLogs(runtimeAddress: Address): Promise; +} + +export interface RuntimeWritePort { + createRuntime(factoryAddress: Address): Promise; + installRuntimeStep(factoryAddress: Address): Promise; + registerTrack(runtimeAddress: Address, registration: RuntimeTrackRegistration): Promise; + payForAccess(runtimeAddress: Address, contentHash: Hash, value: bigint): Promise; + setAccessMode(runtimeAddress: Address, update: RuntimeAccessPolicyUpdate): Promise; + setReleaseActive(runtimeAddress: Address, contentHash: Hash, active: boolean): Promise; + waitForTransaction(txHash: Hash): Promise; +} diff --git a/web/src/features/runtime/viemRuntimeAdapter.test.ts b/web/src/features/runtime/viemRuntimeAdapter.test.ts new file mode 100644 index 0000000..d4b2c6c --- /dev/null +++ b/web/src/features/runtime/viemRuntimeAdapter.test.ts @@ -0,0 +1,161 @@ +import { describe, expect, it, vi } from 'vitest'; +import { createViemRuntimeReader, createViemRuntimeWriter } from './viemRuntimeAdapter'; +import type { OnchainTrackRecord } from '../../shared/types'; + +const directory = '0x1000000000000000000000000000000000000000' as const; +const factory = '0x2000000000000000000000000000000000000000' as const; +const runtime = '0x3000000000000000000000000000000000000000' as const; +const artist = '0x4000000000000000000000000000000000000000' as const; +const listener = '0x5000000000000000000000000000000000000000' as const; +const splitRecipient = '0x6000000000000000000000000000000000000000' as const; +const hash = `0x${'ab'.repeat(32)}` as const; +const txHash = `0x${'cd'.repeat(32)}` as const; + +function baseTrackRecord(patch: Partial = {}): OnchainTrackRecord { + return { + artist, + tokenId: 1n, + title: 'Runtime song', + artistName: 'Runtime artist', + description: 'On-chain description', + imageRef: 'ipfs://cover', + audioRef: 'dotify.audio.v2:audio', + metadataRef: 'ipfs://metadata', + artistContractRef: 'dotify:self-certified', + royaltyBps: 9000, + accessMode: 1, + pricePlanck: 1_000_000_000_000_000_000n, + requiredPersonhood: 0, + registeredAtBlock: 12n, + active: true, + ...patch + }; +} + +describe('createViemRuntimeReader', () => { + it('paginates directory runtimes and filters zero-address entries', async () => { + const readContract = vi.fn(async ({ functionName, args }: { functionName: string; args?: unknown[] }) => { + if (functionName !== 'artistsPage') throw new Error(`unexpected ${functionName}`); + const offset = args?.[0]; + if (offset === 0n) { + return [[artist], [runtime]]; + } + return [[listener], ['0x0000000000000000000000000000000000000000']]; + }); + const reader = createViemRuntimeReader({ + ethRpcUrl: 'http://localhost:8545', + publicClient: { readContract } as never + }); + + await expect(reader.listArtistRuntimes(directory, 51n)).resolves.toEqual([{ artist, runtime }]); + expect(readContract).toHaveBeenCalledTimes(2); + }); + + it('returns runtime track snapshots with royalty splits', async () => { + const record = baseTrackRecord(); + const readContract = vi.fn(async ({ functionName }: { functionName: string }) => { + switch (functionName) { + case 'musicRegTrackCount': + return 1n; + case 'musicRegTrackHashAtIndex': + return hash; + case 'musicRegGetTrack': + return [record, runtime]; + case 'musicRoySplitCount': + return 1n; + case 'musicRoySplitAt': + return [splitRecipient, 2500]; + default: + throw new Error(`unexpected ${functionName}`); + } + }); + const reader = createViemRuntimeReader({ + ethRpcUrl: 'http://localhost:8545', + publicClient: { readContract } as never + }); + + await expect(reader.listRuntimeTracks(runtime)).resolves.toEqual([ + { + hash, + record, + royaltySplits: [{ recipient: splitRecipient, bps: 2500 }] + } + ]); + }); + + it('normalizes royalty payment logs with block timestamps', async () => { + const getLogs = vi.fn(async () => [ + { + args: { contentHash: hash, listener, amount: 2_000_000_000_000_000_000n }, + transactionHash: txHash, + blockNumber: 7n, + logIndex: 3 + } + ]); + const getBlock = vi.fn(async () => ({ timestamp: 123n })); + const reader = createViemRuntimeReader({ + ethRpcUrl: 'http://localhost:8545', + publicClient: { getLogs, getBlock } as never + }); + + await expect(reader.listRoyaltyPaymentLogs(runtime)).resolves.toEqual([ + { + trackHash: hash, + listener, + amountWei: 2_000_000_000_000_000_000n, + paidAtMs: 123_000, + transactionHash: txHash, + blockNumber: 7n, + logIndex: 3 + } + ]); + }); +}); + +describe('createViemRuntimeWriter', () => { + it('routes runtime writes through named contract calls and waits for receipts', async () => { + const writeContract = vi.fn(async ({ functionName }: { functionName: string }) => { + return `${txHash}:${functionName}` as `0x${string}`; + }); + const waitForTransactionReceipt = vi.fn(async () => ({ status: 'success' })); + const writer = createViemRuntimeWriter({ + ethRpcUrl: 'http://localhost:8545', + walletClient: { writeContract } as never, + publicClient: { waitForTransactionReceipt } as never + }); + + await expect(writer.createRuntime(factory)).resolves.toBe(`${txHash}:createRuntime`); + await expect(writer.installRuntimeStep(factory)).resolves.toBe(`${txHash}:installRuntimeStep`); + await expect(writer.payForAccess(runtime, hash, 1n)).resolves.toBe(`${txHash}:musicRoyPayAccess`); + await expect( + writer.registerTrack(runtime, { + contentHash: hash, + title: 'Runtime song', + artistName: 'Runtime artist', + description: 'On-chain description', + imageRef: 'ipfs://cover', + audioRef: 'dotify.audio.v2:audio', + metadataRef: 'ipfs://metadata', + artistContractRef: 'dotify:self-certified', + accessMode: 1, + pricePlanck: 1n, + requiredPersonhood: 0, + royaltyRecipients: [artist], + royaltyShares: [10_000] + }) + ).resolves.toBe(`${txHash}:musicRegRegister`); + await expect( + writer.setAccessMode(runtime, { + contentHash: hash, + accessMode: 2, + pricePlanck: 0n, + requiredPersonhood: 1 + }) + ).resolves.toBe(`${txHash}:musicRegSetAccessMode`); + await expect(writer.setReleaseActive(runtime, hash, false)).resolves.toBe(`${txHash}:musicRegDeactivate`); + + await writer.waitForTransaction(txHash); + expect(waitForTransactionReceipt).toHaveBeenCalledWith({ hash: txHash }); + expect(writeContract).toHaveBeenCalledTimes(6); + }); +}); diff --git a/web/src/features/runtime/viemRuntimeAdapter.ts b/web/src/features/runtime/viemRuntimeAdapter.ts new file mode 100644 index 0000000..39300fa --- /dev/null +++ b/web/src/features/runtime/viemRuntimeAdapter.ts @@ -0,0 +1,310 @@ +import { parseAbiItem, zeroAddress, type Address, type Hash } from 'viem'; +import { + artistDirectoryAbi, + artistRuntimeFactoryAbi, + getPublicClient, + getWalletClient, + musicAccessAbi, + musicRegistryAbi, + musicRoyaltiesAbi +} from '../../shared/config/contracts'; +import type { + RuntimeAccessPolicyUpdate, + RuntimeDirectoryEntry, + RuntimeReadPort, + RuntimeRoyaltyPaymentLog, + RuntimeTrackSnapshot, + RuntimeWritePort +} from './runtimePorts'; +import type { OnchainTrackRecord } from '../../shared/types'; + +type ViemPublicClient = ReturnType; +type ViemWalletClient = Awaited>; + +const musicRoyAccessPaidEvent = parseAbiItem('event MusicRoyAccessPaid(bytes32 indexed contentHash, address indexed listener, uint256 amount)'); + +export type ViemRuntimeReaderDeps = { + ethRpcUrl: string; + publicClient?: ViemPublicClient; +}; + +export type ViemRuntimeWriterDeps = ViemRuntimeReaderDeps & { + walletClient: ViemWalletClient; +}; + +function resolvePublicClient(deps: ViemRuntimeReaderDeps): ViemPublicClient { + return deps.publicClient ?? getPublicClient(deps.ethRpcUrl); +} + +async function blockTimestampMs(client: ViemPublicClient, blockNumber: bigint): Promise { + const block = await client.getBlock({ blockNumber }); + return Number(block.timestamp) * 1000; +} + +export function createViemRuntimeReader(deps: ViemRuntimeReaderDeps): RuntimeReadPort { + const client = () => resolvePublicClient(deps); + + return { + ensureContract(address) { + return client() + .getCode({ address }) + .then(code => Boolean(code && code !== '0x')); + }, + + async resolveArtistRuntime(directoryAddress, artistAddress) { + const runtimeAddress = (await client().readContract({ + address: directoryAddress, + abi: artistDirectoryAbi, + functionName: 'runtimeOf', + args: [artistAddress] + })) as Address; + return runtimeAddress === zeroAddress ? null : runtimeAddress; + }, + + async getArtistCount(directoryAddress) { + return (await client().readContract({ + address: directoryAddress, + abi: artistDirectoryAbi, + functionName: 'artistCount' + })) as bigint; + }, + + async listArtistRuntimes(directoryAddress, artistCount) { + const pageSize = 50n; + const entries: RuntimeDirectoryEntry[] = []; + + for (let offset = 0n; offset < artistCount; offset += pageSize) { + const limit = artistCount - offset > pageSize ? pageSize : artistCount - offset; + const [artists, runtimes] = (await client().readContract({ + address: directoryAddress, + abi: artistDirectoryAbi, + functionName: 'artistsPage', + args: [offset, limit] + })) as [Address[], Address[]]; + + for (let index = 0; index < artists.length; index += 1) { + const artist = artists[index]; + const runtime = runtimes[index]; + if (!artist || !runtime || runtime === zeroAddress) continue; + entries.push({ artist, runtime }); + } + } + + return entries; + }, + + async listRuntimeTracks(runtimeAddress) { + const trackCount = (await client().readContract({ + address: runtimeAddress, + abi: musicRegistryAbi, + functionName: 'musicRegTrackCount' + })) as bigint; + + return Promise.all( + Array.from({ length: Number(trackCount) }, async (_, index): Promise => { + const hash = (await client().readContract({ + address: runtimeAddress, + abi: musicRegistryAbi, + functionName: 'musicRegTrackHashAtIndex', + args: [BigInt(index)] + })) as Hash; + + const [record] = (await client().readContract({ + address: runtimeAddress, + abi: musicRegistryAbi, + functionName: 'musicRegGetTrack', + args: [hash] + })) as [OnchainTrackRecord, Address]; + + const splitCount = (await client() + .readContract({ + address: runtimeAddress, + abi: musicRoyaltiesAbi, + functionName: 'musicRoySplitCount', + args: [hash] + }) + .catch(() => 0n)) as bigint; + + const royaltySplits = ( + await Promise.all( + Array.from({ length: Number(splitCount) }, async (_, splitIndex) => { + try { + const [recipient, bps] = (await client().readContract({ + address: runtimeAddress, + abi: musicRoyaltiesAbi, + functionName: 'musicRoySplitAt', + args: [hash, BigInt(splitIndex)] + })) as [Address, number]; + return { recipient, bps: Number(bps) }; + } catch { + return null; + } + }) + ) + ).filter((split): split is { recipient: Address; bps: number } => Boolean(split)); + + return { hash, record, royaltySplits }; + }) + ); + }, + + async canAccess(runtimeAddress, contentHash, listenerAddress) { + return (await client().readContract({ + address: runtimeAddress, + abi: musicAccessAbi, + functionName: 'musicAccCanAccess', + args: [contentHash, listenerAddress] + })) as boolean; + }, + + async hasPaid(runtimeAddress, contentHash, listenerAddress) { + return (await client().readContract({ + address: runtimeAddress, + abi: musicAccessAbi, + functionName: 'musicAccHasPaid', + args: [contentHash, listenerAddress] + })) as boolean; + }, + + async pendingRuntimeOf(factoryAddress, artistAddress) { + const pendingRuntime = (await client().readContract({ + address: factoryAddress, + abi: artistRuntimeFactoryAbi, + functionName: 'pendingRuntimeOf', + args: [artistAddress] + })) as Address; + return pendingRuntime === zeroAddress ? null : pendingRuntime; + }, + + async pendingRuntimeStageOf(factoryAddress, artistAddress) { + return Number( + await client().readContract({ + address: factoryAddress, + abi: artistRuntimeFactoryAbi, + functionName: 'pendingRuntimeStageOf', + args: [artistAddress] + }) + ); + }, + + async listRoyaltyPaymentLogs(runtimeAddress) { + const logs = await client().getLogs({ + address: runtimeAddress, + event: musicRoyAccessPaidEvent, + fromBlock: 0n, + toBlock: 'latest' + }); + const timestampsByBlock = new Map(); + await Promise.all( + Array.from(new Set(logs.map(log => log.blockNumber.toString()))).map(async blockNumber => { + timestampsByBlock.set(blockNumber, await blockTimestampMs(client(), BigInt(blockNumber))); + }) + ); + + return logs + .map((log): RuntimeRoyaltyPaymentLog | null => { + const trackHash = log.args.contentHash; + const listener = log.args.listener; + const amountWei = log.args.amount; + if (!trackHash || !listener || amountWei === undefined) return null; + return { + trackHash, + listener, + amountWei, + paidAtMs: timestampsByBlock.get(log.blockNumber.toString()) ?? null, + transactionHash: log.transactionHash, + blockNumber: log.blockNumber, + logIndex: log.logIndex + }; + }) + .filter((payment): payment is RuntimeRoyaltyPaymentLog => Boolean(payment)); + } + }; +} + +export function createViemRuntimeWriter(deps: ViemRuntimeWriterDeps): RuntimeWritePort { + const client = () => resolvePublicClient(deps); + const { walletClient } = deps; + + return { + createRuntime(factoryAddress) { + return walletClient.writeContract({ + address: factoryAddress, + abi: artistRuntimeFactoryAbi, + functionName: 'createRuntime' + }); + }, + + installRuntimeStep(factoryAddress) { + return walletClient.writeContract({ + address: factoryAddress, + abi: artistRuntimeFactoryAbi, + functionName: 'installRuntimeStep' + }); + }, + + registerTrack(runtimeAddress, registration) { + return walletClient.writeContract({ + address: runtimeAddress, + abi: musicRegistryAbi, + functionName: 'musicRegRegister', + args: [ + { + contentHash: registration.contentHash, + title: registration.title, + artistName: registration.artistName, + description: registration.description, + imageRef: registration.imageRef, + audioRef: registration.audioRef, + metadataRef: registration.metadataRef, + artistContractRef: registration.artistContractRef, + accessMode: registration.accessMode, + pricePlanck: registration.pricePlanck, + requiredPersonhood: registration.requiredPersonhood + }, + registration.royaltyRecipients, + registration.royaltyShares + ] + }); + }, + + payForAccess(runtimeAddress, contentHash, value) { + return walletClient.writeContract({ + address: runtimeAddress, + abi: musicRoyaltiesAbi, + functionName: 'musicRoyPayAccess', + args: [contentHash], + value + }); + }, + + setAccessMode(runtimeAddress, update: RuntimeAccessPolicyUpdate) { + return walletClient.writeContract({ + address: runtimeAddress, + abi: musicRegistryAbi, + functionName: 'musicRegSetAccessMode', + args: [update.contentHash, update.accessMode, update.pricePlanck, update.requiredPersonhood] + }); + }, + + setReleaseActive(runtimeAddress, contentHash, active) { + return active + ? walletClient.writeContract({ + address: runtimeAddress, + abi: musicRegistryAbi, + functionName: 'musicRegReactivate', + args: [contentHash] + }) + : walletClient.writeContract({ + address: runtimeAddress, + abi: musicRegistryAbi, + functionName: 'musicRegDeactivate', + args: [contentHash] + }); + }, + + async waitForTransaction(txHash) { + await client().waitForTransactionReceipt({ hash: txHash }); + } + }; +} diff --git a/web/src/hooks/useArtistConsole.ts b/web/src/hooks/useArtistConsole.ts index 8e06d74..56420ba 100644 --- a/web/src/hooks/useArtistConsole.ts +++ b/web/src/hooks/useArtistConsole.ts @@ -1,14 +1,6 @@ import { useState } from 'react'; -import { getAddress, isAddress, parseAbiItem } from 'viem'; -import { - ensureContract, - getPublicClient, - getWalletClient, - resolveEvmChain, - artistRuntimeFactoryAbi, - artistDirectoryAbi, - musicRegistryAbi -} from '../shared/config/contracts'; +import { getAddress, isAddress } from 'viem'; +import { getWalletClient, resolveEvmChain } from '../shared/config/contracts'; import { checkBulletinAuthorization, encodeBulletinJson, uploadToBulletin } from './useBulletin'; import { protectedAudioUploadToCID, @@ -21,8 +13,9 @@ import { import { chainMismatchMessage } from '../features/wallet/network'; import { localAudioRef, priceDotForAccessMode, runtimeAddressFromTrackId } from '../features/catalog/trackModel'; import { encodeAccessMode, encodeRequiredPersonhood, manifestRequiredPersonhood } from '../features/runtime/accessEncoding'; +import { createViemRuntimeReader, createViemRuntimeWriter } from '../features/runtime/viemRuntimeAdapter'; import { resolveConfiguredArtistPublicationSafety } from '../shared/config/deploymentSafety'; -import { describeArtistRegistrationError, formatBlockTimestampMs, formatWeiAsDot, shorten, dotToPlanck } from '../shared/utils/format'; +import { describeArtistRegistrationError, formatWeiAsDot, shorten, dotToPlanck } from '../shared/utils/format'; import { createArtistPublishE2eTrack, E2E_ARTIST_PROFILE_TX_HASH, @@ -41,8 +34,6 @@ import type { AccessMode, CatalogTrack, PersonhoodLevel, ReleaseRoyaltySplitDraf import type { ConnectedWallet } from './useWallet'; import type { PolkadotSigner } from 'polkadot-api'; -const zeroAddress = '0x0000000000000000000000000000000000000000' as const; -const musicRoyAccessPaidEvent = parseAbiItem('event MusicRoyAccessPaid(bytes32 indexed contentHash, address indexed listener, uint256 amount)'); const runtimeBootstrapSteps = [ { label: 'Claim your artist space', @@ -241,6 +232,7 @@ export function useArtistConsole(deps: UseArtistConsoleDeps) { coverUploadRef } = deps; + const runtimeReader = createViemRuntimeReader({ ethRpcUrl }); const [artistRuntimeAddress, setArtistRuntimeAddress] = useState<`0x${string}` | null>(null); const [artistRegistrationStatus, setArtistRegistrationStatus] = useState('Checking artist registration'); const [isRegisteringArtist, setIsRegisteringArtist] = useState(false); @@ -314,21 +306,16 @@ export function useArtistConsole(deps: UseArtistConsoleDeps) { setArtistRegistrationStatus('Checking artist runtime'); try { - const directoryExists = await ensureContract(directoryAddress!, ethRpcUrl); + const directoryExists = await runtimeReader.ensureContract(directoryAddress!); if (!directoryExists) { setArtistRuntimeAddress(null); setArtistRegistrationStatus('Artist directory unavailable'); return null; } - const runtimeAddress = (await getPublicClient(ethRpcUrl).readContract({ - address: directoryAddress!, - abi: artistDirectoryAbi, - functionName: 'runtimeOf', - args: [activeEvmAddress] - })) as `0x${string}`; + const runtimeAddress = await runtimeReader.resolveArtistRuntime(directoryAddress!, activeEvmAddress); - if (runtimeAddress === zeroAddress) { + if (!runtimeAddress) { setArtistRuntimeAddress(null); setArtistRegistrationStatus(artistPublicationQuarantined ? artistPublicationSafety.reason : 'Artist not registered yet'); return null; @@ -420,7 +407,7 @@ export function useArtistConsole(deps: UseArtistConsoleDeps) { return; } - const factoryExists = await ensureContract(factoryAddress!, ethRpcUrl); + const factoryExists = await runtimeReader.ensureContract(factoryAddress!); if (!factoryExists) { setTransactionFeedback({ tone: 'error', @@ -431,19 +418,14 @@ export function useArtistConsole(deps: UseArtistConsoleDeps) { } const walletClient = await getActiveWalletClient(); - const publicClient = getPublicClient(ethRpcUrl); + const runtimeWriter = createViemRuntimeWriter({ ethRpcUrl, walletClient }); - let pendingRuntime = (await publicClient.readContract({ - address: factoryAddress!, - abi: artistRuntimeFactoryAbi, - functionName: 'pendingRuntimeOf', - args: [activeEvmAddress] - })) as `0x${string}`; + let pendingRuntime = await runtimeReader.pendingRuntimeOf(factoryAddress!, activeEvmAddress); let txHash: `0x${string}` | undefined; const confirmedBootstrapTxHashes: Partial> = {}; - if (pendingRuntime === zeroAddress) { + if (!pendingRuntime) { setArtistRegistrationStatus(runtimeBootstrapSteps[0].label); setTransactionFeedback({ tone: 'pending', @@ -452,11 +434,7 @@ export function useArtistConsole(deps: UseArtistConsoleDeps) { steps: artistRuntimeBootstrapRoadmap(0, 'active') }); - txHash = await walletClient.writeContract({ - address: factoryAddress!, - abi: artistRuntimeFactoryAbi, - functionName: 'createRuntime' - }); + txHash = await runtimeWriter.createRuntime(factoryAddress!); setTransactionFeedback({ tone: 'pending', @@ -466,17 +444,10 @@ export function useArtistConsole(deps: UseArtistConsoleDeps) { steps: artistRuntimeBootstrapRoadmap(0, 'submitted', confirmedBootstrapTxHashes) }); - await publicClient.waitForTransactionReceipt({ hash: txHash }); + await runtimeWriter.waitForTransaction(txHash); confirmedBootstrapTxHashes[0] = txHash; } else { - const pendingStage = Number( - await publicClient.readContract({ - address: factoryAddress!, - abi: artistRuntimeFactoryAbi, - functionName: 'pendingRuntimeStageOf', - args: [activeEvmAddress] - }) - ); + const pendingStage = await runtimeReader.pendingRuntimeStageOf(factoryAddress!, activeEvmAddress); const pendingStepIndex = Math.max(1, Math.min(runtimeBootstrapSteps.length - 1, pendingStage)); setTransactionFeedback({ tone: 'pending', @@ -486,22 +457,10 @@ export function useArtistConsole(deps: UseArtistConsoleDeps) { }); } - pendingRuntime = (await publicClient.readContract({ - address: factoryAddress!, - abi: artistRuntimeFactoryAbi, - functionName: 'pendingRuntimeOf', - args: [activeEvmAddress] - })) as `0x${string}`; - - while (pendingRuntime !== zeroAddress) { - const currentStage = Number( - await publicClient.readContract({ - address: factoryAddress!, - abi: artistRuntimeFactoryAbi, - functionName: 'pendingRuntimeStageOf', - args: [activeEvmAddress] - }) - ); + pendingRuntime = await runtimeReader.pendingRuntimeOf(factoryAddress!, activeEvmAddress); + + while (pendingRuntime) { + const currentStage = await runtimeReader.pendingRuntimeStageOf(factoryAddress!, activeEvmAddress); const stepIndex = Math.max(1, Math.min(runtimeBootstrapSteps.length - 1, currentStage)); const step = runtimeBootstrapSteps[stepIndex]; @@ -513,11 +472,7 @@ export function useArtistConsole(deps: UseArtistConsoleDeps) { steps: artistRuntimeBootstrapRoadmap(stepIndex, 'active', confirmedBootstrapTxHashes) }); - txHash = await walletClient.writeContract({ - address: factoryAddress!, - abi: artistRuntimeFactoryAbi, - functionName: 'installRuntimeStep' - }); + txHash = await runtimeWriter.installRuntimeStep(factoryAddress!); setTransactionFeedback({ tone: 'pending', @@ -527,15 +482,10 @@ export function useArtistConsole(deps: UseArtistConsoleDeps) { steps: artistRuntimeBootstrapRoadmap(stepIndex, 'submitted', confirmedBootstrapTxHashes) }); - await publicClient.waitForTransactionReceipt({ hash: txHash }); + await runtimeWriter.waitForTransaction(txHash); confirmedBootstrapTxHashes[stepIndex] = txHash; - pendingRuntime = (await publicClient.readContract({ - address: factoryAddress!, - abi: artistRuntimeFactoryAbi, - functionName: 'pendingRuntimeOf', - args: [activeEvmAddress] - })) as `0x${string}`; + pendingRuntime = await runtimeReader.pendingRuntimeOf(factoryAddress!, activeEvmAddress); } const runtimeAddress = await refreshArtistRuntime(); @@ -579,42 +529,20 @@ export function useArtistConsole(deps: UseArtistConsoleDeps) { setRoyaltyStatus('Reading artist runtime payments'); try { - const client = getPublicClient(ethRpcUrl); const trackByHash = new Map(artistTracks.map(track => [track.hash.toLowerCase(), track])); - const logs = await client.getLogs({ - address: artistRuntimeAddress, - event: musicRoyAccessPaidEvent, - fromBlock: 0n, - toBlock: 'latest' - }); - const blockTimestampsByNumber = new Map(); - await Promise.all( - Array.from(new Set(logs.map(log => log.blockNumber.toString()))).map(async blockNumber => { - const block = await client.getBlock({ blockNumber: BigInt(blockNumber) }); - blockTimestampsByNumber.set(blockNumber, block.timestamp); - }) - ); - + const logs = await runtimeReader.listRoyaltyPaymentLogs(artistRuntimeAddress); const payments = logs .map(log => { - const trackHash = log.args.contentHash; - const listener = log.args.listener; - const amountWei = log.args.amount; - - if (!trackHash || !listener || amountWei === undefined) { - return null; - } - - const track = trackByHash.get(trackHash.toLowerCase()); + const track = trackByHash.get(log.trackHash.toLowerCase()); return { id: `${log.transactionHash}-${log.logIndex}`, - trackHash, - trackTitle: track?.title ?? shorten(trackHash, 14), - listener, - amountWei, - amountDot: formatWeiAsDot(amountWei), - paidAtMs: formatBlockTimestampMs(blockTimestampsByNumber.get(log.blockNumber.toString())), + trackHash: log.trackHash, + trackTitle: track?.title ?? shorten(log.trackHash, 14), + listener: log.listener, + amountWei: log.amountWei, + amountDot: formatWeiAsDot(log.amountWei), + paidAtMs: log.paidAtMs, transactionHash: log.transactionHash, blockNumber: log.blockNumber, logIndex: log.logIndex @@ -862,7 +790,7 @@ export function useArtistConsole(deps: UseArtistConsoleDeps) { title: 'Checking factory', message: 'Verifying that the ArtistRuntimeFactory is reachable before submission.' }); - const factoryExists = await ensureContract(factoryAddress, ethRpcUrl); + const factoryExists = await runtimeReader.ensureContract(factoryAddress); if (!factoryExists) { setRightsStatus('Factory not found'); setTransactionFeedback({ tone: 'error', title: 'Factory unavailable', message: 'ArtistRuntimeFactory not found at the configured address.' }); @@ -880,6 +808,7 @@ export function useArtistConsole(deps: UseArtistConsoleDeps) { } const walletClient = await getActiveWalletClient(); + const runtimeWriter = createViemRuntimeWriter({ ethRpcUrl, walletClient }); const ipfsAudioRef = resolvedAudioRef || localAudioRef(fileHash); const ipfsCoverRef = resolvedCoverCID ? `ipfs://${resolvedCoverCID}` : `dotify:cover:${fileHash}`; @@ -890,27 +819,20 @@ export function useArtistConsole(deps: UseArtistConsoleDeps) { message: 'Sending the registration to your SmartRuntime.' }); - const txHash = await walletClient.writeContract({ - address: runtimeAddress, - abi: musicRegistryAbi, - functionName: 'musicRegRegister', - args: [ - { - contentHash: fileHash, - title, - artistName, - description, - imageRef: ipfsCoverRef, - audioRef: ipfsAudioRef, - metadataRef: ipfsMetadataRef, - artistContractRef: `dotify:self-certified:${fileHash}`, - accessMode: encodeAccessMode(accessMode), - pricePlanck: dotToPlanck(priceDotForAccessMode(accessMode, priceDot)), - requiredPersonhood: encodeRequiredPersonhood(accessMode, personhoodLevel) - }, - royaltyRecipients, - royaltyShares - ] + const txHash = await runtimeWriter.registerTrack(runtimeAddress, { + contentHash: fileHash, + title, + artistName, + description, + imageRef: ipfsCoverRef, + audioRef: ipfsAudioRef, + metadataRef: ipfsMetadataRef, + artistContractRef: `dotify:self-certified:${fileHash}`, + accessMode: encodeAccessMode(accessMode), + pricePlanck: dotToPlanck(priceDotForAccessMode(accessMode, priceDot)), + requiredPersonhood: encodeRequiredPersonhood(accessMode, personhoodLevel), + royaltyRecipients, + royaltyShares }); setRightsStatus('Waiting for transaction confirmation'); @@ -920,7 +842,7 @@ export function useArtistConsole(deps: UseArtistConsoleDeps) { message: 'Transaction submitted. Waiting for the final receipt on the EVM network.', txHash }); - await getPublicClient(ethRpcUrl).waitForTransactionReceipt({ hash: txHash }); + await runtimeWriter.waitForTransaction(txHash); setRightsStatus('Rights registered'); setTransactionFeedback({ tone: 'success', @@ -973,24 +895,20 @@ export function useArtistConsole(deps: UseArtistConsoleDeps) { setReleaseActionId(`${track.id}:access`); try { const walletClient = await getActiveWalletClient(); + const runtimeWriter = createViemRuntimeWriter({ ethRpcUrl, walletClient }); setTransactionFeedback({ tone: 'pending', title: 'Updating access', message: `Changing "${track.title}" access policy.` }); - const txHash = await walletClient.writeContract({ - address: runtimeAddress, - abi: musicRegistryAbi, - functionName: 'musicRegSetAccessMode', - args: [ - track.hash, - encodeAccessMode(nextAccessMode), - dotToPlanck(priceDotForAccessMode(nextAccessMode, nextPriceDot)), - encodeRequiredPersonhood(nextAccessMode, nextPersonhoodLevel) - ] + const txHash = await runtimeWriter.setAccessMode(runtimeAddress, { + contentHash: track.hash, + accessMode: encodeAccessMode(nextAccessMode), + pricePlanck: dotToPlanck(priceDotForAccessMode(nextAccessMode, nextPriceDot)), + requiredPersonhood: encodeRequiredPersonhood(nextAccessMode, nextPersonhoodLevel) }); setTransactionFeedback({ tone: 'pending', title: 'Awaiting confirmation', message: 'Access update submitted.', txHash }); - await getPublicClient(ethRpcUrl).waitForTransactionReceipt({ hash: txHash }); + await runtimeWriter.waitForTransaction(txHash); await refreshCatalogFromRegistry(track.hash); setTransactionFeedback({ tone: 'success', @@ -1029,26 +947,15 @@ export function useArtistConsole(deps: UseArtistConsoleDeps) { setReleaseActionId(`${track.id}:active`); try { const walletClient = await getActiveWalletClient(); + const runtimeWriter = createViemRuntimeWriter({ ethRpcUrl, walletClient }); setTransactionFeedback({ tone: 'pending', title: active ? 'Reactivating release' : 'Deactivating release', message: `${active ? 'Reactivating' : 'Deactivating'} "${track.title}".` }); - const txHash = active - ? await walletClient.writeContract({ - address: runtimeAddress, - abi: musicRegistryAbi, - functionName: 'musicRegReactivate', - args: [track.hash] - }) - : await walletClient.writeContract({ - address: runtimeAddress, - abi: musicRegistryAbi, - functionName: 'musicRegDeactivate', - args: [track.hash] - }); + const txHash = await runtimeWriter.setReleaseActive(runtimeAddress, track.hash, active); setTransactionFeedback({ tone: 'pending', title: 'Awaiting confirmation', message: 'Release status update submitted.', txHash }); - await getPublicClient(ethRpcUrl).waitForTransactionReceipt({ hash: txHash }); + await runtimeWriter.waitForTransaction(txHash); await refreshCatalogFromRegistry(track.hash); setTransactionFeedback({ tone: 'success', diff --git a/web/src/hooks/useCatalog.ts b/web/src/hooks/useCatalog.ts index e403caa..5fed5e8 100644 --- a/web/src/hooks/useCatalog.ts +++ b/web/src/hooks/useCatalog.ts @@ -1,6 +1,6 @@ import { useRef, useState } from 'react'; import { fetchAssetRef, fetchIpfsCid, getGatewayUrl } from '../services/pinata'; -import { ensureContract, getPublicClient, artistDirectoryAbi, musicRegistryAbi, musicAccessAbi, musicRoyaltiesAbi } from '../shared/config/contracts'; +import { getPublicClient } from '../shared/config/contracts'; import { decryptAudio, hexToBytes } from '../shared/utils/crypto'; import { formatWeiAsDot } from '../shared/utils/format'; import { isKeyServiceConfigured, requestContentKey, requestFreeContentKey, type KeyRequestPurpose } from '../services/keyService'; @@ -24,6 +24,8 @@ import { pumpAudioV2ReadAhead } from '../features/catalog/audioV2Pipeline'; import { AudioV2ChunkAuthenticationError, routeAudioV2MseFailure } from '../features/catalog/audioV2Recovery'; import { runtimeAddressFromTrackId } from '../features/catalog/trackModel'; import { decodeAccessMode, decodePersonhood } from '../features/runtime/accessEncoding'; +import { createViemRuntimeReader, createViemRuntimeWriter } from '../features/runtime/viemRuntimeAdapter'; +import type { RuntimeReadPort, RuntimeTrackSnapshot } from '../features/runtime/runtimePorts'; import { fetchCatalog, isCatalogApiConfigured, readCachedCatalog, type CatalogApiRelease } from '../services/catalog'; import { E2E_CLASSIC_AUDIO_URL, @@ -49,12 +51,10 @@ import type { AccessGate, AccessMode, CatalogTrack, - OnchainTrackRecord, PersonhoodLevel, PlayerState, RegistryCatalogTrack, RoomPlaybackMode, - RoyaltySplit, TrackInfo, TransactionFeedback } from '../shared/types'; @@ -272,6 +272,7 @@ export function useCatalog(deps: UseCatalogDeps) { setDescription } = deps; + const runtimeReader = createViemRuntimeReader({ ethRpcUrl }); const usesCatalogApi = isCatalogApiConfigured() && !isClassicUnlockE2e && !isArtistPublishE2e && !isRoomJoinE2e; const [initialCatalog] = useState(() => { const cached = usesCatalogApi ? readCachedCatalog() : null; @@ -379,12 +380,7 @@ export function useCatalog(deps: UseCatalogDeps) { // a buyer, or personhood-verified, so the read answers true only when // the track's current mode grants access to everyone (Free). This is // what lets a walletless visitor play Free tracks (access model v2). - return (await getPublicClient(ethRpcUrl).readContract({ - address: runtimeAddress, - abi: musicAccessAbi, - functionName: 'musicAccCanAccess', - args: [track.hash, listenerAddress ?? zeroAddress] - })) as boolean; + return await runtimeReader.canAccess(runtimeAddress, track.hash, listenerAddress ?? zeroAddress); } catch { return false; } @@ -405,12 +401,7 @@ export function useCatalog(deps: UseCatalogDeps) { const runtimeAddress = runtimeAddressFromTrackId(track); if (!runtimeAddress) return false; try { - return (await getPublicClient(ethRpcUrl).readContract({ - address: runtimeAddress, - abi: musicAccessAbi, - functionName: 'musicAccHasPaid', - args: [track.hash, listenerAddress] - })) as boolean; + return await runtimeReader.hasPaid(runtimeAddress, track.hash, listenerAddress); } catch { return false; } @@ -1008,7 +999,6 @@ export function useCatalog(deps: UseCatalogDeps) { const runtimeAddress = runtimeAddressFromTrackId(track); if (!runtimeAddress) return; - const { musicRoyaltiesAbi, getPublicClient: getClient } = await import('../shared/config/contracts'); const { dotToPlanck } = await import('../shared/utils/format'); const priceWei = dotToPlanck(track.priceDot); @@ -1022,15 +1012,10 @@ export function useCatalog(deps: UseCatalogDeps) { try { const walletClient = await getActiveWalletClient(); - const txHash = await walletClient.writeContract({ - address: runtimeAddress, - abi: musicRoyaltiesAbi, - functionName: 'musicRoyPayAccess', - args: [track.hash], - value: priceWei - }); + const runtimeWriter = createViemRuntimeWriter({ ethRpcUrl, walletClient }); + const txHash = await runtimeWriter.payForAccess(runtimeAddress, track.hash, priceWei); setTransactionFeedback({ tone: 'pending', title: 'Awaiting confirmation', message: 'Payment submitted.', txHash }); - await getClient(ethRpcUrl).waitForTransactionReceipt({ hash: txHash }); + await runtimeWriter.waitForTransaction(txHash); setCatalogAccessByTrackId(previous => ({ ...previous, [track.id]: true })); setCatalogPaidAccessByTrackId(previous => ({ ...previous, [track.id]: true })); @@ -1047,117 +1032,45 @@ export function useCatalog(deps: UseCatalogDeps) { } } - async function fetchDirectoryEntries(client: ReturnType, registryAddress: `0x${string}`, artistCount: bigint) { - const pageSize = 50n; - const entries: Array<{ artist: `0x${string}`; runtime: `0x${string}` }> = []; - - for (let offset = 0n; offset < artistCount; offset += pageSize) { - const limit = artistCount - offset > pageSize ? pageSize : artistCount - offset; - const [artists, runtimes] = (await client.readContract({ - address: registryAddress, - abi: artistDirectoryAbi, - functionName: 'artistsPage', - args: [offset, limit] - })) as [`0x${string}`[], `0x${string}`[]]; - - for (let index = 0; index < artists.length; index += 1) { - const artist = artists[index]; - const runtime = runtimes[index]; - if (!artist || !runtime || runtime === zeroAddress) continue; - entries.push({ artist, runtime }); - } - } + async function fetchRuntimeCatalog(reader: RuntimeReadPort, artistAddress: `0x${string}`, runtimeAddress: `0x${string}`): Promise { + const snapshots = await reader.listRuntimeTracks(runtimeAddress); + const tracks = snapshots.map((snapshot: RuntimeTrackSnapshot): RegistryCatalogTrack => { + const { hash, record: track } = snapshot; + const imageRef = resolveVisualAssetRef(track.imageRef, track.title); + const encrypted = isEncryptedAudioRef(track.audioRef); + const localUrl = resolveAudioAssetRef(track.audioRef); - return entries; - } - - async function fetchRuntimeCatalog( - client: ReturnType, - artistAddress: `0x${string}`, - runtimeAddress: `0x${string}` - ): Promise { - const trackCount = (await client.readContract({ - address: runtimeAddress, - abi: musicRegistryAbi, - functionName: 'musicRegTrackCount' - })) as bigint; - - const tracks: Array = await Promise.all( - Array.from({ length: Number(trackCount) }, async (_, index) => { - const hash = (await client.readContract({ - address: runtimeAddress, - abi: musicRegistryAbi, - functionName: 'musicRegTrackHashAtIndex', - args: [BigInt(index)] - })) as `0x${string}`; - - const [track] = (await client.readContract({ - address: runtimeAddress, - abi: musicRegistryAbi, - functionName: 'musicRegGetTrack', - args: [hash] - })) as [OnchainTrackRecord, `0x${string}`]; - - const imageRef = resolveVisualAssetRef(track.imageRef, track.title); - const encrypted = isEncryptedAudioRef(track.audioRef); - const localUrl = resolveAudioAssetRef(track.audioRef); - const splitCount = (await client - .readContract({ - address: runtimeAddress, - abi: musicRoyaltiesAbi, - functionName: 'musicRoySplitCount', - args: [hash] - }) - .catch(() => 0n)) as bigint; - const royaltySplits = await Promise.all( - Array.from({ length: Number(splitCount) }, async (_, splitIndex): Promise => { - try { - const [recipient, bps] = (await client.readContract({ - address: runtimeAddress, - abi: musicRoyaltiesAbi, - functionName: 'musicRoySplitAt', - args: [hash, BigInt(splitIndex)] - })) as [`0x${string}`, number]; - return { - label: splitIndex === 0 ? 'Primary recipient' : `Split ${splitIndex + 1}`, - recipient, - bps: Number(bps) - }; - } catch { - return null; - } - }) - ); - - return { - id: `${runtimeAddress}:${hash}`, - hash, - title: track.title, - artist: track.artistName, - artistAddress: track.artist || artistAddress, - audioRef: track.audioRef, - imageRef, - priceDot: formatWeiAsDot(track.pricePlanck), - localUrl, - description: track.description, - bulletinRef: track.metadataRef.startsWith('paseo-bulletin:') ? track.metadataRef : '', - metadataRef: track.metadataRef, - royaltyBps: Number(track.royaltyBps), - txHash: undefined, - durationLabel: 'ready', - accessMode: decodeAccessMode(Number(track.accessMode)), - active: track.active, - source: 'artist' as const, - royaltySplits: royaltySplits.filter((split): split is RoyaltySplit => Boolean(split)), - personhoodLevel: decodePersonhood(Number(track.requiredPersonhood)), - zone: 'Registry', - encrypted, - registeredAtBlock: Number(track.registeredAtBlock) - }; - }) - ); + return { + id: `${runtimeAddress}:${hash}`, + hash, + title: track.title, + artist: track.artistName, + artistAddress: track.artist || artistAddress, + audioRef: track.audioRef, + imageRef, + priceDot: formatWeiAsDot(track.pricePlanck), + localUrl, + description: track.description, + bulletinRef: track.metadataRef.startsWith('paseo-bulletin:') ? track.metadataRef : '', + metadataRef: track.metadataRef, + royaltyBps: Number(track.royaltyBps), + txHash: undefined, + durationLabel: 'ready', + accessMode: decodeAccessMode(Number(track.accessMode)), + active: track.active, + source: 'artist' as const, + royaltySplits: snapshot.royaltySplits.map((split, splitIndex) => ({ + label: splitIndex === 0 ? 'Primary recipient' : `Split ${splitIndex + 1}`, + ...split + })), + personhoodLevel: decodePersonhood(Number(track.requiredPersonhood)), + zone: 'Registry', + encrypted, + registeredAtBlock: Number(track.registeredAtBlock) + }; + }); - return tracks.flatMap(track => (track ? [track] : [])); + return tracks; } function commitCatalog(allTracks: CatalogTrack[], preferredTrackHash: `0x${string}` | undefined, status: string): CatalogTrack[] { @@ -1227,7 +1140,7 @@ export function useCatalog(deps: UseCatalogDeps) { setCatalogStatus('Loading registry catalog'); try { - const directoryExists = await ensureContract(directoryAddress, ethRpcUrl); + const directoryExists = await runtimeReader.ensureContract(directoryAddress); if (!directoryExists) { setCatalogTracks([]); setAllCatalogTracks([]); @@ -1236,12 +1149,7 @@ export function useCatalog(deps: UseCatalogDeps) { return []; } - const client = getPublicClient(ethRpcUrl); - const artistCount = (await client.readContract({ - address: directoryAddress, - abi: artistDirectoryAbi, - functionName: 'artistCount' - })) as bigint; + const artistCount = await runtimeReader.getArtistCount(directoryAddress); if (artistCount === 0n) { setCatalogTracks([]); @@ -1251,11 +1159,11 @@ export function useCatalog(deps: UseCatalogDeps) { return []; } - const entries = await fetchDirectoryEntries(client, directoryAddress, artistCount); + const entries = await runtimeReader.listArtistRuntimes(directoryAddress, artistCount); const runtimeCatalogs = await Promise.all( entries.map(async entry => { try { - return await fetchRuntimeCatalog(client, entry.artist, entry.runtime); + return await fetchRuntimeCatalog(runtimeReader, entry.artist, entry.runtime); } catch (runtimeError) { console.warn(`Failed to load runtime catalog for ${entry.runtime}`, runtimeError); return []; @@ -1341,7 +1249,6 @@ export function useCatalog(deps: UseCatalogDeps) { payForTrackAccess, fetchAndDecryptAudio, refreshCatalogFromRegistry, - fetchDirectoryEntries, fetchRuntimeCatalog, clearObjectUrls }; From 00f1d93db4e36462c16d5ecab7a0b14d5b3bb939 Mon Sep 17 00:00:00 2001 From: Kevin Nzeng Essimengane Date: Sun, 26 Jul 2026 23:40:55 +0200 Subject: [PATCH 4/4] feat: add Product CDM runtime adapter --- README.md | 9 +- docs/backlog/README.md | 13 +- ...oduct-readiness-and-killer-dapp-roadmap.md | 6 +- docs/explanation/architecture-overview.md | 4 +- .../product-devnet-architecture.md | 29 +- docs/index.html | 8 +- docs/operations/product-devnet-deployment.md | 5 +- spec.md | 9 +- .../runtime/productCdmRuntimeAdapter.test.ts | 286 +++++++++++++++ .../runtime/productCdmRuntimeAdapter.ts | 345 ++++++++++++++++++ 10 files changed, 689 insertions(+), 25 deletions(-) create mode 100644 web/src/features/runtime/productCdmRuntimeAdapter.test.ts create mode 100644 web/src/features/runtime/productCdmRuntimeAdapter.ts diff --git a/README.md b/README.md index 2a23937..91ca92a 100644 --- a/README.md +++ b/README.md @@ -45,9 +45,12 @@ iteration can move signaling to statement-store style infrastructure. **Product SDK direction**: Dotify now has an adaptive Product DevNet build for `dotify-test01.dot`. It keeps standalone link-first rooms and Free listening intact, adds explicit app-scoped Product identity, and publishes through -Bulletin/DotNS. Product host signing is not yet accepted for contract writes or -protected key delivery; those boundaries remain passkey/EVM until the CDM/PAPI -and backend signature adapters are proven. See +Bulletin/DotNS. The runtime hooks now sit behind typed ports with the current +viem implementation and an experimental Product CDM/PAPI adapter boundary. +Product host signing is not yet accepted for contract writes or protected key +delivery; those boundaries remain passkey/EVM until CDM-installed runtime +packages, host-signed transaction evidence, and backend signature adapters are +proven. See [`docs/explanation/product-devnet-architecture.md`](docs/explanation/product-devnet-architecture.md) and the [`Product roadmap`](docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md). diff --git a/docs/backlog/README.md b/docs/backlog/README.md index 6702155..5e32be6 100644 --- a/docs/backlog/README.md +++ b/docs/backlog/README.md @@ -107,9 +107,11 @@ Product SDK direction. The plan is now dual-mode: standalone web remains the first public listening path, while the Product DevNet build adds `dotify-test01.dot`, explicit Host detection, app-scoped Product identity, and canonical -Product-origin room links. It does not imply Product-signed contract writes, -protected key access, Statement Store rooms, or Humanity decisions; those -remain gated until their adapters prove the current API and security boundary. +Product-origin room links. The typed runtime ports and experimental +Product CDM/PAPI adapter boundary are implementation preparation only; they do +not imply Product-signed contract writes, protected key access, Statement Store +rooms, or Humanity decisions. Those remain gated until their adapters prove the +current API and security boundary. The Product SDK evidence snapshot used for this replanning is `@parity/product-sdk` 0.19.1 and @@ -162,8 +164,9 @@ on `main`. The remaining order is: 3. Improve room resilience and shared-listening depth only where it preserves the link-first guest doctrine. 4. Validate the delivered Product host/account and Bulletin/DotNS baseline, - then port writes through CDM/PAPI, add backend Product-signature - verification, and run bounded resource-allocation/Statement Store spikes. + then wire real CDM-installed runtime packages through the Product CDM/PAPI + adapter, add backend Product-signature verification, and run bounded + resource-allocation/Statement Store spikes. 5. Build live Humanity / Individuality only after the research ticket proves a privacy-preserving source, proof shape, address-binding story, and fallback UX. diff --git a/docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md b/docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md index 1d2a4b5..e3a9b9d 100644 --- a/docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md +++ b/docs/backlog/polkadot-product-readiness-and-killer-dapp-roadmap.md @@ -164,7 +164,11 @@ Goal: deepen the delivered Product mode one adapter at a time. - Delivered on the follow-up branch: extract typed runtime read/write ports and move the current viem runtime implementation behind `RuntimeReadPort` / `RuntimeWritePort`. -- Next: add a generated CDM/PAPI adapter behind those ports. +- Delivered on the next follow-up branch: add an experimental CDM/PAPI adapter + behind those ports. It is not selected by default until Dotify has + CDM-installed Product runtime packages and host-signed transaction evidence. +- Next: wire a generated CDM manifest/types into Product mode and run real host + transaction smoke tests. - Next: add a backend signature-scheme adapter that verifies Product account signatures and address binding before key delivery. - Keep backend key delivery authoritative unless a Product-host design proves a diff --git a/docs/explanation/architecture-overview.md b/docs/explanation/architecture-overview.md index 58f4dad..d3439a1 100644 --- a/docs/explanation/architecture-overview.md +++ b/docs/explanation/architecture-overview.md @@ -104,7 +104,9 @@ src/ │ └── useWallet.ts # Wallet tiers: passkey → EIP-6963 extension ├── features/runtime/ │ ├── runtimePorts.ts # RuntimeReadPort / RuntimeWritePort contracts -│ └── viemRuntimeAdapter.ts # Current EVM implementation behind the ports +│ ├── viemRuntimeAdapter.ts # Current EVM implementation behind the ports +│ └── productCdmRuntimeAdapter.ts +│ # Experimental Product CDM/PAPI adapter ├── views/ # One file per screen / tab │ ├── ListenView.tsx │ ├── PlayerView.tsx diff --git a/docs/explanation/product-devnet-architecture.md b/docs/explanation/product-devnet-architecture.md index 8ceea6b..160fa98 100644 --- a/docs/explanation/product-devnet-architecture.md +++ b/docs/explanation/product-devnet-architecture.md @@ -149,17 +149,28 @@ Adapters: - `ViemRuntimeAdapter`: current standalone EVM implementation behind the typed ports; -- `ProductRuntimeAdapter`: next adapter, generated from CDM/ABI bindings and - submitted with the host PAPI signer; +- `ProductCdmRuntimeAdapter`: experimental CDM/PAPI implementation behind the + same ports. It maps the Dotify runtime method surface to Product SDK contract + handles, but remains opt-in until Dotify has CDM-installed Product runtime + packages and host signing evidence; - `CatalogApiAdapter`: the existing server-side read model, shared by both frontends. -The remaining Product contract work is adapter work, not UI rewiring. The -backend authentication protocol must still gain an explicit signature scheme -field. A Product signature is accepted only after the server can bind the -signed payload, Product account public key, derived H160, chain, nonce, -purpose, and expiry. EIP-191 remains supported for standalone clients. Unknown -schemes fail closed. +The CDM adapter has one deliberate gap: royalty payment history is not read +through Product contract handles because the current SDK surface exposes +method queries and transactions, not the viem-style historical log query used +by the artist console. Product mode must use the backend catalog/read-model +indexer, or a future Product event/indexer API, for that history. + +The remaining Product contract work is integration and evidence work, not UI +rewiring. Operators still need CDM-deployed Dotify runtime packages, +`cdm.json`/generated contract types, `pallet-revive` account mapping, and real +host-signed transaction smoke evidence before Product writes can replace the +EVM wallet path. The backend authentication protocol must also gain an +explicit signature scheme field. A Product signature is accepted only after the +server can bind the signed payload, Product account public key, derived H160, +chain, nonce, purpose, and expiry. EIP-191 remains supported for standalone +clients. Unknown schemes fail closed. This avoids a second frontend business model and allows Product mode to replace one infrastructure adapter at a time. @@ -209,6 +220,8 @@ For every SDK or deploy-tool upgrade: - [Product documentation](https://docs.polkadotcommunity.foundation/) - [Build and publish guide](https://docs.polkadotcommunity.foundation/guides/build-and-publish/) +- [Deploy and register contracts with CDM](https://docs.polkadotcommunity.foundation/guides/deploy-contracts-cdm/) +- [Smart contracts and CDM](https://docs.polkadotcommunity.foundation/architecture/contracts/) - [Platform Services SDK guide](https://docs.polkadotcommunity.foundation/guides/platform-services-sdk/) - [Product network reference](https://docs.polkadotcommunity.foundation/reference/networks/) - [Product identity architecture](https://docs.polkadotcommunity.foundation/architecture/identity/) diff --git a/docs/index.html b/docs/index.html index 175a953..87f46e7 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1541,10 +1541,10 @@

    Operate the spine and validate first sound

    Product DevNet now, sovereignty adapters next

    Dotify now has a publishable dotify-test01.dot build, explicit app-scoped Product - identity, public room links that preserve wallet-free entry, and typed runtime ports around - the current viem implementation. CDM/PAPI contract writes, Product-signed key requests, - Humanity/Individuality proofs, consented provenance, and ambassador mechanics remain - sequenced behind verified security and privacy boundaries. + identity, public room links that preserve wallet-free entry, typed runtime ports around the + current viem implementation, and an experimental CDM/PAPI adapter boundary. Product contract + writes, Product-signed key requests, Humanity/Individuality proofs, consented provenance, and + ambassador mechanics remain sequenced behind verified security and privacy boundaries.

    diff --git a/docs/operations/product-devnet-deployment.md b/docs/operations/product-devnet-deployment.md index 84270a4..4c1fe1d 100644 --- a/docs/operations/product-devnet-deployment.md +++ b/docs/operations/product-devnet-deployment.md @@ -171,7 +171,10 @@ active. ## Known Limits - Product account signing is identity/presence only in this phase. -- Contract writes and key requests still require passkey/EVM signing. +- Contract writes and key requests still require passkey/EVM signing in the + shipped UI. The experimental Product CDM/PAPI runtime adapter is present in + code, but it is not selected until Dotify has CDM-installed runtime packages, + generated contract types, and real host-signed transaction evidence. - Rooms still depend on one in-memory Fly signaling machine. - Product-host cloud storage does not hold Dotify audio or content keys. - Product personhood is not yet an access decision source. diff --git a/spec.md b/spec.md index c2692df..bcb9bda 100644 --- a/spec.md +++ b/spec.md @@ -119,6 +119,10 @@ host, and requests an app-scoped account only after explicit user action. That account is currently an identity/presence capability: Classic payments, artist publication, and protected key requests still require the passkey/EVM path until CDM/PAPI writes and backend Product-signature verification are delivered. +The runtime hooks now depend on typed read/write ports; the current viem +adapter remains active, and the Product CDM/PAPI adapter remains experimental +until Dotify has CDM-installed runtime packages and host-signed transaction +evidence. ## 5. Repository Layout @@ -668,8 +672,9 @@ Priority improvements: 4. Finish security hardening for publish intents, auth chain binding, durable revocation, realtime reconnect, and short-lived TURN credentials. 5. Validate the delivered Product host/account and Bulletin/DotNS deployment - baseline, then implement CDM/PAPI contract portability, backend Product - signature verification, and a bounded Statement Store presence spike. + baseline, then wire real CDM-installed runtime packages through the + experimental Product CDM/PAPI adapter, add backend Product signature + verification, and run a bounded Statement Store presence spike. 6. Move the large catalog, session, artist, and player workflows behind domain ports and application use cases. 7. Validate the cacheable catalog API's warm/cold p75 budgets under public seed diff --git a/web/src/features/runtime/productCdmRuntimeAdapter.test.ts b/web/src/features/runtime/productCdmRuntimeAdapter.test.ts new file mode 100644 index 0000000..3ea0a23 --- /dev/null +++ b/web/src/features/runtime/productCdmRuntimeAdapter.test.ts @@ -0,0 +1,286 @@ +import { describe, expect, it, vi } from 'vitest'; +import { + ProductCdmRuntimeError, + ProductCdmRuntimeUnsupportedOperationError, + createProductCdmRuntimeContractResolver, + createProductCdmRuntimeReader, + createProductCdmRuntimeWriter, + type ProductCdmContractHandle +} from './productCdmRuntimeAdapter'; +import type { OnchainTrackRecord } from '../../shared/types'; + +const directory = '0x1000000000000000000000000000000000000000' as const; +const factory = '0x2000000000000000000000000000000000000000' as const; +const runtime = '0x3000000000000000000000000000000000000000' as const; +const artist = '0x4000000000000000000000000000000000000000' as const; +const listener = '0x5000000000000000000000000000000000000000' as const; +const splitRecipient = '0x6000000000000000000000000000000000000000' as const; +const hash = `0x${'ab'.repeat(32)}` as const; +const txHash = `0x${'cd'.repeat(32)}` as const; + +function baseTrackRecord(patch: Partial = {}): OnchainTrackRecord { + return { + artist, + tokenId: 1n, + title: 'Product runtime song', + artistName: 'Product runtime artist', + description: 'CDM-backed description', + imageRef: 'ipfs://cover', + audioRef: 'dotify.audio.v2:audio', + metadataRef: 'ipfs://metadata', + artistContractRef: 'dotify:self-certified', + royaltyBps: 9000, + accessMode: 1, + pricePlanck: 1_000_000_000_000_000_000n, + requiredPersonhood: 0, + registeredAtBlock: 12n, + active: true, + ...patch + }; +} + +function queryMethod(value: unknown) { + return { + query: vi.fn(async () => ({ success: true as const, value })) + }; +} + +function txMethod() { + return { + tx: vi.fn(async () => ({ + ok: true as const, + value: { + txHash, + ok: true + } + })) + }; +} + +describe('createProductCdmRuntimeContractResolver', () => { + it('resolves static CDM packages and requires an explicit runtime instance factory', async () => { + const directoryContract = {}; + const factoryContract = {}; + const manager = { + getContract: vi.fn((packageName: string) => { + if (packageName === '@dotify/directory') return directoryContract; + if (packageName === '@dotify/factory') return factoryContract; + throw new Error(`unexpected package ${packageName}`); + }), + getAddress: vi.fn((packageName: string) => { + if (packageName === '@dotify/directory') return directory; + if (packageName === '@dotify/factory') return factory; + return runtime; + }) + }; + const resolver = createProductCdmRuntimeContractResolver({ + manager, + packages: { + directory: '@dotify/directory', + factory: '@dotify/factory', + runtime: '@dotify/runtime' + } + }); + + expect(await resolver.hasContract?.(directory)).toBe(true); + expect(await resolver.hasContract?.(runtime)).toBe(false); + expect(resolver.getDirectoryContract(directory)).toBe(directoryContract); + expect(resolver.getFactoryContract(factory)).toBe(factoryContract); + expect(() => resolver.getRuntimeContract(runtime)).toThrow(ProductCdmRuntimeUnsupportedOperationError); + }); + + it('fails closed when a configured package address does not match the requested address', () => { + const resolver = createProductCdmRuntimeContractResolver({ + manager: { + getContract: vi.fn(() => ({})), + getAddress: vi.fn(() => factory) + }, + packages: { + directory: '@dotify/directory', + factory: '@dotify/factory', + runtime: '@dotify/runtime' + } + }); + + expect(() => resolver.getDirectoryContract(directory)).toThrow(ProductCdmRuntimeError); + }); +}); + +describe('createProductCdmRuntimeReader', () => { + it('paginates directory runtimes and filters zero-address entries', async () => { + const artistsPage = { + query: vi.fn(async (offset: unknown) => { + if (offset === 0n) { + return { success: true as const, value: [[artist], [runtime]] }; + } + return { success: true as const, value: [[listener], ['0x0000000000000000000000000000000000000000']] }; + }) + }; + const reader = createProductCdmRuntimeReader({ + directoryPageSize: 50n, + contracts: { + getDirectoryContract: () => ({ artistsPage }), + getFactoryContract: () => ({}), + getRuntimeContract: () => ({}) + } + }); + + await expect(reader.listArtistRuntimes(directory, 51n)).resolves.toEqual([{ artist, runtime }]); + expect(artistsPage.query).toHaveBeenCalledTimes(2); + }); + + it('returns runtime track snapshots with royalty splits and skips unreadable splits', async () => { + const record = baseTrackRecord(); + const musicRoySplitAt = { + query: vi.fn(async (_contentHash: unknown, splitIndex: unknown) => { + if (splitIndex === 1n) { + return { success: false as const, value: 'missing split' }; + } + return { success: true as const, value: [splitRecipient, 2500n] }; + }) + }; + const runtimeContract: ProductCdmContractHandle = { + musicRegTrackCount: queryMethod(1n), + musicRegTrackHashAtIndex: queryMethod(hash), + musicRegGetTrack: queryMethod([record, runtime]), + musicRoySplitCount: queryMethod(2n), + musicRoySplitAt + }; + const reader = createProductCdmRuntimeReader({ + contracts: { + getDirectoryContract: () => ({}), + getFactoryContract: () => ({}), + getRuntimeContract: () => runtimeContract + } + }); + + await expect(reader.listRuntimeTracks(runtime)).resolves.toEqual([ + { + hash, + record, + royaltySplits: [{ recipient: splitRecipient, bps: 2500 }] + } + ]); + }); + + it('normalizes zero-address runtime lookups and rejects failed queries', async () => { + const reader = createProductCdmRuntimeReader({ + contracts: { + getDirectoryContract: () => ({ + runtimeOf: queryMethod('0x0000000000000000000000000000000000000000'), + artistCount: { + query: vi.fn(async () => ({ success: false as const, value: 'registry unavailable' })) + } + }), + getFactoryContract: () => ({}), + getRuntimeContract: () => ({}) + } + }); + + await expect(reader.resolveArtistRuntime(directory, artist)).resolves.toBeNull(); + await expect(reader.getArtistCount(directory)).rejects.toThrow(ProductCdmRuntimeError); + }); + + it('marks royalty payment history unsupported until Product events are indexed', async () => { + const reader = createProductCdmRuntimeReader({ + contracts: { + getDirectoryContract: () => ({}), + getFactoryContract: () => ({}), + getRuntimeContract: () => ({}) + } + }); + + await expect(reader.listRoyaltyPaymentLogs(runtime)).rejects.toThrow(ProductCdmRuntimeUnsupportedOperationError); + }); +}); + +describe('createProductCdmRuntimeWriter', () => { + it('routes runtime writes through Product CDM contract tx methods', async () => { + const createRuntime = txMethod(); + const installRuntimeStep = txMethod(); + const musicRegRegister = txMethod(); + const musicRoyPayAccess = txMethod(); + const musicRegSetAccessMode = txMethod(); + const musicRegDeactivate = txMethod(); + const writer = createProductCdmRuntimeWriter({ + contracts: { + getDirectoryContract: () => ({}), + getFactoryContract: () => ({ createRuntime, installRuntimeStep }), + getRuntimeContract: () => ({ + musicRegRegister, + musicRoyPayAccess, + musicRegSetAccessMode, + musicRegDeactivate + }) + } + }); + + await expect(writer.createRuntime(factory)).resolves.toBe(txHash); + await expect(writer.installRuntimeStep(factory)).resolves.toBe(txHash); + await expect( + writer.registerTrack(runtime, { + contentHash: hash, + title: 'Product song', + artistName: 'Product artist', + description: 'Published through CDM', + imageRef: 'ipfs://cover', + audioRef: 'dotify.audio.v2:audio', + metadataRef: 'ipfs://metadata', + artistContractRef: 'dotify:self-certified', + accessMode: 1, + pricePlanck: 1n, + requiredPersonhood: 0, + royaltyRecipients: [artist], + royaltyShares: [10_000] + }) + ).resolves.toBe(txHash); + await expect(writer.payForAccess(runtime, hash, 3n)).resolves.toBe(txHash); + await expect( + writer.setAccessMode(runtime, { + contentHash: hash, + accessMode: 2, + pricePlanck: 0n, + requiredPersonhood: 1 + }) + ).resolves.toBe(txHash); + await expect(writer.setReleaseActive(runtime, hash, false)).resolves.toBe(txHash); + await expect(writer.waitForTransaction(txHash)).resolves.toBeUndefined(); + + expect(musicRoyPayAccess.tx).toHaveBeenCalledWith(hash, { value: 3n }); + expect(musicRegSetAccessMode.tx).toHaveBeenCalledWith(hash, 2, 0n, 1); + expect(musicRegDeactivate.tx).toHaveBeenCalledWith(hash); + }); + + it('throws when Product tx submission returns an error or invalid hash', async () => { + const failedTx = { + tx: vi.fn(async () => ({ ok: false as const, error: 'no signer' })) + }; + const badHashTx = { + tx: vi.fn(async () => ({ + ok: true as const, + value: { + txHash: '0x123', + ok: true + } + })) + }; + + const failedWriter = createProductCdmRuntimeWriter({ + contracts: { + getDirectoryContract: () => ({}), + getFactoryContract: () => ({ createRuntime: failedTx }), + getRuntimeContract: () => ({}) + } + }); + const badHashWriter = createProductCdmRuntimeWriter({ + contracts: { + getDirectoryContract: () => ({}), + getFactoryContract: () => ({ createRuntime: badHashTx }), + getRuntimeContract: () => ({}) + } + }); + + await expect(failedWriter.createRuntime(factory)).rejects.toThrow(ProductCdmRuntimeError); + await expect(badHashWriter.createRuntime(factory)).rejects.toThrow(ProductCdmRuntimeError); + }); +}); diff --git a/web/src/features/runtime/productCdmRuntimeAdapter.ts b/web/src/features/runtime/productCdmRuntimeAdapter.ts new file mode 100644 index 0000000..df38821 --- /dev/null +++ b/web/src/features/runtime/productCdmRuntimeAdapter.ts @@ -0,0 +1,345 @@ +import { zeroAddress, type Address, type Hash } from 'viem'; +import type { + RuntimeAccessPolicyUpdate, + RuntimeDirectoryEntry, + RuntimeReadPort, + RuntimeRoyaltyPaymentLog, + RuntimeTrackRegistration, + RuntimeTrackSnapshot, + RuntimeWritePort +} from './runtimePorts'; +import type { OnchainTrackRecord } from '../../shared/types'; + +export type ProductCdmQueryResult = + | { + success: true; + value: T; + gasRequired?: unknown; + } + | { + success: false; + value: unknown; + gasRequired?: unknown; + }; + +export type ProductCdmTxResult = { + txHash: string; + ok: boolean; + dispatchError?: unknown; +}; + +export type ProductCdmResult = + | { + ok: true; + value: T; + } + | { + ok: false; + error: unknown; + }; + +export type ProductCdmContractMethod = { + query?: (...args: unknown[]) => Promise; + tx?: (...args: unknown[]) => Promise>; +}; + +// Structural mirror of @parity/product-sdk-contracts handles. Keeping this +// local lets unit tests exercise the adapter without opening a Product host. +export type ProductCdmContractHandle = Record; + +export type ProductCdmRuntimePackages = { + directory: string; + factory: string; + runtime: string; +}; + +export type ProductCdmContractManagerLike = { + getContract(packageName: string): ProductCdmContractHandle; + getAddress?: (packageName: string) => Address; +}; + +export type ProductCdmRuntimeContractFactory = (runtimeAddress: Address, runtimePackage: string) => ProductCdmContractHandle; + +export type ProductCdmRuntimeContractResolver = { + hasContract?: (address: Address) => Promise; + getDirectoryContract(directoryAddress: Address): ProductCdmContractHandle; + getFactoryContract(factoryAddress: Address): ProductCdmContractHandle; + getRuntimeContract(runtimeAddress: Address): ProductCdmContractHandle; +}; + +export type ProductCdmRuntimeAdapterDeps = { + contracts: ProductCdmRuntimeContractResolver; + directoryPageSize?: bigint; +}; + +export class ProductCdmRuntimeError extends Error { + constructor(message: string) { + super(message); + this.name = 'ProductCdmRuntimeError'; + } +} + +export class ProductCdmRuntimeUnsupportedOperationError extends ProductCdmRuntimeError { + constructor(message: string) { + super(message); + this.name = 'ProductCdmRuntimeUnsupportedOperationError'; + } +} + +export function createProductCdmRuntimeContractResolver(input: { + manager: ProductCdmContractManagerLike; + packages: ProductCdmRuntimePackages; + runtimeContractFactory?: ProductCdmRuntimeContractFactory; + hasContract?: (address: Address) => Promise; +}): ProductCdmRuntimeContractResolver { + const { manager, packages, runtimeContractFactory } = input; + + return { + async hasContract(address) { + if (input.hasContract) return input.hasContract(address); + return [packages.directory, packages.factory].some(packageName => { + try { + return sameAddress(manager.getAddress?.(packageName), address); + } catch { + return false; + } + }); + }, + + getDirectoryContract(directoryAddress) { + assertPackageAddress(manager, packages.directory, directoryAddress, 'ArtistDirectory'); + return manager.getContract(packages.directory); + }, + + getFactoryContract(factoryAddress) { + assertPackageAddress(manager, packages.factory, factoryAddress, 'ArtistRuntimeFactory'); + return manager.getContract(packages.factory); + }, + + getRuntimeContract(runtimeAddress) { + if (!runtimeContractFactory) { + throw new ProductCdmRuntimeUnsupportedOperationError( + 'Product CDM runtime instance resolution is not configured. Run cdm install for the SmartRuntime ABI and pass a runtimeContractFactory that binds that ABI to the artist runtime address.' + ); + } + return runtimeContractFactory(runtimeAddress, packages.runtime); + } + }; +} + +export function createProductCdmRuntimeReader(deps: ProductCdmRuntimeAdapterDeps): RuntimeReadPort { + const pageSize = deps.directoryPageSize ?? 50n; + + return { + async ensureContract(address) { + return deps.contracts.hasContract ? deps.contracts.hasContract(address) : false; + }, + + async resolveArtistRuntime(directoryAddress, artistAddress) { + const runtimeAddress = await queryContract
    (deps.contracts.getDirectoryContract(directoryAddress), 'runtimeOf', [artistAddress]); + return runtimeAddress === zeroAddress ? null : runtimeAddress; + }, + + async getArtistCount(directoryAddress) { + return toBigInt(await queryContract(deps.contracts.getDirectoryContract(directoryAddress), 'artistCount')); + }, + + async listArtistRuntimes(directoryAddress, artistCount) { + const directory = deps.contracts.getDirectoryContract(directoryAddress); + const entries: RuntimeDirectoryEntry[] = []; + + for (let offset = 0n; offset < artistCount; offset += pageSize) { + const limit = artistCount - offset > pageSize ? pageSize : artistCount - offset; + const [artists, runtimes] = await queryContract<[Address[], Address[]]>(directory, 'artistsPage', [offset, limit]); + + for (let index = 0; index < artists.length; index += 1) { + const artist = artists[index]; + const runtime = runtimes[index]; + if (!artist || !runtime || runtime === zeroAddress) continue; + entries.push({ artist, runtime }); + } + } + + return entries; + }, + + async listRuntimeTracks(runtimeAddress) { + const runtime = deps.contracts.getRuntimeContract(runtimeAddress); + const trackCount = toBigInt(await queryContract(runtime, 'musicRegTrackCount')); + + return Promise.all( + Array.from({ length: Number(trackCount) }, async (_, index): Promise => { + const hash = await queryContract(runtime, 'musicRegTrackHashAtIndex', [BigInt(index)]); + const trackResult = await queryContract(runtime, 'musicRegGetTrack', [hash]); + const record = Array.isArray(trackResult) ? trackResult[0] : trackResult; + const splitCount = await queryContract(runtime, 'musicRoySplitCount', [hash]).catch(() => 0n); + const royaltySplits = ( + await Promise.all( + Array.from({ length: Number(splitCount) }, async (_, splitIndex) => { + try { + const [recipient, bps] = await queryContract<[Address, bigint | number | string]>(runtime, 'musicRoySplitAt', [hash, BigInt(splitIndex)]); + return { recipient, bps: toNumber(bps) }; + } catch { + return null; + } + }) + ) + ).filter((split): split is { recipient: Address; bps: number } => Boolean(split)); + + return { hash, record, royaltySplits }; + }) + ); + }, + + canAccess(runtimeAddress, contentHash, listenerAddress) { + return queryContract(deps.contracts.getRuntimeContract(runtimeAddress), 'musicAccCanAccess', [contentHash, listenerAddress]); + }, + + hasPaid(runtimeAddress, contentHash, listenerAddress) { + return queryContract(deps.contracts.getRuntimeContract(runtimeAddress), 'musicAccHasPaid', [contentHash, listenerAddress]); + }, + + async pendingRuntimeOf(factoryAddress, artistAddress) { + const runtimeAddress = await queryContract
    (deps.contracts.getFactoryContract(factoryAddress), 'pendingRuntimeOf', [artistAddress]); + return runtimeAddress === zeroAddress ? null : runtimeAddress; + }, + + async pendingRuntimeStageOf(factoryAddress, artistAddress) { + return toNumber( + await queryContract(deps.contracts.getFactoryContract(factoryAddress), 'pendingRuntimeStageOf', [artistAddress]) + ); + }, + + async listRoyaltyPaymentLogs(): Promise { + throw new ProductCdmRuntimeUnsupportedOperationError( + 'Product CDM runtime payment history is not available through the current contract handle API. Use the catalog/read-model indexer until a Product event API or backend indexer is wired.' + ); + } + }; +} + +export function createProductCdmRuntimeWriter(deps: ProductCdmRuntimeAdapterDeps): RuntimeWritePort { + return { + createRuntime(factoryAddress) { + return txContract(deps.contracts.getFactoryContract(factoryAddress), 'createRuntime'); + }, + + installRuntimeStep(factoryAddress) { + return txContract(deps.contracts.getFactoryContract(factoryAddress), 'installRuntimeStep'); + }, + + registerTrack(runtimeAddress, registration: RuntimeTrackRegistration) { + return txContract(deps.contracts.getRuntimeContract(runtimeAddress), 'musicRegRegister', [ + { + contentHash: registration.contentHash, + title: registration.title, + artistName: registration.artistName, + description: registration.description, + imageRef: registration.imageRef, + audioRef: registration.audioRef, + metadataRef: registration.metadataRef, + artistContractRef: registration.artistContractRef, + accessMode: registration.accessMode, + pricePlanck: registration.pricePlanck, + requiredPersonhood: registration.requiredPersonhood + }, + registration.royaltyRecipients, + registration.royaltyShares + ]); + }, + + payForAccess(runtimeAddress, contentHash, value) { + return txContract(deps.contracts.getRuntimeContract(runtimeAddress), 'musicRoyPayAccess', [contentHash, { value }]); + }, + + setAccessMode(runtimeAddress, update: RuntimeAccessPolicyUpdate) { + return txContract(deps.contracts.getRuntimeContract(runtimeAddress), 'musicRegSetAccessMode', [ + update.contentHash, + update.accessMode, + update.pricePlanck, + update.requiredPersonhood + ]); + }, + + setReleaseActive(runtimeAddress, contentHash, active) { + return txContract(deps.contracts.getRuntimeContract(runtimeAddress), active ? 'musicRegReactivate' : 'musicRegDeactivate', [contentHash]); + }, + + async waitForTransaction() { + return; + } + }; +} + +function assertPackageAddress(manager: ProductCdmContractManagerLike, packageName: string, requestedAddress: Address, label: string): void { + const resolvedAddress = manager.getAddress?.(packageName); + if (resolvedAddress && !sameAddress(resolvedAddress, requestedAddress)) { + throw new ProductCdmRuntimeError(`${label} address ${requestedAddress} does not match CDM package ${packageName} at ${resolvedAddress}.`); + } +} + +function sameAddress(left: Address | undefined, right: Address): boolean { + return Boolean(left && left.toLowerCase() === right.toLowerCase()); +} + +function getMethod(contract: ProductCdmContractHandle, methodName: string): ProductCdmContractMethod { + const method = contract[methodName]; + if (!method) { + throw new ProductCdmRuntimeError(`Product CDM contract method "${methodName}" is missing from the installed ABI.`); + } + return method; +} + +async function queryContract(contract: ProductCdmContractHandle, methodName: string, args: unknown[] = []): Promise { + const method = getMethod(contract, methodName); + if (!method.query) { + throw new ProductCdmRuntimeError(`Product CDM contract method "${methodName}" does not support query.`); + } + + const result = await method.query(...args); + if (!result.success) { + throw new ProductCdmRuntimeError(`Product CDM query "${methodName}" failed: ${formatUnknown(result.value)}`); + } + return result.value as T; +} + +async function txContract(contract: ProductCdmContractHandle, methodName: string, args: unknown[] = []): Promise { + const method = getMethod(contract, methodName); + if (!method.tx) { + throw new ProductCdmRuntimeError(`Product CDM contract method "${methodName}" does not support transactions.`); + } + + const result = await method.tx(...args); + if (!result.ok) { + throw new ProductCdmRuntimeError(`Product CDM transaction "${methodName}" failed: ${formatUnknown(result.error)}`); + } + if (!result.value.ok) { + throw new ProductCdmRuntimeError(`Product CDM transaction "${methodName}" was rejected by the runtime: ${formatUnknown(result.value.dispatchError)}`); + } + return asHash(result.value.txHash, methodName); +} + +function asHash(value: string, methodName: string): Hash { + if (/^0x[0-9a-fA-F]{64}$/.test(value)) return value as Hash; + throw new ProductCdmRuntimeError(`Product CDM transaction "${methodName}" returned an invalid transaction hash.`); +} + +function toBigInt(value: bigint | number | string): bigint { + if (typeof value === 'bigint') return value; + if (typeof value === 'number') return BigInt(value); + return BigInt(value); +} + +function toNumber(value: bigint | number | string): number { + return Number(value); +} + +function formatUnknown(value: unknown): string { + if (value instanceof Error) return value.message; + if (typeof value === 'string') return value; + try { + return JSON.stringify(value) ?? String(value); + } catch { + return String(value); + } +}