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

placemark

v0.1.3

Published

Opaque, tamper-evident pagination cursors — seal state into a URL-safe token, open it with typed failures instead of silent corruption

Readme

placemark

npm MIT License

Opaque, tamper-evident pagination cursors — seal state into a URL-safe token, open it with typed failures instead of silent corruption.

The problem

Building pagination that's both secure and user-friendly is hard:

  • Server-side sessions → Complex state management, doesn't scale horizontally
  • Opaque cursors → Clients can't bookmark or share URLs
  • JSON in URLs → Exposes internal structure, encourages tampering
  • Database offsets → Break when data changes, inconsistent results
  • Custom encoding → Easy to get wrong, security vulnerabilities

You get either complex state management or insecure, unfriendly URLs.

The solution

placemark encodes pagination state into tamper-evident URL-safe tokens:

import placemark from "placemark";

// Create instance with secret for tamper protection
const cursor = placemark({ secret: "my-app-secret-key" });

// Seal pagination state into URL-safe token
const token = cursor.seal({
  page: 2,
  pageSize: 10,
  sort: { field: "created", order: "desc" },
  filters: { status: "active" }
});
// → "WzEsbnVsbCwie1wicGFnZVwiOjIsXCJwYWdlU2l6ZVwiOjEw..."

// Open token with automatic validation
const state = cursor.open<{ page: number; pageSize: number }>(token);
// → { page: 2, pageSize: 10, ... }

Benefits:

  • Zero server-side storage — All state in the token
  • Tamper-evident — HMAC prevents modification
  • URL-safe — Perfect for query parameters
  • Type-safe — Full TypeScript support
  • Optional expiration — TTL for time-sensitive tokens

Install

npm install placemark
# or
pnpm add placemark
# or
yarn add placemark

Use

Basic pagination

import placemark from "placemark";

const cursor = placemark({ secret: "my-app-secret-key" });

// Server creates initial token
const token = cursor.seal({ page: 1, pageSize: 10 });

// Client requests next page with token
const state = cursor.open(token);
state.page += 1;
const nextToken = cursor.seal(state);

// Use in URLs
const url = `/api/items?cursor=${encodeURIComponent(nextToken)}`;

Advanced pagination with filters

import placemark from "placemark";

const cursor = placemark({
  secret: "secret",
  ttl: 300000 // 5-minute expiration
});

const complexState = {
  page: 1,
  pageSize: 25,
  sort: { field: "created", order: "desc" },
  filters: {
    status: ["active", "pending"],
    category: "electronics",
    priceRange: { min: 0, max: 1000 }
  }
};

const token = cursor.seal(complexState);
const restored = cursor.open(token); // Perfect restoration

RESTful API example

import placemark from "placemark";

const apiCursor = placemark({ secret: "api-secret" });

app.get("/api/items", (req, res) => {
  let state = { page: 1, pageSize: 10 };

  if (req.query.cursor) {
    try {
      state = apiCursor.open(req.query.cursor);
    } catch (error) {
      return res.status(400).json({ error: "Invalid cursor" });
    }
  }

  const items = await fetchItems(state);
  const nextState = { ...state, page: state.page + 1 };
  const nextCursor = apiCursor.seal(nextState);

  res.json({
    items,
    nextCursor
  });
});

Error handling

import placemark from "placemark";
import {
  MalformedCursor,
  TamperedCursor,
  ExpiredCursor,
  VersionMismatch
} from "placemark";

const cursor = placemark({ secret: "secret" });

try {
  const state = cursor.open(token);
} catch (error) {
  if (error instanceof MalformedCursor) {
    // Invalid token format
  } else if (error instanceof TamperedCursor) {
    // Token was tampered with
  } else if (error instanceof ExpiredCursor) {
    // Token has expired (TTL)
  } else if (error instanceof VersionMismatch) {
    // Version incompatibility
  }
}

Encoded-only mode (no tamper protection)

import placemark from "placemark";

// No secret = encoded-only mode
const cursor = placemark();

const token = cursor.seal({ page: 1, pageSize: 10 });
const state = cursor.open(token); // Works, but no tamper protection

API

Core functions

placemark(options?: PlacemarkOptions): Placemark

Creates a placemark instance for encoding/decoding tokens.

Options:

  • secret?: string | Uint8Array — Secret key for HMAC validation (omit for encoded-only mode)
  • version?: number — Version number for format changes (default: 1)
  • ttl?: number — Time-to-live in milliseconds (requires issuedAt stamping)
  • clock?: () => number — Clock function for time injection (default: Date.now)

Placemark.seal<T>(data: T): string

Encodes JSON-serializable data into a URL-safe token string.

  • With secret: payload.mac format with HMAC protection
  • Without secret: payload format (encoded-only)

Placemark.open<T>(cursor: string): T

Decodes a token and returns the original data.

Throws:

  • MalformedCursor — Invalid token format
  • TamperedCursor — HMAC validation failed (secret mode only)
  • ExpiredCursor — Token expired (TTL mode only)
  • VersionMismatch — Version mismatch

Error classes

MalformedCursor

Invalid token format or structure.

TamperedCursor

Token failed HMAC validation (indicates tampering).

ExpiredCursor

Token exceeded its time-to-live.

VersionMismatch

Token version doesn't match expected version.

Usage patterns

URL parameter integration

import placemark from "placemark";

const cursor = placemark({ secret: "secret" });

// Server sends URL to client
const pageToken = cursor.seal({ page: 1, pageSize: 10 });
const url = `https://api.example.com/items?cursor=${encodeURIComponent(pageToken)}`;

// Client requests next page
const params = new URLSearchParams(url.split("?")[1]);
const token = params.get("cursor");
const state = cursor.open(token);

Clock manipulation for testing

let currentTime = 1000000;
const clock = () => currentTime;

const cursor = placemark({
  secret: "secret",
  ttl: 60000, // 1 minute
  clock
});

const token = cursor.seal({ page: 1 });

currentTime += 120000; // Advance 2 minutes

cursor.open(token); // Throws ExpiredCursor

Version migration strategy

// V1 tokens
const v1Cursor = placemark({ secret: "secret", version: 1 });

// V2 tokens (new format)
const v2Cursor = placemark({ secret: "secret", version: 2 });

// Migration function
function migrateToken(oldToken: string) {
  try {
    return v2Cursor.open(oldToken);
  } catch (error) {
    if (error instanceof VersionMismatch) {
      const oldState = v1Cursor.open(oldToken);
      return v2Cursor.seal(oldState);
    }
    throw error;
  }
}

Performance

placemark is optimized for high-traffic applications:

  • Encoding: ~0.006ms per token
  • Decoding: ~0.006ms per token
  • Token size: 50-500 chars depending on data size
  • Memory: Zero retained state per token

Suitable for production APIs with thousands of requests per second.

Non-goals

By design, placemark focuses on one thing: encoding state into tamper-evident tokens. These features are explicitly out of scope:

  • Encryption — Tokens are encoded, not encrypted. Use encryption libraries for sensitive data.
  • Compression — Large payloads produce large tokens. Compress data before sealing if needed.
  • Signature algorithms — Only HMAC-SHA256 for tamper evidence.
  • Token storage — No server-side token storage or tracking.
  • Session management — Use session libraries for complex session handling.
  • Rate limiting — Use rate limiting libraries for API protection.

If you need these features, compose placemark with specialized libraries.

Related Packages

Caching & Concurrency:

Text Processing:

  • @azghr/shorn — Truncate strings by byte budget without breaking graphemes
  • seriatim — Sequential processing utilities

HTTP & Network:

  • forbear — Read server rate-limit instructions from HTTP responses
  • forestall — Delay execution until a condition is met
  • obviate — Render operations unnecessary through caching

System & Process:

  • quiesce — Ordered, timeboxed graceful shutdown for Node
  • sortition — Deterministic percentage rollouts and A/B bucketing
  • stanch — Stop flows or operations based on conditions

Utilities:

  • expunge — Remove or exclude items from collections
  • occlude — Hide or mask data and functionality
  • specie — Currency and financial calculations

License

MIT