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

@prabhask5/stellar-engine

v1.1.6

Published

A local-first, offline-capable sync engine for **SvelteKit + Supabase + Dexie** applications. All reads come from IndexedDB, all writes land locally first, and a background sync loop ships changes to Supabase -- so your app stays fast and functional regar

Readme

@prabhask5/stellar-engine

A local-first, offline-capable sync engine for SvelteKit + Supabase + Dexie applications. All reads come from IndexedDB, all writes land locally first, and a background sync loop ships changes to Supabase -- so your app stays fast and functional regardless of network state.

Documentation

Features

  • Intent-based sync operations -- operations preserve intent (increment, set, create, delete) instead of just final state, enabling smarter coalescing and conflict handling.
  • Three-tier conflict resolution -- field-level diffing, numeric merge fields, and configurable exclusion lists let you resolve conflicts precisely rather than with blanket last-write-wins.
  • Offline authentication -- credential caching and offline session tokens let users sign in and work without connectivity; sessions reconcile automatically on reconnect.
  • Single-user auth mode -- for personal apps, use a simplified PIN code or password gate backed by real Supabase email/password auth. The user provides an email during setup; the PIN is padded to meet Supabase's minimum password length and verified server-side. Setup, unlock, lock, and gate change are all handled by the engine with full offline support.
  • Realtime subscriptions -- Supabase Realtime channels push remote changes into local state instantly, with duplicate-delivery guards to prevent re-processing.
  • Operation coalescing -- batches of rapid local writes (e.g., 50 individual increments) are compressed into a single outbound operation, reducing sync traffic dramatically.
  • Tombstone management -- soft deletes are propagated cleanly, and stale tombstones are garbage-collected after a configurable retention period.
  • Egress optimization -- column-level select lists and ownership filters ensure only the data your client needs is fetched from Supabase.
  • Email -- optional SMTP email sending for share link invitations and notifications, with credential validation.

Quick start

Install from npm:

npm install @prabhask5/stellar-engine

Initialize the engine at app startup (e.g., in a SvelteKit root +layout.ts):

import { initEngine, startSyncEngine, supabase } from '@prabhask5/stellar-engine';
import { initConfig } from '@prabhask5/stellar-engine/config';
import { resolveAuthState } from '@prabhask5/stellar-engine/auth';

initEngine({
  prefix: 'myapp',
  supabase,
  tables: [
    {
      supabaseName: 'projects',
      columns: 'id, name, created_at, updated_at, is_deleted, user_id',
    },
    // ...more tables
  ],
  database: {
    name: 'MyAppDB',
    versions: [
      {
        version: 1,
        stores: {
          projects: 'id, user_id, updated_at',
          tasks: 'id, project_id, user_id, updated_at',
        }
      }
    ]
  },
  auth: {
    enableOfflineAuth: true,
  },
});

await initConfig();
const auth = await resolveAuthState();
if (auth.authMode !== 'none') await startSyncEngine();

Single-user mode

For personal apps with a PIN code gate backed by real Supabase email/password auth:

import { initEngine, startSyncEngine, supabase } from '@prabhask5/stellar-engine';
import { initConfig } from '@prabhask5/stellar-engine/config';
import { resolveAuthState } from '@prabhask5/stellar-engine/auth';

initEngine({
  prefix: 'myapp',
  supabase,
  tables: [/* ... */],
  database: {/* ... */},
  auth: {
    mode: 'single-user',
    singleUser: { gateType: 'code', codeLength: 4 },
    enableOfflineAuth: true,
    // emailConfirmation: { enabled: true },       // require email confirmation on setup
    // deviceVerification: { enabled: true },       // require OTP verification on new devices
  },
});

await initConfig();
const auth = await resolveAuthState();

if (!auth.singleUserSetUp) {
  // Show setup screen → call setupSingleUser(code, profile, email)
  // Returns { error, confirmationRequired }
  // If confirmationRequired, prompt user to check email then call completeSingleUserSetup()
} else if (auth.authMode === 'none') {
  // Show unlock screen → call unlockSingleUser(code)
  // Returns { error, deviceVerificationRequired?, maskedEmail? }
  // If deviceVerificationRequired, prompt for OTP then call completeDeviceVerification(tokenHash?)
} else {
  await startSyncEngine();
}

Email (optional)

Send emails via SMTP for share link invitations:

import { sendEmail, validateSmtpCredentials } from '@prabhask5/stellar-engine/email';

// Validate SMTP credentials
const { valid, error } = await validateSmtpCredentials({
  smtpHost: 'smtp.example.com',
  smtpPort: 587,
  smtpUser: '[email protected]',
  smtpPass: 'password',
  fromEmail: '[email protected]',
  fromName: 'My App'
});

// Send an email
const result = await sendEmail(config, {
  to: '[email protected]',
  subject: 'You have been invited',
  html: '<p>Click here to view the shared note.</p>'
});

Subpath exports

Import only what you need via subpath exports:

| Subpath | Contents | |---|---| | @prabhask5/stellar-engine | initEngine, startSyncEngine, runFullSync, supabase, getDb, validateSupabaseCredentials, validateSchema | | @prabhask5/stellar-engine/data | All engine CRUD + query operations (engineCreate, engineUpdate, etc.) | | @prabhask5/stellar-engine/auth | All auth functions (signIn, signUp, resolveAuthState, isAdmin, changeEmail, completeEmailChange, single-user: setupSingleUser, unlockSingleUser, lockSingleUser, completeSingleUserSetup, completeDeviceVerification, changeSingleUserEmail, completeSingleUserEmailChange, padPin, etc.) | | @prabhask5/stellar-engine/stores | Reactive stores + event subscriptions (syncStatusStore, authState, onSyncComplete, etc.) | | @prabhask5/stellar-engine/types | All type exports (Session, SyncEngineConfig, BatchOperation, SingleUserConfig, etc.) | | @prabhask5/stellar-engine/utils | Utility functions (generateId, now, calculateNewOrder, snakeToCamel, debug, etc.) | | @prabhask5/stellar-engine/actions | Svelte use: actions (remoteChangeAnimation, trackEditing, triggerLocalAnimation) | | @prabhask5/stellar-engine/config | Runtime config (initConfig, getConfig, setConfig, getDexieTableFor) | | @prabhask5/stellar-engine/crdt | CRDT document lifecycle, realtime sync, awareness/presence, offline cache | | @prabhask5/stellar-engine/email | Email sending (sendEmail, validateSmtpCredentials) |

The root export (@prabhask5/stellar-engine) re-exports everything for backward compatibility.

Requirements

Supabase

Your Supabase project needs tables matching the supabaseName entries in your config. The corresponding Dexie (IndexedDB) table name is automatically derived from supabaseName using snakeToCamel() conversion (e.g., goal_lists becomes goalLists). Each table should have at minimum:

  • id (uuid primary key)
  • updated_at (timestamptz) -- used as the sync cursor
  • is_deleted (boolean, default false) -- for soft-delete / tombstone support
  • An ownership column (e.g., user_id) if you use ownershipFilter

Row-Level Security policies should scope reads and writes to the authenticated user.

Single-user mode additional requirements:

Single-user mode uses real Supabase email/password auth where the PIN is padded to meet Supabase's minimum password length. The user provides an email during setup, and the PIN is verified server-side.

If deviceVerification is enabled in the auth config, you need a trusted_devices table:

CREATE TABLE trusted_devices (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id uuid REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,
  device_id text NOT NULL,
  device_label text,
  trusted_at timestamptz DEFAULT now() NOT NULL,
  last_used_at timestamptz DEFAULT now() NOT NULL,
  UNIQUE(user_id, device_id)
);
ALTER TABLE trusted_devices ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users manage own devices" ON trusted_devices FOR ALL
  USING (auth.uid() = user_id) WITH CHECK (auth.uid() = user_id);

If emailConfirmation is enabled, Supabase email templates must be configured. See EMAIL_TEMPLATES.md for the full HTML templates for signup confirmation, email change confirmation, and device verification emails.

Schema validation: The engine automatically validates that all configured tables (and trusted_devices when deviceVerification.enabled) exist in Supabase on the first sync. Missing tables are reported via syncStatusStore and the debug console.

Dexie (IndexedDB)

When you provide a database config to initEngine, the engine creates and manages the Dexie instance for you. System tables (syncQueue, conflictHistory, offlineCredentials, offlineSession, singleUserConfig) are automatically merged into every schema version -- you only declare your application tables. Note that the store keys use the camelCase Dexie table names (auto-derived from supabaseName via snakeToCamel()):

database: {
  name: 'MyAppDB',
  versions: [
    {
      version: 1,
      stores: {
        projects: 'id, user_id, updated_at',
        tasks: 'id, project_id, user_id, updated_at',
      }
    }
  ]
}

Alternatively, you can provide a pre-created Dexie instance via the db config option for full control.

Architecture

+---------------------+
|   Application UI    |
+---------------------+
         |
         v
+---------------------+       +-------------------+
|    Repositories     | ----> |    Dexie (IDB)    |
| (read/write local)  |       |  - app tables     |
+---------------------+       |  - syncQueue      |
         |                    |  - conflictHistory |
         | queueSyncOperation +-------------------+
         v                              ^
+---------------------+                |
|    Sync Engine      | ---------------+
|  - coalesce ops     |    hydrate / reconcile
|  - push to remote   |
|  - pull from remote  |
|  - resolve conflicts |
+---------------------+
         |
         v
+---------------------+       +---------------------+
|   Supabase REST     |       | Supabase Realtime   |
|   (push / pull)     |       | (live subscriptions)|
+---------------------+       +---------------------+
  1. Repositories read from and write to Dexie, then enqueue a SyncOperationItem describing the intent of the change.
  2. The engine debounces outbound operations, coalesces them, and pushes to Supabase via REST. On pull, it fetches rows newer than the local sync cursor and reconciles them with any pending local operations.
  3. Realtime channels deliver server-side changes immediately, skipping the next poll cycle when the subscription is healthy.

API overview

Configuration

| Export | Description | |---|---| | initEngine(config) | Initialize the engine with table definitions, Supabase client, and Dexie instance. | | getEngineConfig() | Retrieve the current config (throws if not initialized). | | SyncEngineConfig / TableConfig | TypeScript interfaces for the config objects. TableConfig uses supabaseName only; Dexie table names are auto-derived. |

Engine lifecycle

| Export | Description | |---|---| | startSyncEngine() | Start the sync loop, realtime subscriptions, and event listeners. | | stopSyncEngine() | Tear down everything cleanly. | | scheduleSyncPush() | Trigger a debounced push of pending operations. | | runFullSync() | Run a complete pull-then-push cycle. | | clearLocalCache() | Wipe all local application data. | | clearPendingSyncQueue() | Drop all pending outbound operations. |

Entity tracking

| Export | Description | |---|---| | markEntityModified(table, id) | Record that an entity was recently modified locally (prevents incoming realtime from overwriting). | | onSyncComplete(callback) | Register a callback invoked after each successful sync cycle. |

Auth

| Export | Description | |---|---| | signIn / signUp / signOut | Supabase auth wrappers that also manage offline credential caching. | | getSession / isSessionExpired | Session inspection helpers. | | changePassword / resendConfirmationEmail | Account management. | | changeEmail(newEmail) | Request email change (sends confirmation to new address). Returns { error, confirmationRequired }. | | completeEmailChange() | Finalize email change after confirmation. Refreshes session and updates cached credentials. | | getUserProfile / updateProfile | Profile read/write via Supabase user metadata. |

Offline auth

| Export | Description | |---|---| | cacheOfflineCredentials / getOfflineCredentials / verifyOfflineCredentials / clearOfflineCredentials | Store and verify credentials locally for offline sign-in. | | createOfflineSession / getValidOfflineSession / clearOfflineSession | Manage offline session tokens in IndexedDB. |

Single-user auth

For personal apps that use a simplified PIN or password gate. Uses real Supabase email/password auth where the PIN is padded to meet minimum password length. Enable by setting auth.mode: 'single-user' in the engine config.

| Export | Description | |---|---| | isSingleUserSetUp() | Check if initial setup is complete. | | getSingleUserInfo() | Get display info (profile, gate type) for the unlock screen. | | setupSingleUser(gate, profile, email) | First-time setup: create gate, Supabase email/password user, and store config. Returns { error, confirmationRequired }. | | unlockSingleUser(gate) | Verify gate and restore session (online or offline). Returns { error, deviceVerificationRequired?, maskedEmail? }. | | completeSingleUserSetup() | Called after the user confirms their email (when emailConfirmation is enabled). | | completeDeviceVerification(tokenHash?) | Called after the user completes device OTP verification (when deviceVerification is enabled). | | lockSingleUser() | Stop sync and reset auth state without destroying data. | | changeSingleUserGate(oldGate, newGate) | Change the PIN code or password. | | updateSingleUserProfile(profile) | Update profile in IndexedDB and Supabase metadata. | | changeSingleUserEmail(newEmail) | Request email change for single-user mode. Returns { error, confirmationRequired }. | | completeSingleUserEmailChange() | Finalize email change: refresh session, update IndexedDB config and cached credentials. | | resetSingleUser() | Full reset: clear config, sign out, wipe local data. | | padPin(pin) | Pad a PIN to meet Supabase's minimum password length requirement. |

Queue

| Export | Description | |---|---| | queueSyncOperation(item) | Enqueue a raw SyncOperationItem. | | queueCreateOperation(table, id, payload) | Enqueue entity creation. | | queueDeleteOperation(table, id) | Enqueue a soft delete. | | coalescePendingOps() | Compress the outbox in-place (called automatically before push). | | getPendingSync() / getPendingEntityIds() | Inspect the current outbox. |

Conflict resolution

| Export | Description | |---|---| | resolveConflicts(table, localEntity, remoteEntity, pendingOps) | Three-tier field-level conflict resolver. Returns the merged entity. |

Realtime

| Export | Description | |---|---| | startRealtimeSubscriptions() / stopRealtimeSubscriptions() | Manage Supabase Realtime channels for all configured tables. | | isRealtimeHealthy() | Realtime connection health check. | | wasRecentlyProcessedByRealtime(table, id) | Guard against duplicate processing. | | onRealtimeDataUpdate(callback) | Register a handler for incoming realtime changes. |

Stores (Svelte 5 compatible)

| Export | Description | |---|---| | syncStatusStore | Reactive store exposing current SyncStatus, last sync time, and errors. | | remoteChangesStore | Tracks which entities were recently changed by remote peers. | | createRecentChangeIndicator(table, id) | Derived indicator for UI highlighting of remote changes. | | createPendingDeleteIndicator(table, id) | Derived indicator for entities awaiting delete confirmation. | | isOnline | Reactive boolean reflecting network state. | | authState / isAuthenticated / userDisplayInfo | Reactive auth status stores. |

Supabase client

| Export | Description | |---|---| | supabase | The configured SupabaseClient instance. | | getSupabaseAsync() | Async getter that waits for initialization. | | resetSupabaseClient() | Tear down and reinitialize the client. |

Runtime config

| Export | Description | |---|---| | initConfig / getConfig / waitForConfig / setConfig | Manage app-level runtime configuration (e.g., feature flags loaded from the server). | | isConfigured() / clearConfigCache() | Status and cache management. |

Utilities

| Export | Description | |---|---| | generateId() | Generate a UUID. | | now() | Current ISO timestamp string. | | calculateNewOrder(before, after) | Fractional ordering helper for drag-and-drop reorder. | | snakeToCamel(str) | Convert a snake_case string to camelCase (also strips invalid characters). Used internally to derive Dexie table names from supabaseName. | | getDeviceId() | Stable per-device identifier (persisted in localStorage). | | debugLog / debugWarn / debugError | Prefixed console helpers (gated by setDebugMode). |

Browser console debug utilities

When debug mode is enabled, the engine exposes utilities on the window object using the configured app prefix (e.g. stellar):

| Window property | Description | |---|---| | window.__<prefix>SyncStats() | View sync cycle statistics (total cycles, recent cycle details, trigger types). | | window.__<prefix>Egress() | Monitor data transfer from Supabase (total bytes, per-table breakdown, recent cycles). | | window.__<prefix>Tombstones() | Check soft-deleted record counts across all tables. | | window.__<prefix>Tombstones({ cleanup: true }) | Manually trigger tombstone cleanup. | | window.__<prefix>Tombstones({ cleanup: true, force: true }) | Force server cleanup (bypasses 24-hour interval). | | window.__<prefix>Sync.forceFullSync() | Reset sync cursor, clear local data, and re-download everything from server. | | window.__<prefix>Sync.resetSyncCursor() | Clear the stored cursor so the next sync pulls all data. | | window.__<prefix>Sync.sync() | Trigger a manual sync cycle. | | window.__<prefix>Sync.getStatus() | View current sync cursor and pending operation count. | | window.__<prefix>Sync.checkConnection() | Test Supabase connectivity. | | window.__<prefix>Sync.realtimeStatus() | Check realtime connection state and health. |

Svelte actions

| Export | Description | |---|---| | remoteChangeAnimation | Svelte use: action that animates an element when a remote change arrives. | | trackEditing | Action that signals the engine a field is being actively edited (suppresses incoming overwrites). | | triggerLocalAnimation | Programmatically trigger the local-change animation on a node. |

Use cases

  • Productivity and task management apps -- offline-capable task boards, habit trackers, daily planners with cross-device sync.
  • Notion-like editors -- block-based documents where each block is a synced entity with field-level conflict resolution.
  • Personal finance trackers -- numeric merge fields handle concurrent balance adjustments across devices.
  • File and asset management UIs -- fractional ordering keeps drag-and-drop sort order consistent without rewriting every row.

License

Private -- not yet published under an open-source license.