Meshkit logoMeshkit

Examples

Real-world applications and projects built with the Meshkit SDK.

For a minimal two-peer walkthrough — Alice encrypts a file, publishes the ciphertext, and Bob decrypts it after fetching the CID — see Encryption.

Each entry below is a working implementation of Meshkit in a real application. Jump to a specific example using the table of contents on the right.

ExampleStackFeatures used
Invoice-ProReact · Ionic · Capacitor (Android / iOS)createMeshkitClient, upload, pin, retrieve, healthCheck
SocialCalc-SugarizerSugarizer · RequireJS · Electron / Webinit, upload, pin, publishName, resolveName, retrieve, generateKey, listKeys
Aspiring AppsIonic portal · Python apps-service · Node meshkit-serviceinit, upload, pin, retrieve

Invoice-Pro

Repository: github.com/anurag-p6/invoice-mvp-android-101 — branch meshkit-vps

Description: An offline-first mobile invoicing app for Android and iOS. Users create and manage professional invoices on-device without requiring any cloud account. Meshkit connects the app to a self-hosted Kubo node — running on a personal VPS, a cloud server, or a local machine — so invoices can be backed up as PDFs to your own IPFS node and pinned there permanently.

Tech stack: React 19 · Ionic 8 · Capacitor 8 · SQLite (@capacitor-community/sqlite) · SocialCalc spreadsheet engine · Vite 7

SDK features used

APIHow it's used
createMeshkitClient({ apiUrl })Creates an HTTP RPC client pointed at the user's Kubo node URL (e.g. http://your-vps:5001). The client is lazily instantiated and cached; the cache is busted whenever the user saves a new node URL in Settings.
client.upload(Uint8Array)The active invoice is rendered to a PDF Blob via html2canvas + jsPDF, converted to Uint8Array, and uploaded to the Kubo node. Returns a CID shown to the user as a short toast.
client.pin(cid)Called immediately after every successful upload to pin the PDF on the node so it is not garbage-collected.
client.retrieve(cid)Exported and available for restoring a backed-up invoice by CID.
client.healthCheck()Runs a connectivity check when the user taps "Test" in Settings, showing a green or red status indicator.

Architecture

All SDK calls are isolated in a single service module (src/services/meshkitService.ts). UI components only import named wrapper functions — the meshkit dependency is never touched directly outside the service.

@ipfs-meshkit/meshkit
        │
        ▼
src/services/meshkitService.ts     ← single integration point
        │
        ├── InvoicePage/Menu.tsx   uploadBlobToIPFS()  →  "Backup to IPFS" action sheet item
        └── SettingsPage.tsx       setKuboUrl() + checkConnection()  →  IPFS Backup settings panel

Node URL configuration

The Kubo node URL is set by the user at runtime in Settings → IPFS Backup:

  • Input field accepts any URL — http://127.0.0.1:5001 for a local daemon, http://your-vps-ip:5001 for a self-hosted VPS, or an HTTPS address for a cloud-hosted node.
  • Saved to localStorage["meshkit_kubo_url"]; defaults to http://127.0.0.1:5001 if unset.
  • The IPFS gateway URL for the backed-up PDF is derived automatically by swapping port 5001 → 8080 (getGatewayUrl), following the standard Kubo convention.

Key implementation details

  • PDF backup, not raw data: The app uploads the rendered invoice as a PDF blob — not raw JSON. The invoice is first rendered to HTML by SocialCalc, then converted to a PDF Blob, then uploaded as Uint8Array.
  • Browser compatibility: @ipfs-meshkit/meshkit ships Node.js-only internals (child_process, fs/promises, path) that are never invoked at browser/Capacitor runtime. vite.config.ts aliases them to lightweight stubs so the bundle resolves cleanly.
  • Android cleartext HTTP: network_security_config.xml whitelists cleartext HTTP for 127.0.0.1, localhost, and entire 192.168.x.x / 10.x.x.x subnets, so the app can reach a LAN or local Kubo node without requiring TLS.
  • Upload + pin as one operation: uploadToIPFS() always calls pin() immediately after upload() — a single wrapper ensures content is never uploaded without being pinned.

SocialCalc-Sugarizer

Repository: github.com/AspiringDevelopers/socialcalc-sugarizer

Description: A collaborative spreadsheet activity inside Sugarizer — an open-source learning platform for children. The integration enables serverless peer-to-peer spreadsheet sharing: a teacher or student publishes a spreadsheet to their local Kubo node and shares a stable IPNS link. Anyone with that link can open the latest version of the sheet directly in their Sugarizer instance, with no Sugarizer server involved. IPNS ensures the link stays valid across edits — each "Publish / Update" action pushes a new CID behind the same IPNS name.

Tech stack: Sugarizer 2.0 · Vue 3 · Electron · RequireJS (AMD) · SocialCalc spreadsheet engine · Vendored Meshkit browser AMD module

SDK features used

APIHow it's used
Meshkit.init({ nodes })Initialises the singleton with all configured node URLs. Health-checks every node concurrently at startup and keeps only reachable ones. Called lazily on first use via getMeshkit().
upload(Uint8Array)Uploads the full SocialCalc save format (plain-text, UTF-8 encoded) to the Kubo node. Returns a CID.
pin(cid)Pins the CID immediately after every upload to prevent garbage collection.
publishName(cid, { key, ttl: "1m" })Publishes the new CID to IPNS under the sheet's ed25519 key. TTL is set to 1 minute (IPNS_TTL_FAST) for fast propagation across the network.
resolveName(name)Resolves an IPNS name to its latest CID (/api/v0/name/resolve). Called with nocache: true on explicit "Fetch latest" to bypass local DHT cache.
resolveAndRetrieve(name)Convenience combo used in the fetch flow: resolves the IPNS name, extracts the CID, and retrieves the bytes in one call. Falls back to the HTTP gateway if the RPC API is unreachable.
retrieve(cid)Fetches spreadsheet bytes by CID and decodes them back to the SocialCalc plain-text format.
generateKey(label)Creates a per-spreadsheet ed25519 IPNS key (socialcalc-<sheetId>). Called once on first publish.
listKeys()Fallback if generateKey() fails because the key already exists — finds and reuses the existing key by label.

IPNS persistence flow

PUBLISH (user clicks "Publish / Update"):
  SocialCalc.CreateSpreadsheetSave()
    → TextEncoder → Uint8Array
    → upload(bytes)   → CID
    → pin(cid)
    → publishName(cid, { key: "socialcalc-<id>", ttl: "1m" })
    → stable IPNS link:  /ipns/<k51...>   (same link on every update)

FETCH (user opens shared link or clicks "Fetch latest"):
  parseShareTarget(input)   ← accepts ?ipns=, /ipns/, ipns://, ?cid=, bare CID/key
    → resolveAndRetrieve(name, { nocache: true })
        → /api/v0/name/resolve  →  CID
        → /api/v0/cat           →  bytes
    → [fallback] GET http://127.0.0.1:8080/ipns/<name>
    → TextDecoder → SocialCalc format → loadSpreadsheet()

Node URL configuration

Node URLs are read from localStorage at runtime — no build config or env vars:

KeyPurposeDefault
socialcalc_meshkit_nodesJSON array of Kubo API URLs["http://127.0.0.1:5001"]
socialcalc_meshkit_gatewayHTTP gateway URL for fallback fetcheshttp://127.0.0.1:8080

Multi-node is supported: pass multiple URLs in the JSON array. Write operations (upload, pin, publish) always use the primary node; read operations (retrieve, resolve) use failover across all healthy nodes.

Sugar journal integration

After every publish or fetch, IPFS metadata is written to the Sugar datastore so the share state persists across sessions:

Journal keyValue stored
ipfs_ipnsThe IPNS name (k51…)
ipfs_ipns_keyThe local key label (socialcalc-<id>)
ipfs_cidThe latest content CID
ipfs_gatewayThe full gateway URL

On activity resume, the stored key and IPNS name are restored from journal metadata and reused — no new key is generated for an existing sheet.

Key implementation details

  • Vendored AMD SDK: The Meshkit SDK is not installed via npm. It is shipped as a self-contained RequireJS AMD module at lib/meshkit/meshkit.js — a browser port of @ipfs-meshkit/core with no Node.js dependencies and no build step required.
  • URL-based auto-load: If the activity is launched with ?ipns=<name> or ?cid=<hash> in the URL, it automatically fetches and loads the shared spreadsheet on startup, before falling back to the Sugar journal.
  • Share link formats: parseShareTarget() accepts all common IPFS/IPNS link formats — ?ipns=, /ipns/, ipns://, ?cid=, /ipfs/, ipfs://, bare CID (Qm…, baf…), and bare IPNS key (k51…, 12D3…).
  • Graceful gateway fallback: If the local Kubo RPC API is unreachable during a fetch, the app retries automatically via the HTTP gateway (http://127.0.0.1:8080/ipns/<name>), so read access works even when the API port is firewalled.

Aspiring Apps

Pull request: its-me-ani/aspiring-apps #1 — Meshkit IPFS app service

Description: Agentic invoice applications in Aspiring Apps. Users pick a storage backend in Settings. With IPFS selected, invoice workbook bodies are uploaded to a Kubo node and fetched back by CID. The default node is Aspiring Apps' Kubo on Render (https://kubo-render.onrender.com). A user can point the same setting at their own Kubo RPC URL.

Tech stack: Ionic portal (React) · Python apps-service · Node meshkit-service (@ipfs-meshkit/meshkit ^1.2.1) · Kubo

SDK features used

APIHow it's used
init({ nodes })meshkit-service connects to the local Kubo URL (MESHKIT_NODES_LOCAL, default http://localhost:5001) and the server URL (MESHKIT_NODES_SERVER, default https://kubo-render.onrender.com).
upload + pinuploadAndPin uploads the invoice JSON (or a file) and pins the CID on that Kubo target.
retrieveLoads the workbook bytes back by CID. JSON responses are decoded in the service; file bytes are returned as an octet stream.

The portal and the Python service do not import the SDK. They call meshkit-service over HTTP (MESHKIT_SERVICE_URL, default http://127.0.0.1:4000).

Storage choice

Settings → Storage offers two backends:

BackendWhat happens to the invoice body
Aspiring Storage (s3)Stored in S3 as before.
IPFS (ipfs)JSON is sent to meshkit-service, which uploads and pins it on Kubo. The apps-service record keeps the CID.

The Kubo URL field accepts any http(s) RPC address. Leaving the default uses the Render node.

Request path

Settings (storageBackend: "ipfs", Kubo URL)
        │
        ▼
apps-service  storage_manager.py
        │  MeshkitClient.upload_json / retrieve_json
        ▼
meshkit-service  (Node, @ipfs-meshkit/meshkit)
        │  init({ nodes }) → upload → pin → retrieve
        ▼
Kubo  (local :5001  or  https://kubo-render.onrender.com)

meshkit-service exposes POST /ipfs/upload, POST /ipfs/retrieve, and POST /ipfs/pin, plus the invoice aliases POST /putJSON and GET /getJSON/:cid. Each call carries a target of local or server.

Agent uploads

An agent using IPFS Meshkit MCP can upload the workbook to the user's own Kubo node and record the CID with ipfsNodeUrl. On read, storage_manager fetches that CID from the recorded node (POST /api/v0/cat) instead of the shared Render node. Deleting the app record does not unpin the IPFS object.

On this page