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

@jsm-mit/chat-motoko-package

v0.8.0

Published

Wrapper TypeScript package for the chat-motoko canister: projects, multi-party chats, messages and a poller for agent hosts.

Downloads

45

Readme

@jsm-mit/chat-motoko-package

TypeScript wrapper for the chat-motoko canister — a generic, multi-project, multi-party chat on the Internet Computer — plus the integration tests that prove it.

import { RoomsActor, ChatsActor, MessagesActor, ChatPoller } from "@jsm-mit/chat-motoko-package";

// A canister admin creates the project with its accounts canister — the one asked
// `isUser(principal)` before a non-admin opens a chat (Sultana: sultana-core-motoko).
// A project admin defines a room: who receives the customer's messages.
// One room per thing the app wants a conversation about (Sultana: per salon), closed to
// the people who may open it — an empty allowedCustomers means everybody with an account.
await new RoomsActor(canisterId, adminIdentity).createRoomAsyncUnsafe({
    projectId: "sultana-stage", id: `salon-${salonId}`, name: "Asystent salonu",
    recipients: [{ principal: villagePrincipal, role: "agent", displayName: "Asystentka Ola" }],
    allowedCustomers: [ownerPrincipal],
});

// The customer opens the room; the same call returns the same chat next time.
const chat = await new ChatsActor(canisterId, identity).openChatAsyncUnsafe({ projectId: "sultana-stage", roomId: `salon-${salonId}`, customerName: "Michał" });

const messages = new MessagesActor(canisterId, identity);
await messages.postAsyncUnsafe({ chatId: chat.id, text: "dodaj usługę strzyżenie" });

// The page carries the thread AND what the others are doing: `presence[].typing` while
// somebody is writing (a room's recipients report it with setTypingAsyncUnsafe, and their
// own post clears it), `presence[].lastReadSeq` for "read up to here".
const page = await messages.getMessagesAsyncUnsafe({ chatId: chat.id, sinceSeq: 0 });

// A host that sends receipts and typing as a courtesy skips the proof: the call is taken
// in by the IC, the certified reply is never verified (that check is the expensive part
// on a small CPU), and a refusal goes unnoticed.
await messages.markReadUnverifiedAsyncUnsafe(chat.id, page.lastSeq);
await messages.setTypingUnverifiedAsyncUnsafe(chat.id);

// Every actor takes `{ blsVerify }` as a third argument: a faster check of the certified
// replies than agent-js's pure-JS one, for a host that makes many update calls.
const fast = new MessagesActor(canisterId, identity, { blsVerify: myVerifier });

// An agent host: every new message in every chat this identity is a recipient of, with
// the room and the customer on each message — route by (projectId, roomId).
const poller = new ChatPoller(messages, 1000, { onError: console.error });
poller.messages$.subscribe((m) => console.log(m.roomId, m.customer, m.kind, m.text));
poller.run();

One class per canister controller (AdminActor, ProjectsActor, RoomsActor, ChatsActor, MessagesActor), every method …AsyncUnsafe (throws one of CanisterError, CriticalCanisterError, CallRefusedAtInspectionStage) or …AsyncSafe (never throws). Views translate Principal → text, opt → optional, variants → string unions; sequence numbers are plain numbers, timestamps bigint nanoseconds.

Deleting: RoomsActor.deleteRoomAsyncUnsafe (project admins) takes a room with every chat and message in it; ProjectsActor.deleteProjectAsyncUnsafe (canister admins only) takes a project with all its rooms. The canister deletes in bounded calls (500 chats or 50 000 messages each), and these methods repeat the call until it is done — pass onStep to see the progress, or call deleteRoomStepAsyncUnsafe / deleteProjectStepAsyncUnsafe for one call at a time.

src/ is browser-safe — the same package serves the agent host and a web panel.

Scripts: build, typecheck, sync-declarations, test-suite, test-access-restrictions, test-smoke, user1 / user2 (an interactive admin/chat console, one person per terminal: the key comes from USER1_PEM / USER2_PEM in .env; another canister: npm run user2 -- <canister-id>), redeploy. See CLAUDE.md for who runs what.

Integration tests and redeploys

The tests always run on the crafting-table slot short-living, the short-lived test canister the wrapper packages share. npm run test-suite (or test-access-restrictions, or test-smoke — the quick check publishing runs) reinstalls the current ../chat-motoko build into short-living with a 3-minute lease (npm run craft:deploy -- short-living --lease 3 there), then runs the suite with CANISTER_ID set to short-living's id from ~/motoko-crafting-table/canister_ids.json. No prompt. The crafting table refuses while another deploy's lease on short-living is active; npm run test-suite -- --force takes it anyway. No .env: every identity is generated per run; setup claims the admin role on the fresh canister.

npm run redeploy -- [slot] [reinstall|upgrade] [--force]

deploys the current ../chat-motoko build for sandbox play, without tests and without .env: craft:deploy (reinstall) or craft:upgrade in ../chat-motoko. The slot defaults to backend6; the mode to upgrade where the slot allows it and to reinstall on short-living. After a reinstall claim the admin role yourself in the sandbox — the script prints the command.

Publishing

Bump the version in package.json by hand, then:

npm run publish-public

scripts/publish-public.sh refuses unless this repo is on master equal to origin/master with nothing uncommitted but the bump, the version is not on the registry yet, and ../chat-motoko is on master, clean and equal to its origin/master. It then reinstalls that master into short-living (craft:deploy -- short-living --lease 2), reads the live interface (dfx canister metadata <short-living> candid:service --ic --identity anonymous) and refuses if it differs from the committed declarations/chat-motoko-backend/chat-motoko-backend.did (trailing whitespace and newlines aside) — sync the declarations, commit, push, publish again. On the same deploy it runs the smoke test (tests/test-smoke.ts: setup, one write and one read per domain) and refuses if it fails. Next scripts/stamp-canister-commit.sh repeats the canister-repo checks, rebuilds the canister, regenerates the declarations and refuses if that changes what is committed here. Only then it writes chatMotoko.{repo, repoUrl, commit} into package.json — the canister commit this version was generated from — publishes, and commits and pushes Version bump to <version> (when there is nothing to commit, it stops there without an error). A failed publish takes the stamp back out.