Official TypeScript SDK for the Sigil deep-link protocol. Build envelopes, launch requests, and handle results — either as a simple await or via manual URI construction. See the Payload format page.
github.com/sigil-oss/sigil.connect — TypeScript types, changelog, and full API reference.
npm install @sigil-oss/connectbuildSigilUrl wraps the request in an envelope, base64url-encodes it, and returns a sigil://v1/request?d=… URI ready to open.
import { buildSigilUrl, createEnvelope, createConnectRequest } from '@sigil-oss/connect';
const url = buildSigilUrl(
createEnvelope(
createConnectRequest({
type: 'connect',
dapp: { name: 'My App', origin: 'https://myapp.example' },
permissions: ['transfer', 'sign_message'],
}),
{ callback: 'https://myapp.example/api/sigil/callback' },
)
);
window.location.href = url;import { buildSigilUrl, createEnvelope, createTransferRequest } from '@sigil-oss/connect';
const url = buildSigilUrl(
createEnvelope(
createTransferRequest({
type: 'transfer',
dapp: { name: 'My App', origin: 'https://myapp.example' },
to: 'NQZBXKZP4MTLDUVWXYZK8MFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
amount: 1_500_000,
}),
{ callback: 'https://myapp.example/api/sigil/callback' },
)
);
window.location.href = url;Pass redirect_uri instead of (or alongside) callback. After the user acts, Sigil opens redirect_uri?result=<base64url JSON> in the default browser. Read the result client-side — no endpoint, no infra.
import { sigilRequest, createSignMessageRequest } from '@sigil-oss/connect';
// One await — no server, no redirect boilerplate.
// Sigil opens /__sigil__ after the user acts; handleRedirect() there
// broadcasts the result back and this Promise resolves.
const result = await sigilRequest(
createSignMessageRequest({
type: 'sign_message',
dapp: { name: 'My App', origin: 'https://myapp.example' },
message: 'Sign in to My App · ' + new Date().toISOString(),
}),
);
if (result.status === 'signed') {
console.log('identity:', result.identity);
}With redirect_uri, the signed result lands in the browser URL bar and history. Use callback for anything involving real money or sensitive data that must stay server-side.
Sigil POSTs a JSON body to your callback URL from the Rust layer. parseCallback validates the shape and narrows the type. Always verify the nonce before acting on the result.
import { parseCallback, type SigilResult } from '@sigil-oss/connect';
// POST /api/sigil/callback
app.post('/api/sigil/callback', express.json(), async (req, res) => {
const result: SigilResult = parseCallback(req.body);
// Always verify the nonce against what you sent
if (result.nonce !== pendingNonces.get(result.nonce)) {
return res.status(400).json({ error: 'nonce_mismatch' });
}
if (result.status === 'connected') {
console.log('Paired identity:', result.identity);
console.log('Granted permissions:', result.permissions);
} else if (result.status === 'signed') {
console.log('Transaction hash:', result.tx_hash);
} else if (result.status === 'rejected') {
console.log('Rejected, reason:', result.reason);
}
res.sendStatus(200);
});sigilRequest() launches Sigil via a link click (the page stays alive), then returns a Promise that resolves when the user acts. Internally it uses BroadcastChannel — no server, no polling.
import { sigilRequest, createSignMessageRequest } from '@sigil-oss/connect';
// One await — no server, no redirect boilerplate
const result = await sigilRequest(
createSignMessageRequest({
type: 'sign_message',
dapp: { name: 'My App', origin: 'https://myapp.example' },
message: 'Sign in to My App · ' + new Date().toISOString(),
}),
// Sigil opens /__sigil__ after the user acts; handleRedirect() broadcasts
// the result back over a BroadcastChannel and this Promise resolves.
{ callbackPath: '/__sigil__' },
);
if (result.status === 'signed') {
console.log('identity:', result.identity);
console.log('signature:', result.signature);
}Mount this at the callbackPath route in your app (default /__sigil__). It reads the ?result= param, broadcasts it to the waiting sigilRequest() Promise, and closes the tab.
// Mount this at the callbackPath route in your app — e.g. pages/__sigil__.tsx
import { handleRedirect } from '@sigil-oss/connect';
// Call it on page load. It reads ?result=…, posts to the BroadcastChannel
// that sigilRequest() is listening on, then closes the tab.
handleRedirect();