Skip to content

Quickstart

Terminal window
npm install @calimero-network/mero-js

The package ships ESM, CommonJS and a browser build with its own TypeScript declarations. Its one dependency, @phala/dcap-qvl, verifies TDX quotes and is loaded only when the client first meets a real one.

A client talks to one node of a cluster at a time, and fails over to the next when that node stays unavailable. Its policy says which nodes it trusts; nothing is sent to a node until its attestation passes.

import { CalimeroClient, browserPasskey } from '@calimero-network/mero-js';
// A Calimero Cloud cluster by name; its nodes come from the node directory.
const client = await CalimeroClient.connect({
cluster: 'eu-shared-1',
// Trust a node that runs a signed mero-tee release, this one or newer.
policy: { release: { minReleaseVersion: '2.3.109' } },
});

The directory only chooses which nodes to try: each one is still attested under your policy, so a wrong list can only make connecting fail. For a fixed list of nodes, or a cluster you run yourself, give them directly: new CalimeroClient({ baseUrl, nodes, policy }).

For a local development cluster (merod local, or merod run --dev), whose nodes send mock quotes, allow them explicitly:

const dev = new CalimeroClient({ baseUrl: 'http://127.0.0.1:2501', policy: { allowMock: true } });

A person’s account is their passkey. signUp creates both and signs in; signIn uses an existing passkey on any node of the cluster.

const session = await client.signUp(browserPasskey(), 'alice');
// later, or on another device that holds the passkey:
await client.signIn(browserPasskey());

The node’s --rp-id and --origins decide which pages may run a passkey ceremony: localhost and http://localhost:3000 by default.

An app instance runs a signed package release, on its own replicated log.

await client.installPackage('com.calimero.kv-store', '1.0.0'); // from the cluster's registry
const app = await client.createApp('notes', { package: 'com.calimero.kv-store', version: '1.0.0' });
await client.call(app, 'set', { key: 'a', value: '1' });
const { result } = await client.view(app, 'get', { key: 'a' }); // '1'
for await (const event of client.events(app)) {
console.log(event.kind, event.data);
}

call carries an idempotency key, so the client can send it again while the node is unavailable without running it twice. See Apps and packages.