Sharing
Share encrypted content with recipient identities.
Sharing gives another MeshKit identity a way to open encrypted content without sending plaintext. MeshKit does this with a share capsule: metadata that points at a CID and wraps the data key for one or more recipient identities.
Do not model MeshKit identities as email addresses by default. An identity is an application-level encryption identity. Your app decides how to bind it to users, devices, DIDs, passkeys, wallets, or an internal directory.
Share A File
import { meshkit } from "@meshkit/meshkit";
const mesh = await meshkit({ identity: "owner" });
await mesh.identity.create("alice");
const file = await mesh.files.put("roadmap.md", "# Roadmap");
const capsule = await mesh.share.file(file).with("alice", {
expiresIn: "7d",
allowDownload: true,
});
await mesh.share.send(capsule, "alice");
const opened = await mesh.share.openCapsule(capsule, { as: "alice" });
console.log(await opened.text());How Sharing Works
owner stores encrypted file
-> owner creates capsule for recipient public key
-> provider stores or queues capsule metadata
-> recipient opens capsule as their MeshKit identity
-> MeshKit checks expiry, revocation, policy, vault, and capabilities
-> MeshKit unwraps the data key and decrypts the contentSharing creates access to encrypted bytes that already exist. It does not copy plaintext into a mailbox.
API
await mesh.share.file(file).with(recipient, options);
await mesh.share.openCapsule(capsule, options);
await mesh.share.revoke(capsuleId);| Parameter | Type | Required | Description |
|---|---|---|---|
share.file(file).with(recipient, options) | MeshFile | string, string | string[], ShareOptions | File and recipient yes | Creates and stores a ShareCapsule for the target CID |
share.openCapsule(capsule, options) | ShareCapsule | string, OpenOptions | Yes | Checks expiry, revocation, policy, vault, and capability requirements before decrypting |
share.send(capsule, recipient) | ShareCapsule, string | Yes | Queues a capsule in the provider mailbox for a recipient |
share.revoke(capsuleId) | string | Yes | Marks the capsule revoked for future opens |
What To Persist
- Source content CID
- Capsule ID
- Recipient identity
- Expiry or policy ID
- Revocation state
- Vault or capability references, if used
Failure Modes
| Error or symptom | Meaning | Fix |
|---|---|---|
identity_not_found | Recipient key is not local and no directory resolved it | Create, import, publish, or resolve the identity first |
recipient_not_authorized or key_unwrap_failed | The opener does not have a valid wrapped key | Open as the intended identity or create a new capsule |
share_expired | Capsule expiry passed | Create a fresh capsule or extend access |
share_revoked | Capsule was revoked | Create a new share if access should resume |
policy_provider_required | Capsule depends on an external policy provider | Configure the same policy provider before opening |
capability_required | Capsule requires a capability token | Pass the token issued by the vault or capability owner |
Revocation Boundary
Revocation blocks future opens through MeshKit checks. It cannot erase plaintext that the recipient already decrypted, copied, cached, or exported. Design product UX and compliance language around that boundary.
Production Notes
- Use a real identity directory or app-owned contact model before sharing with production users.
- Persist capsule IDs and recipient state so you can audit, revoke, and retry.
- Do not log wrapped keys, capability tokens, policy secrets, or decrypted content.
- Validate the provider supports capsules and mailbox records if you use
share.send.
Next Steps
- Read the concept model: Identity and sharing.
- Send mailbox-style payloads with Messages.
- Add advanced access constraints with Security.