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

@thingd/client

v0.91.1

Published

Zero-dependency HTTP client for thingd — works in browsers, edge runtimes, Node.js, Bun, Deno

Downloads

3,274

Readme

@thingd/client

Zero-dependency HTTP client for thingd — works in browsers, Cloudflare Workers, AWS Lambda, Bun, Deno, and Node.js 18+.

For mobile and web application backends, use createThingdAppClient rather than the raw ThingdClient shown below. The raw client is for operator/runtime access to a Thingd REST endpoint; it must not receive a Cloud CLI token, secret project API key, or engine runtime token in an Expo or browser bundle.

import { ThingdClient } from "@thingd/client";

const client = new ThingdClient({
  url: "https://api.thingd.cloud",
  authToken: "md_pk_...",
});

await client.put("notes", { id: "1", text: "Hello world" });
const note = await client.get("notes", "1");

Why this package?

@thingd/client is a pure fetch-based client with zero runtime dependencies (~5KB). Use it when you need to call the thingd REST API from environments where Node.js packages aren't available or desirable.

Install

npm install @thingd/client

Usage

Connect to any thingd instance — local sidecar, Docker, or thingd.cloud. A local runtime token and a Cloud project API key are both sent as Bearer credentials, but they are issued and managed by different systems:

const client = new ThingdClient({
  url: "http://localhost:8757",             // local sidecar
  // url: "https://api.thingd.cloud",       // thingd.cloud
  authToken: "your-api-key",
});

Mobile and web app backends

Use the app client for a project-user backend. It works with browsers, React Native/Expo, Node.js, and other runtimes with fetch:

import { createThingdAppClient } from "@thingd/client";

const app = createThingdAppClient({
  baseUrl: "https://api.thingd.cloud",
  publishableKey: "pk_...",
  expectedIdentity: { projectId: "...", appId: "...", instanceId: "..." },
});

await app.auth.signUp({ email, password, name });
const profile = await app.actions.invoke("createProfile", { timezone: "UTC" }, {
  idempotencyKey: "profile:create:user-1",
});
const sessions = await app.objects.list("workout_sessions", { limit: 100 });

The publishable key is safe for app bundles. Do not use a secret Cloud API key or engine runtime token in a browser or mobile application. See the public app backend contract and Nice Rep mobile setup.

actions is the canonical app API. functions remains available as a deprecated compatibility alias for existing clients; both APIs invoke the same published action routes.

app.objects.list(collection, { limit, offset }) performs an exact, paginated collection read through the published app policy. Ownership and readable-field projection are enforced by the hosted service. Use app.search(query, options) for full-text retrieval, not as a substitute for listing history or records.

expectedIdentity is optional. When set, app.manifest() checks the returned project, app, and instance IDs before the app proceeds. app.actions.getUsage(name) returns the authenticated user's configured lifetime limit, successful uses, and remaining uses; it does not reserve quota for a later invocation.

Failures are ThingdAppError values with status, stable code, safe message, optional requestId, and optional sanitized details. The client reads request IDs from the response body or X-Request-Id and accepts the legacy string-valued error envelope during Cloud rollout.

Objects

await client.put("users", { id: "user-1", name: "Alice" });
const user = await client.get("users", "user-1");
const deleted = await client.delete("users", "user-1");
const users = await client.listObjects("users", {
  filter: { role: "admin" },
  sortBy: { field: "created_at", direction: "desc" },
  limit: 10,
});

Search

const results = await client.search("alice", {
  collections: ["users", "notes"],
  limit: 5,
});

Events

await client.events.append("audit", {
  type: "user.login",
  text: "Alice logged in",
});
const events = await client.events.list("audit", { limit: 10 });

Queues

await client.queue("email").push(
  { to: "[email protected]" },
  { idempotencyKey: "email:user-1", maxAttempts: 3 }
);

const job = await client.queue("email").claim({ leaseMs: 30_000 });
if (job) {
  await client.queue("email").ack(job.id);
}

Links

await client.links.create("users/alice", "authored", "notes/1");
const neighbors = await client.links.neighbors("users/alice", "Outgoing");

Aggregation

const count = await client.aggregate.count("sales", {
  groupBy: "region",
});
const revenue = await client.aggregate.sum("sales", "amount");

NLQ (Natural Language Query)

const result = await client.nlq.query("What were total sales by region?");

API

| Method | Description | |--------|-------------| | put(collection, object) | Create or replace an object | | get(collection, id) | Get an object by ID | | delete(collection, id) | Delete an object | | listObjects(collection, opts) | List/filter/sort objects | | search(query, opts) | Full-text search | | events.append(stream, event) | Append an event | | events.list(stream?, opts) | List events | | queue(name).push(payload, opts) | Push a queue job | | queue(name).claim(opts) | Claim a job | | queue(name).ack(jobId) | Acknowledge a job | | queue(name).nack(jobId, opts) | Nack a job | | links.create(from, type, to) | Create a graph link | | links.neighbors(ref, dir) | Get linked references | | aggregate.count/sum/avg/min/max | Aggregation queries | | timeseries(collection, opts) | Time-bucketed aggregation | | schema(collection?) | Reflect collection schema | | nlq.query(question) | Natural language query | | listCollections() | List all collections | | listStreams() | List all event streams | | listQueues() | List all queues | | close() | Clean up |

thingd.cloud

Connect to thingd Cloud using a project-scoped API key:

const client = new ThingdClient({
  url: "https://api.thingd.cloud",
  authToken: "md_pk_...",
});

License

Apache-2.0