npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

datadid-sdk-ts

v1.0.7

Published

TypeScript SDK for the DataDID developer platform — Data API and DID API clients

Downloads

675

Readme

Getting Started with datadid-sdk-ts

DataDID is a developer platform that combines decentralized identity (DID) with user authentication and action records. The SDK provides two clients:

  • DataClient — authentication, user info, and action records (data-api.memolabs.net)
  • DIDClient — DID creation/deletion and file operations (prodidapi.memolabs.org)

Installation

npm install datadid-sdk-ts

Requirements: Node.js 18+ (uses native fetch)


Quick Start

import { DataClient } from "datadid-sdk-ts";

async function main() {
  const client = DataClient.production();

  // Log in — the client stores the access token automatically
  const tokens = await client.loginWithEmailPassword("[email protected]", "yourpassword");

  // Fetch your profile
  const me = await client.getMe();
  console.log(me.uid, me.role);
}

main();

Servers

| Client | Purpose | Production URL | Test URL | |---|---|---|---| | DataClient | Auth, user info, action records | https://data-api.memolabs.net | https://testdata-api.memolabs.net | | DIDClient | DID creation, file operations | https://prodidapi.memolabs.org | https://testdidapi.memolabs.org |


Part 1 — DataClient

Create a client

import { DataClient } from "datadid-sdk-ts";

const client = DataClient.production();
// or: const client = DataClient.testnet();
// or: const client = new DataClient({ baseURL: "https://data-api.memolabs.net" });

Login with email (verification code)

// Step 1: send a code to the user's inbox
await client.sendEmailCode("[email protected]");

// Step 2: log in with the code
const tokens = await client.loginWithEmail(
  "[email protected]",
  "123456",  // code from inbox
  "Web"      // source: a string identifying your app — e.g. "Web", "App", "Mobile"
);

console.log(tokens.accessToken);
console.log(tokens.refreshToken);

After a successful login the client stores the access token automatically. All subsequent calls that need authentication will use it.


Register a new account

await client.sendEmailCode("[email protected]");

const tokens = await client.registerWithEmail(
  "[email protected]",
  "123456",     // code from inbox
  "mypassword", // choose a password
  "Web"
);

Login with email + password

const tokens = await client.loginWithEmailPassword(
  "[email protected]",
  "mypassword"
);

Reset password

await client.sendEmailCode("[email protected]");

await client.resetPassword(
  "[email protected]",
  "123456",      // code from inbox
  "newpassword"
);

Login with Telegram

const tokens = await client.loginWithTelegram(
  telegramInitData, // string from Telegram WebApp.initData
  "App"
);

Login with Pi Browser

const tokens = await client.loginWithPi(
  piAccessToken, // access token from Pi Browser SDK
  "App"
);

Login with EVM wallet (MetaMask, etc.)

// Step 1: request a challenge message from the server
// origin is required — use your app's own domain
const message = await client.getEvmChallenge(
  "0xYourWalletAddress",
  985,                    // chain ID (optional, defaults to 985)
  "https://myapp.com"    // origin — required for loginWithEvm to succeed
);

// Step 2: sign the message with the user's wallet
// (using ethers.js, wagmi, viem, or any signing library)
const signature = await signer.signMessage(message);

// Step 3: submit the signature to log in
const result = await client.loginWithEvm(message, signature, "Web");

console.log(result.accessToken);
console.log(result.did);    // the user's DID string (e.g. "did:memo:...")
console.log(result.number); // the user's numeric platform ID

Refresh an access token

const newAccessToken = await client.refreshToken(tokens.refreshToken);

Get current user info

// Basic info (uid, email, username, role)
const me = await client.getMe();
console.log(me.uid, me.role);

// Full profile (avatar, DID, linked social accounts, etc.)
const info = await client.getUserInfo();
console.log(info.name);
console.log(info.address); // numeric platform ID (e.g. "2018955010523533312")
console.log(info.did);
console.log(info.email);
console.log(info.telegram_info);  // if linked
console.log(info.twitter_info);   // if linked
console.log(info.discord_info);   // if linked
console.log(info.pi_info);        // if linked

Action records

Action records are the platform's points/achievement system. Each action has a numeric ID. When a user completes an action, a record is stored with the points earned and a Unix timestamp.

// Check if the user has completed action #61
const record = await client.getActionRecord(61);
if (record) {
  console.log(`Completed at ${record.time}, earned ${record.points} points`);
} else {
  console.log("Not completed yet");
}

// Mark action #61 as completed
await client.addActionRecord(61);

// With extra options (some actions require additional data)
await client.addActionRecord(61, { someOption: "value" });

AliveCheck action IDs (AliveCheck is the platform's liveness/subscription service):

  • 5 — first-time AliveCheck subscription
  • 6 — AliveCheck renewal

Error handling

import { DataDIDApiError } from "datadid-sdk-ts";

try {
  await client.loginWithEmailPassword("[email protected]", "wrongpassword");
} catch (err) {
  if (err instanceof DataDIDApiError) {
    console.error(err.message);      // human-readable message
    console.error(err.statusCode);   // HTTP status code (e.g. 401, 500)
    console.error(err.responseBody); // raw JSON from the server
  }
}

Manual token management

By default, login methods store the access token on the client automatically. You can disable this:

const client = new DataClient({
  baseURL: "https://data-api.memolabs.net",
  disableAutoToken: true,
});

const tokens = await client.loginWithEmail("[email protected]", "123456", "Web");

// Token was NOT stored automatically — set it yourself:
client.setAccessToken(tokens.accessToken);

// Read the current token at any time:
const token = client.getAccessToken();

Part 2 — DIDClient

DID operations use a sign-then-submit pattern. You never send your private key to the server — you only sign a message locally, and the server pays the gas fee and submits the transaction on your behalf.

The pattern for every write operation:

  1. Ask the server for a message to sign
  2. Sign that message with your wallet (free, off-chain)
  3. Submit the signature — the server does the rest

Create a client

import { DIDClient } from "datadid-sdk-ts";

const didClient = DIDClient.production();
// or: const didClient = DIDClient.testnet();

Create a DID

const address = "0xYourWalletAddress";

// Step 1: get the message to sign
const message = await didClient.getCreateMessage(address);

// Step 2: sign it with your wallet (ethers.js example)
// The message is a hex-encoded byte string — sign the bytes, not the hex string
const signature = await wallet.signMessage(ethers.getBytes(message));

// Step 3: submit — server creates the DID on-chain
const newDID = await didClient.createDID(signature, address);

console.log(newDID); // "did:memo:abc123..."

Check if a DID exists

const result = await didClient.getDIDExists("0xYourWalletAddress");
console.log(result);

Get DID info

const info = await didClient.getDIDInfo("0xYourWalletAddress");
console.log(info.did);    // the DID string (e.g. "did:memo:...")
console.log(info.number); // the numeric platform ID

Delete a DID

const myDID = "did:memo:abc123...";

// Step 1: get the message to sign
const message = await didClient.getDeleteMessage(myDID);

// Step 2: sign it
// The message is a hex-encoded byte string — sign the bytes, not the hex string
const signature = await wallet.signMessage(ethers.getBytes(message));

// Step 3: submit
const result = await didClient.deleteDID(signature, myDID);
console.log(result.status);

Upload a file

Files are stored directly by wallet address. For files that need their own on-chain DID, see mfile operations below.

await didClient.uploadFile(fileData, "0xYourWalletAddress");

List files

const files = await didClient.listFiles("0xYourWalletAddress");

Download a file

const file = await didClient.downloadFile("0xYourWalletAddress");

Upload an mfile (file with an on-chain DID)

An mfile is a file that gets its own DID minted on-chain, making it permanently addressable and verifiable on the Memo network. This uses the sign-then-submit pattern.

// Step 1: create the upload request — returns a message to sign
const message = await didClient.createMfileUpload(fileData, "0xYourWalletAddress");

// Step 2: sign it
const signature = await wallet.signMessage(message);

// Step 3: confirm the upload
const result = await didClient.confirmMfileUpload(signature, "0xYourWalletAddress");

Download an mfile

const file = await didClient.downloadMfile(
  "did:mfile:bafkrei...", // the mfile DID
  "0xYourWalletAddress"
);

API Reference

DataClient

| Method | Description | |---|---| | DataClient.production() | Client for production | | DataClient.testnet() | Client for test server | | setAccessToken(token) | Manually set the auth token | | getAccessToken() | Read the current token | | sendEmailCode(email) | Send verification code to email | | loginWithEmail(email, code, source) | Login with email + code | | registerWithEmail(email, code, password, source) | Register new account | | loginWithEmailPassword(email, password) | Login with email + password | | resetPassword(email, code, newPassword) | Reset password | | loginWithTelegram(initdata, source) | Login with Telegram | | loginWithPi(piAccessToken, source) | Login with Pi Browser | | getEvmChallenge(address, chainId?) | Get EVM sign-in challenge | | loginWithEvm(message, signature, source) | Login with EVM wallet signature | | refreshToken(refreshToken) | Get a new access token | | getMe() | Basic user info (uid, email, role) | | getUserInfo() | Full user profile | | getActionRecord(actionId) | Get action completion record (or null) | | addActionRecord(actionId, opts?) | Record an action completion |

DIDClient

| Method | Description | |---|---| | DIDClient.production() | Client for production (prodidapi.memolabs.org) | | DIDClient.testnet() | Client for test server (testdidapi.memolabs.org) | | getCreateMessage(address) | Get message to sign before creating a DID | | createDID(sig, address) | Create a DID (submit signature) | | createDIDAdmin(address) | Admin: create DID without signature | | createTonDID(address) | Create a Ton-network DID | | getDIDExists(address) | Check if a DID exists | | getDIDInfo(address) | Get DID info and chain balances | | getDeleteMessage(did) | Get message to sign before deleting a DID | | deleteDID(sig, did) | Delete a DID (submit signature) | | uploadFile(data, address) | Upload a file | | listFiles(address) | List files for an address | | downloadFile(address) | Download a file | | createMfileUpload(data, address) | Start an mfile upload (returns message to sign) | | confirmMfileUpload(sig, address) | Confirm mfile upload (submit signature) | | downloadMfile(mdid, address) | Download a file by its mfile DID |

Error class

| Property | Type | Description | |---|---|---| | message | string | Human-readable error message | | statusCode | number | HTTP status code | | responseBody | any | Raw JSON response from server |


Links