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

kronan

v0.1.1

Published

Kronan CLI (cart + products + favorites + orders)

Readme

Krónan

CLI + API client for Krónan (Iceland).

Requirements

  • Node.js 18+ (or Bun)

Install

CLI (global):

npm install -g kronan

Run without installing:

npx kronan --help

Library:

npm install kronan

Quick start (CLI)

export KRONAN_AUTH_TOKEN="..."
kronan auth set --from-env
kronan products search --query "mjolk"

More help:

kronan --help
kronan auth --help

Auth (CLI)

You store the raw JWT (no prefix). The CLI adds the CognitoJWT prefix automatically when it sends requests.

Store once (recommended):

export KRONAN_AUTH_TOKEN="..."
kronan auth set --from-env
kronan auth show

One-off usage (no storage):

KRONAN_AUTH_TOKEN="..." kronan products search --query "mjolk"
kronan products search --query "mjolk" --token TOKEN

Token storage (override with KRONAN_CONFIG_DIR):

  • ~/.kronan/auth-token
  • ~/.kronan/refresh-token

The CLI also loads .env from the current directory (existing environment values are not overwritten).

How to obtain a token

Method A (backend request header):

  1. Sign in to the Krónan web app in your browser.
  2. Open DevTools → Network.
  3. Reload the page and click a request to https://backend.kronan.is/.
  4. In request headers, copy the Authorization value that starts with CognitoJWT.
  5. Paste the token (without the CognitoJWT prefix) into KRONAN_AUTH_TOKEN.

Method B (OAuth token response):

  1. In DevTools → Network, find the request to https://auth.kronan.is/oauth2/token.
  2. Copy id_token or access_token from the JSON response.
  3. Set KRONAN_AUTH_TOKEN to that raw token value.

Keep tokens private. Treat them like passwords.

Auto-refresh (optional)

export KRONAN_REFRESH_TOKEN="..."
export KRONAN_COGNITO_TOKEN_URL="https://auth.kronan.is/oauth2/token"
export KRONAN_COGNITO_CLIENT_ID="..."
kronan auth setup --from-env
kronan auth refresh

About the client ID:

  • It identifies the Krónan app in Cognito/OAuth.
  • It is required for refresh, and must match the app that issued your refresh token.
  • It is not a secret by itself.
  • It is the same for all Krónan users (not per user or per machine).

Where to find it:

  • DevTools → Network → https://auth.kronan.is/oauth2/token (POST body has client_id=...).
  • Or https://auth.kronan.is/oauth2/authorize?...&client_id=....
  • Not the same as the Google OAuth client_id (accounts.google.com/...).

Common CLI flows

Browse + add to cart:

kronan products search --query "mjolk"
kronan cart add --sku 100230536 --qty 1
kronan cart show

Checkout (delivery):

kronan order slots --type delivery --query-json '{"chain":"kronan"}'
kronan order apply-shipping --slot-id SLOT_ID
kronan order contact --body-file contact.json
kronan order payment --body-file payment.json
kronan order finish

Orders export:

kronan orders export --since 2025-01-01

orders export writes a JSON snapshot and a line-level CSV to ~/.kronan/orders-last-year.json and ~/.kronan/orders-last-year-lines.csv by default.

Command reference (CLI)

Global options:

  • --token TOKEN override auth token
  • --base-url URL API base URL
  • --group-id ID Customer group id
  • --rate-limit-ms N minimum delay between requests
  • --json print raw JSON response

Auth:

kronan auth show [--raw]
kronan auth set --token TOKEN
kronan auth set --from-env
kronan auth set-refresh --token TOKEN
kronan auth set-refresh --from-env
kronan auth refresh
kronan auth clear

Products:

kronan products search --query TEXT [--page N] [--page-size N]
kronan products sku-list --sku SKU [--sku SKU]
kronan products all-items [--limit N]

Favorites:

kronan favorites products
kronan favorites recipes

Cart:

kronan cart show
kronan cart add --sku SKU --qty N
kronan cart add --line SKU:QTY [--line SKU:QTY]
kronan cart set --sku SKU --qty N
kronan cart remove --sku SKU
kronan cart clear

Order:

kronan order show
kronan order slots --type delivery|pickup [--query-json JSON|--query-file PATH]
kronan order reserve-slot-token
kronan order apply-shipping --slot-id ID [--address-id N]
kronan order contact --body JSON|--body-file PATH
kronan order payment --body JSON|--body-file PATH
kronan order finish
kronan order finish-invoice --body JSON|--body-file PATH

Orders:

kronan orders ongoing [--limit N] [--page-size N]
kronan orders status --token ORDER_TOKEN
kronan orders export [--since DATE] [--out PATH] [--page-size N]

Stats:

kronan stats most-bought [--limit N] [--out PATH] [--page-size N]

Tip: add --json to print raw JSON responses for scripting.

Environment variables (CLI)

  • KRONAN_AUTH_TOKEN (required for authenticated calls)
  • KRONAN_REFRESH_TOKEN (for auth refresh)
  • KRONAN_COGNITO_TOKEN_URL (for auth refresh)
  • KRONAN_COGNITO_CLIENT_ID (for auth refresh)
  • KRONAN_BASE_URL (defaults to https://backend.kronan.is/)
  • KRONAN_GROUP_ID (sets Customer-Group-Id header)
  • KRONAN_CHECKOUT_ID (defaults to default)
  • KRONAN_RATE_LIMIT_MS (minimum delay between requests, default 200)
  • KRONAN_CONFIG_DIR (override token storage directory)

Troubleshooting

Missing auth token:

export KRONAN_AUTH_TOKEN="..."
kronan auth set --from-env

Expired signature / 401:

export KRONAN_REFRESH_TOKEN="..."
export KRONAN_COGNITO_TOKEN_URL="https://auth.kronan.is/oauth2/token"
export KRONAN_COGNITO_CLIENT_ID="..."
kronan auth refresh

Refresh token issues:

If refresh tokens keep failing, consider creating a separate Krónan user for your bot and sign in with Google Auth instead of Auðkenni, which can be unreliable for refresh.

Invalid date for --since (orders export):

kronan orders export --since 2025-01-01

Tokens are stored at ~/.kronan/ by default (override with KRONAN_CONFIG_DIR).

JavaScript/TypeScript usage

Minimal usage:

import { KronanClient } from "kronan";

const client = new KronanClient({
  authToken: process.env.KRONAN_AUTH_TOKEN,
});

const stores = await client.storesList();
console.log("stores:", stores.length);

Search products:

const results = await client.productsRawSearch(
  { query: "banana", page: 1, pageSize: 5 },
  { withDetail: true },
);
console.log(results.count);

Add items to the smart checkout cart:

await client.smartCheckoutsLinesCreate("default", {
  lines: [{ sku: "100230536", quantity: 1 }],
});

Optional auto-refresh configuration:

const client = new KronanClient({
  authToken: process.env.KRONAN_AUTH_TOKEN,
  refreshToken: process.env.KRONAN_REFRESH_TOKEN,
  cognitoTokenUrl: process.env.KRONAN_COGNITO_TOKEN_URL,
  cognitoClientId: process.env.KRONAN_COGNITO_CLIENT_ID,
  onAuthTokenRefreshed: (next) => {
    // Persist refreshed token if you want.
    console.log("refreshed", next.slice(0, 8));
  },
});

The client automatically refreshes the auth token on a 401 response that indicates an expired signature.