Skip to main content

Installation

# From the monorepo
import { initializeFromShyConfig } from '../shyware/sdk/web/votingClient.js'

# Published package (when available)
npm install @co-mission/shyware-sdk
The web SDK is ESM-only. Each embodiment has its own client module; there is no monolithic entry point.

Pattern

Every client follows the same three-step pattern:

1. Validate and initialize from a shyconfig

import { initializeFromShyConfig } from 'shyware/sdk/web/votingClient.js'

const client = await initializeFromShyConfig(shyconfig, {
  // optional overrides
  receiptStore: customStore,  // custom receipt backend
  apiBaseUrl: 'https://api.yourdomain.com'
})
initializeFromShyConfig calls assertXManifest internally. It throws a descriptive error if the manifest is missing required fields, specifies an unsupported contract version, or declares an incompatible identity mode. Initialization is idempotent.

2. Build a transaction envelope

const envelope = await client.buildBallot({
  pollId: 'proposal-42',
  choice: 'yes',
  personId: 'didit-journey-id'
})
// → { txJson, ballotId, ballotNonce, encSecret? }
Build methods return a transaction envelope — a JSON-serialized transaction payload plus any client-side metadata the caller needs to retain (receipt nonce, transfer ID, nullifier, etc.). The envelope is not yet submitted.

3. Submit

await client.submitBallot(envelope.txJson)
// or combined:
await client.castBallot({ ... })
Submit methods POST the txJson to the configured API endpoint. castX convenience methods combine build + submit in one call.

Shared concepts

Identity commitment

Every client delegates identity commitment construction to identityClient.createIdentityCommitment. The resulting commitment is a deterministic hash:
H(namespace : provider : source [:scope])
Where source is the provider-specific identifier (personId for Didit, walletAddress for wallet, subjectId for Identus).

Identity proof hash

A separate proofHash binds the commitment to a specific verification workflow:
H("proof" : provider : source : workflowId : issuerDid : scope : audience : nonce)
Both values are constructed client-side from the identity block of the shyconfig and the caller’s input — no network call required.

Write-only posture

When resolveEffectivePosture determines that write-only mode is active, the receipt store is suppressed: match_store is treated as "none" and user_access as "never". Build methods still produce valid transaction envelopes; submit still works. The participant submits anonymously with no local state retained after the transaction confirms. Web is structurally write-only for high-assurance deployments. This is not merely because browsers lack a Play Integrity or App Attest equivalent — it is because web cannot provide a trusted hostile-environment negative. In deployments that set write_only_on_hostile_network: true, the runtime must supply a verified signal that the network is not hostile (no VPN, client IP not in the high_risk_region_blocklist). A browser has no trusted mechanism to produce this signal; any check at the browser layer is trivially spoofable by the adversary whose presence the check is meant to detect. Native mobile — iOS App Attest + OS-level VPN detection, or Android Play Integrity + ConnectivityManager — is the only client surface that can provide both the device-integrity signal and the network-hostility negative required to authorize recoverable posture.

Client modules

ModuleContract versionMain export
votingClient.jsshyvoting-v1createVotingClient, initializeFromShyConfig
sharesClient.jsshyshares-v1createSharesClient, initializeFromShyConfig
custodyClient.jsshycustody-v1createCustodyClient, initializeFromShyConfig
contractsClient.jsshycontracts-v1createFinancingClient, initializeFromShyConfig
wireClient.jsshywire-v1createWireClient, initializeFromShyConfig
identityClient.jsallcreateIdentityResolver
zkpClient.jsshyvoting-v1 (ZK tier)initZKProver, generateProof