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

@luckystack/sync

v0.2.6

Published

Real-time sync transport for LuckyStack: type-safe room-based fanout, server + per-client validation, streaming, optimistic offline queue. Server entry plus a browser-safe ./client subpath.

Readme

@luckystack/sync

Real-time sync transport for LuckyStack. Type-safe room-based fanout, server + per-client validation, streaming, optimistic offline queue. Server entry plus a browser-safe ./client subpath for React.

Install

npm install @luckystack/sync @luckystack/core @luckystack/login @luckystack/error-tracking react socket.io socket.io-client

Quickstart

A sync event is two files (one mandatory, one optional):

// src/board/_sync/moveCard_server_v1.ts  — runs ONCE per request, validates and produces serverOutput
export const auth = { login: true };

export interface SyncParams {
  data: { cardId: string; toLane: string };
  user: SessionLayout;
  receiver: string; // room code
  functions: Functions;
}

export const main = async ({ data, user, receiver }: SyncParams) => {
  await prisma.card.update({ where: { id: data.cardId }, data: { laneId: data.toLane } });
  return { status: 'success', serverOutput: { cardId: data.cardId, movedBy: user.id } };
};

Add a _client_v1.ts only when you need per-client filtering, per-target auth, or a custom clientOutput. If it would just return { status: 'success' }, leave it out.

Client side

import { syncRequest, upsertSyncEventCallback } from '@luckystack/sync/client';

upsertSyncEventCallback({
  name: 'board/moveCard',
  version: 'v1',
  callback: ({ serverOutput, clientOutput }) => {
    if (serverOutput.status !== 'success') return;
    setCards(prev => moveCardLocally(prev, serverOutput.cardId));
  },
});

await syncRequest({
  name: 'board/moveCard',
  version: 'v1',
  data: { cardId, toLane },
  receiver: roomCode,
  ignoreSelf: true,
});

Subpaths

  • @luckystack/sync — server-only transport adapters (handleSyncRequest, handleHttpSyncRequest). Wired by @luckystack/server.
  • @luckystack/sync/client — browser-safe hooks (syncRequest, useSyncEvents, upsertSyncEventCallback). React 19 required.

How it integrates

  1. Validates server payload, then runs _server_v{N}.ts once.
  2. Dispatches the preSyncFanout hook (may abort).
  3. Resolves the room receiver list, optionally running _client_v{N}.ts once per recipient socket for per-client filtering or auth.
  4. Emits the merged { serverOutput, clientOutput } payload to each socket.
  5. Dispatches postSyncFanout with the recipient count.

Streaming

Sync handlers receive four stream primitives in their _server params, each picking a different audience and cost profile:

| Primitive | Audience | Use when | | --- | --- | --- | | stream(payload) | Originator only (cheapest) | Per-user progress nobody else cares about | | broadcastStream(payload) | Everyone in roomCode, across all instances (Redis adapter) | Live AI chat tokens, collab editor diffs | | streamTo(tokens, payload) | Specific session tokens | Selective subscribers (admin viewers, etc.) | | _client_v{N}.ts stream(...) | Per-recipient (after _server finishes) | Per-target customization (filter / translate / brand) |

Plus createStreamThrottle({ flushEveryMs, flushAtChars }) for coalescing tiny LLM tokens into bigger chunks — cuts message count by 10–100× without losing the "live" feel.

// src/chat/_sync/sendMessage_server_v1.ts — AI chat with live broadcast
import { createStreamThrottle } from '@luckystack/sync';

export const main = async ({ clientInput, broadcastStream }: SyncParams) => {
  const throttle = createStreamThrottle({ flushEveryMs: 50, flushAtChars: 32 });

  let full = '';
  for await (const piece of openaiStream) {
    full += piece.text;
    throttle.push(piece.text, broadcastStream);
  }
  throttle.flush(broadcastStream);

  return { status: 'success', message: full };
};

Recipients consume both broadcastStream and streamTo chunks via the same upsertSyncEventCallback they already use:

upsertSyncEventCallback({
  name: 'chat/sendMessage',
  version: 'v1',
  callback: ({ stream, status }) => {
    if (status === 'stream' && stream?.chunk) appendToken(stream.chunk);
  },
});

Full decision tree, performance notes, and additional examples live in docs/ARCHITECTURE_SYNC.md.

Public API

Server entry (@luckystack/sync):

| Export | Purpose | | --- | --- | | handleSyncRequest(socket, msg, ack) | Socket.io sync handler (default export). | | handleHttpSyncRequest(req, res) | HTTP/SSE fallback. | | createStreamThrottle(options) | Coalesce small stream pieces into bigger chunks (LLM-token-friendly). | | Type: HttpSyncStreamEvent | SSE event shape. | | Type: StreamThrottle / CreateStreamThrottleOptions | Throttle helper types. |

Configure stream throttling and offline-queue policy via registerProjectConfig({ sync, offlineQueue }). The shapes are exported from @luckystack/core as SyncConfig (with nested SyncStreamThrottleConfig) and OfflineQueueConfig — they cover the throttle defaults, fanout iteration tuning, and the queue's max-size + drop policy ('reject' triggers the offline.queueFull error code on overflow).

Client entry (@luckystack/sync/client):

| Export | Purpose | | --- | --- | | syncRequest(opts) | Fire a typed sync event, optionally with ignoreSelf and receiver. | | upsertSyncEventCallback({ name, version, callback }) | Subscribe to inbound sync payloads. | | useSyncEvents(...) | React hook for component-scoped subscriptions. |

Related architecture docs

Dependencies

  • Runtime: @luckystack/core, @luckystack/login, @luckystack/error-tracking
  • Peer (canonical ranges, standardized 2026-05-07):
    • @prisma/client@^6.19.0 (transitively required via @luckystack/core)
    • react@^19.2.0 (/client entry only)
    • socket.io@^4.8.0
    • socket.io-client@^4.8.0

License

MIT — see LICENSE.