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

ecoku

v0.5.4

Published

A lightweight browser client for the Ecoku self-hosted comment system

Readme

Ecoku browser client

ecoku is the embeddable TypeScript browser client for the Ecoku self-hosted comment service. It owns one explicit container and renders the published plain-text, no-avatar, threaded comment surface.

Install

ecoku is available on npm. Install version 0.5.4:

npm install --save-exact [email protected]

SDK versions follow repository release tags. You can also use the SDK served by your Ecoku instance or build this package from source.

The SDK exposes the same default Ecoku constructor through ESM, CommonJS, and a browser UMD global:

// ESM
import Ecoku from 'ecoku'

// CommonJS
const Ecoku = require('ecoku')
<script src="https://ecoku.example.com/client/ecoku.umd.js"></script>
<script>
  const comments = new Ecoku({ /* explicit configuration */ })
</script>

The production Ecoku image also exposes /client/ecoku-loader.js. Static sites can use the loader with declarative data-ecoku-comments attributes instead of copying the UMD bundle into each site. See the repository static-site integration guide for the complete contract.

Mount a comment surface

import Ecoku from 'ecoku'

const comments = new Ecoku({
  container: '#comments',
  serverURL: 'https://ecoku.example.com/',
  siteId: 'docs',
  pageKey: 'guides/windows-11-iot-ltsc',
  pageTitle: 'Windows 11 IoT LTSC 养老指南',
  pageSize: 10,
  theme: 'auto', // auto | light | dark
  // i18n: 'en', // zh-CN | zh-Hant | en; omit to use the site's language
  // cssURL: 'https://ecoku.example.com/client/ecoku.unstyled.css',
})

await comments.init()

The caller must provide the canonical pageKey; pageTitle should be the human-readable article title used by notifications. The SDK never derives either value from the browser URL. Styles are bundled into the component; colour tokens inherit from the host page and the auto theme inherits its color-scheme. Default --ecoku-* tokens have zero specificity, so a host rule on .ecoku-comments overrides them. Pass cssURL to skip injection and use a host stylesheet instead (none skips without loading a file).

The interface language comes from the i18n option, then the site's saved language, then zh-CN. Default placeholder, empty-state and blogger-badge text follow that language; text the site customized is shown as written.

The server-authoritative site registry controls whether email and website are required and supplies the comment textarea placeholder. The SDK reads this safe form configuration from the public comment-list response; it never accepts management credentials in browser options. Nickname and comment content remain required for every site.

For a single-page application, call setPageKey() after a route change; it loads the first page of the new article itself. reload() refreshes the current page, and destroy() unmounts the surface:

await comments.setPageKey('guides/another-article', 'Another article')
await comments.reload()   // refresh the current page when needed
comments.destroy()        // when the host component unmounts

apiBaseUrl remains a deprecated alias for serverURL. The former ecoku-comment-* DOM-template protocol is no longer supported; production integration must provide a dedicated container. This removal is the breaking change from the former DOM-template integration. Replace legacy template elements with one empty container and pass that container together with serverURL, siteId, and pageKey to the constructor.

Privacy and security contract

  • The browser receives only published comments and public tombstones.
  • Nickname, email, and website are shared by the root and inline reply forms. They are encrypted in IndexedDB with a non-extractable AES-GCM key, scoped to serverURL + siteId, and expire seven days after saving. No identity value is written to localStorage, cookies, or URLs; clearing browser site data removes it naturally. Unavailable, corrupt, or expired storage falls back to an empty identity without blocking comments.
  • The SDK never accepts a management key, administrator token, client IP, forwarding header, user-agent value, location, avatar, analytics endpoint, or third-party IP service.
  • The server selects off, Cloudflare Turnstile, or a self-hosted Cap instance through public form configuration. The SDK loads only the selected Widget and sends one generic, single-use captchaToken; provider Secrets and Siteverify results never enter the browser. Cap Widget/WASM assets come from the configured instance, not a public CDN.
  • Comment content is rendered as text. HTML and Markdown are not interpreted.
  • Author websites must use http or https and are rendered with nofollow ugc noopener noreferrer.

Strict host CSP must allow the selected provider. Turnstile requires https://challenges.cloudflare.com; current Cap 3.x instrumentation requires the configured Cap HTTPS Origin in script-src and connect-src, worker-src blob:, frame-src 'self', WebAssembly, and JavaScript 'unsafe-eval' because its generated sandbox script uses eval / new Function. Nonce-based Cap instrumentation also uses the same preconfigured window.CAP_CSS_NONCE and window.CAP_SCRIPT_NONCE before Ecoku loads. Hosts that reject this CSP tradeoff must disable instrumentation for that Cap key or select Turnstile; do not broaden the policy with wildcards or unsafe-inline.

Development checks

pnpm run test
pnpm run type-check
pnpm run build
pnpm run test:package
pnpm run validate

The package currently has no lint script.

The optional second setPageKey argument updates the article title; omission clears the old title. Call after the host has updated its route and title. Direct SDK cssURL disables inline CSS only; add the corresponding stylesheet with a host <link rel="stylesheet">. The hosted loader inserts that link automatically.