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

@slopit/core

v0.1.0

Published

Core types, schemas, and validation for slopit behavioral analytics

Downloads

10

Readme

@slopit/core

Core type definitions, schemas, and utilities for the slopit behavioral capture toolkit.

Installation

pnpm add @slopit/core

Quick Start

import {
  generateSessionId,
  hashText,
  validateSession,
  captureEnvironment,
} from "@slopit/core";

// generate unique identifiers
const sessionId = generateSessionId();

// hash sensitive text
const hash = await hashText("user input text");

// capture browser environment
const env = captureEnvironment();

// validate session data
const result = validateSession(sessionData);
if (!result.success) {
  console.error("Validation errors:", result.errors);
}

Type Definitions

Session Types

SlopitSession

The top-level container for all data from a research session.

interface SlopitSession {
  schemaVersion: string;
  sessionId: string;
  participantId?: string;
  studyId?: string;
  platform: PlatformInfo;
  environment: EnvironmentInfo;
  timing: SessionTiming;
  trials: SlopitTrial[];
  globalEvents: GlobalEvents;
}

SlopitTrial

Data for a single trial within a session.

interface SlopitTrial {
  trialId: string;
  trialIndex: number;
  trialType: string;
  startTime: number;
  endTime: number;
  rt: number;
  stimulus?: StimulusInfo;
  response?: ResponseInfo;
  behavioral?: BehavioralData;
  captureFlags?: CaptureFlag[];
  platformData?: Record<string, unknown>;
}

PlatformInfo

Information about the experiment platform.

interface PlatformInfo {
  name: string;           // e.g., "jspsych"
  version: string;        // platform version
  adapterVersion: string; // slopit adapter version
}

EnvironmentInfo

Browser and system environment data.

interface EnvironmentInfo {
  userAgent: string;
  language: string;
  platform: string;
  screenWidth: number;
  screenHeight: number;
  windowWidth: number;
  windowHeight: number;
  devicePixelRatio: number;
  timezone: string;
  timezoneOffset: number;
}

SessionTiming

Timing information for the session.

interface SessionTiming {
  startTime: number;  // Unix timestamp in milliseconds
  endTime: number;    // Unix timestamp in milliseconds
  duration: number;   // Total duration in milliseconds
}

Behavioral Event Types

KeystrokeEvent

A single keystroke event.

| Field | Type | Description | |-------|------|-------------| | time | number | Time since trial start in milliseconds | | key | string | Key value from KeyboardEvent.key (e.g., "a", "Enter", "Backspace") | | code | string | Physical key code from KeyboardEvent.code (e.g., "KeyA", "Enter") | | event | "keydown" | "keyup" | Event type | | textLength | number? | Current text length at this moment | | modifiers | ModifierState? | Modifier key states |

ModifierState

Modifier key states at time of keystroke.

interface ModifierState {
  shift: boolean;
  ctrl: boolean;
  alt: boolean;
  meta: boolean;
}

FocusEvent

A focus or visibility change event.

| Field | Type | Description | |-------|------|-------------| | time | number | Time since trial start in milliseconds | | event | "focus" | "blur" | "visibilitychange" | Event type | | visibility | "visible" | "hidden"? | For visibilitychange events, the new state | | blurDuration | number? | For blur events, duration until refocus (filled retrospectively) |

PasteEvent

A paste event.

| Field | Type | Description | |-------|------|-------------| | time | number | Time since trial start in milliseconds | | textLength | number | Length of pasted text in characters | | textPreview | string? | First N characters of pasted text (default N=100) | | textHash | string? | SHA-256 hash of full pasted text | | precedingKeystrokes | number | Number of keystrokes in preceding 2 seconds | | blocked | boolean | Whether paste was blocked by configuration |

MouseEvent

A mouse event.

| Field | Type | Description | |-------|------|-------------| | time | number | Time since trial start in milliseconds | | event | "mousemove" | "mousedown" | "mouseup" | "click" | Event type | | x | number | X coordinate relative to viewport | | y | number | Y coordinate relative to viewport | | velocity | number? | Velocity in pixels per millisecond (for mousemove) | | distance | number? | Distance traveled since last event in pixels | | deltaTime | number? | Time since last mouse event in milliseconds | | isDragging | boolean? | Whether this event is part of a drag operation |

ScrollEvent

A scroll event.

| Field | Type | Description | |-------|------|-------------| | time | number | Time since trial start in milliseconds | | direction | "up" | "down" | Direction of scroll | | deltaY | number | Scroll delta in pixels | | scrollTop | number | Current scroll position from top | | scrollHeight | number | Scrollable element height | | clientHeight | number | Viewport height | | velocity | number? | Velocity in pixels per millisecond |

ClipboardCopyEvent

A clipboard copy or cut event.

| Field | Type | Description | |-------|------|-------------| | time | number | Time since trial start in milliseconds | | event | "copy" | "cut" | Event type | | textLength | number | Length of selected text | | textPreview | string? | First N characters of copied text | | textHash | string? | SHA-256 hash of copied text | | selectionStart | number? | Selection start index in input element | | selectionEnd | number? | Selection end index in input element |

InputDurationEvent

An input duration event tracking focus sessions.

| Field | Type | Description | |-------|------|-------------| | focusTime | number | Time since trial start when focus was gained | | blurTime | number | Time since trial start when focus was lost | | duration | number | Duration focused in milliseconds | | elementId | string? | Element identifier (id or name attribute) | | keystrokesDuringFocus | number? | Number of keystrokes during focus | | pastesDuringFocus | number? | Number of paste events during focus |

Behavioral Metrics Types

BehavioralData

Container for all behavioral capture data.

interface BehavioralData {
  keystrokes?: KeystrokeEvent[];
  focus?: FocusEvent[];
  paste?: PasteEvent[];
  mouse?: MouseEvent[];
  scroll?: ScrollEvent[];
  clipboard?: ClipboardCopyEvent[];
  inputDuration?: InputDurationEvent[];
  metrics?: BehavioralMetrics;
}

BehavioralMetrics

Computed metrics from behavioral data.

interface BehavioralMetrics {
  keystroke?: KeystrokeMetrics;
  focus?: FocusMetrics;
  timing?: TimingMetrics;
  mouse?: MouseMetrics;
  scroll?: ScrollMetrics;
  inputDuration?: InputDurationMetrics;
}

KeystrokeMetrics

Metrics computed from keystroke data.

| Field | Type | Description | |-------|------|-------------| | totalKeystrokes | number | Total number of keystrokes | | printableKeystrokes | number | Number of printable character keystrokes | | deletions | number | Number of deletion keystrokes (Backspace, Delete) | | meanIKI | number | Mean inter-keystroke interval in milliseconds | | stdIKI | number | Standard deviation of IKI | | medianIKI | number | Median IKI | | pauseCount | number | Number of pauses (IKI > threshold) | | productProcessRatio | number | Ratio of final characters to total keystrokes |

FocusMetrics

Metrics computed from focus data.

| Field | Type | Description | |-------|------|-------------| | blurCount | number | Number of blur events | | totalBlurDuration | number | Total time in milliseconds with window blurred | | hiddenCount | number | Number of visibility hidden events | | totalHiddenDuration | number | Total time in milliseconds with document hidden |

TimingMetrics

Timing metrics.

| Field | Type | Description | |-------|------|-------------| | firstKeystrokeLatency | number? | Time from trial start to first keystroke | | totalResponseTime | number | Time from trial start to response submission | | charactersPerMinute | number? | Characters per minute (excluding deletions) |

MouseMetrics

Metrics computed from mouse data.

| Field | Type | Description | |-------|------|-------------| | totalEvents | number | Total number of mouse events | | clickCount | number | Number of click events | | meanVelocity | number | Mean mouse velocity in pixels per millisecond | | totalDistance | number | Total distance traveled by cursor in pixels | | totalIdleTime | number | Total idle time with no mouse movement | | idlePeriodCount | number | Number of idle periods exceeding threshold |

ScrollMetrics

Metrics computed from scroll data.

| Field | Type | Description | |-------|------|-------------| | totalScrollEvents | number | Total number of scroll events | | totalScrollDistance | number | Total scroll distance in pixels | | directionChanges | number | Number of scroll direction changes | | meanScrollVelocity | number | Mean scroll velocity | | upDownRatio | number | Time spent scrolling up vs down ratio |

InputDurationMetrics

Metrics computed from input duration data.

| Field | Type | Description | |-------|------|-------------| | totalFocusDuration | number | Total focus duration across all inputs | | meanFocusDuration | number | Mean focus duration per input session | | focusSessionCount | number | Number of focus sessions | | maxFocusDuration | number | Longest single focus session |

Flag Types

CaptureFlag

Flag generated during data capture.

interface CaptureFlag {
  type: string;                      // Flag type identifier
  severity: Severity;                // "info" | "low" | "medium" | "high"
  message: string;                   // Human-readable description
  timestamp: number;                 // Timestamp when flag was generated
  details?: Record<string, unknown>; // Additional details
}

AnalysisFlag

Flag generated during server-side analysis.

interface AnalysisFlag {
  type: string;                      // Flag type identifier
  analyzer: string;                  // Analyzer that generated this flag
  severity: Severity;                // "info" | "low" | "medium" | "high"
  message: string;                   // Human-readable description
  confidence?: number;               // Confidence score (0.0 to 1.0)
  evidence?: Record<string, unknown>;// Evidence supporting this flag
  trialIds?: string[];               // Related trial IDs if trial-specific
}

Severity

Severity level for flags.

type Severity = "info" | "low" | "medium" | "high";

Validation

validateSession

Validates a session object against the schema.

import { validateSession } from "@slopit/core";

const result = validateSession(sessionData);

if (result.success) {
  console.log("Session is valid");
} else {
  console.error("Validation errors:", result.errors);
}

isValidSession

Type guard for checking session validity.

import { isValidSession } from "@slopit/core";

if (isValidSession(data)) {
  // data is typed as SlopitSession
  console.log(data.sessionId);
}

Zod Schemas

The package exports Zod schemas for all types.

import {
  SlopitSessionSchema,
  SlopitTrialSchema,
  BehavioralDataSchema,
  KeystrokeEventSchema,
  FocusEventSchema,
  PasteEventSchema,
  CaptureFlagSchema,
  AnalysisFlagSchema,
} from "@slopit/core";

// parse and validate data
const keystroke = KeystrokeEventSchema.parse(rawData);

// safe parse with error handling
const result = SlopitTrialSchema.safeParse(trialData);
if (!result.success) {
  console.error(result.error.issues);
}

Utility Functions

ID Generation

generateSessionId

Generates a unique session identifier.

import { generateSessionId } from "@slopit/core";

const id = generateSessionId();
// Returns: "session_1706123456789_a1b2c3d4"

generateTrialId

Generates a unique trial identifier.

import { generateTrialId } from "@slopit/core";

const id = generateTrialId();
// Returns: "trial_1706123456789_e5f6g7h8"

Hashing

hashText

Computes SHA-256 hash of text using Web Crypto API.

import { hashText } from "@slopit/core";

const hash = await hashText("Hello, world!");
// Returns: "315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3"

simpleHash

Synchronous simple hash for non-cryptographic purposes.

import { simpleHash } from "@slopit/core";

const hash = simpleHash("Hello, world!");
// Returns: "0a1b2c3d" (8-character hex string)

Timing

now

Returns current Unix timestamp in milliseconds.

import { now } from "@slopit/core";

const timestamp = now();
// Returns: 1706123456789

highResTime

Returns high-resolution timestamp for performance measurement.

import { highResTime } from "@slopit/core";

const start = highResTime();
// ... do work
const elapsed = highResTime() - start;

duration

Calculates duration between two timestamps.

import { duration } from "@slopit/core";

const elapsed = duration(startTime);        // from startTime to now
const elapsed = duration(startTime, endTime); // from startTime to endTime

formatDuration

Formats a duration in human-readable format.

import { formatDuration } from "@slopit/core";

formatDuration(65000);    // "1m 5s"
formatDuration(3661000);  // "1h 1m 1s"
formatDuration(500);      // "500ms"

toTimestamp / fromTimestamp

Converts between Date objects and Unix timestamps.

import { toTimestamp, fromTimestamp } from "@slopit/core";

const timestamp = toTimestamp(new Date());
const date = fromTimestamp(1706123456789);

Environment

captureEnvironment

Captures browser and system environment information.

import { captureEnvironment } from "@slopit/core";

const env = captureEnvironment();
/*
{
  userAgent: "Mozilla/5.0 ...",
  language: "en-US",
  platform: "MacIntel",
  screenWidth: 2560,
  screenHeight: 1440,
  windowWidth: 1920,
  windowHeight: 1080,
  devicePixelRatio: 2,
  timezone: "America/New_York",
  timezoneOffset: -300
}
*/

Constants

import {
  SCHEMA_VERSION,
  DEFAULT_CONFIG,
  SEVERITY_LEVELS,
  KNOWN_PLATFORMS,
} from "@slopit/core";

console.log(SCHEMA_VERSION);    // "1.0.0"
console.log(SEVERITY_LEVELS);   // ["info", "low", "medium", "high"]
console.log(KNOWN_PLATFORMS);   // ["jspsych", "pavlovia", "gorilla", ...]

Package Exports

The package provides multiple entry points:

// main entry point with all exports
import { ... } from "@slopit/core";

// schemas only
import { ... } from "@slopit/core/schemas";

// validation only
import { ... } from "@slopit/core/validation";

License

MIT