Loading...
private.me Docs
Get UX Helpers
PRIVATE.ME · Technical White Paper

UX Helpers: Consistent User Experience

Shared UX utilities for consistent experience across all PRIVATE.ME packages. Provides standardized pagination, search, progress reporting, and error formatting — ensuring every ACI delivers the same developer-friendly interface. Zero configuration. One dependency (@private.me/shared). Tested across 100+ ACIs.

v0.1.0 101 tests passing 5 modules 1 dependency 100+ ACIs Dual ESM/CJS
Section 01

Executive Summary

UX Helpers provides four essential capabilities that every developer expects: pagination with metadata, flexible search, progress tracking, and actionable error messages. Used by 100+ ACIs across the PRIVATE.ME platform.

Pagination handles collections of any size with consistent metadata (page, limit, total, hasNext, hasPrev). Search supports case-insensitive matching across multiple fields with optional result limits. Progress reporting enables real-time updates for long-running operations like XorIDA splitting or multi-share reconstruction. Error formatting transforms technical errors into user-friendly messages with hints, field attribution, and documentation links.

Every ACI that integrates UX Helpers delivers the same developer experience — predictable interfaces, helpful error messages, and progress visibility. This consistency reduces cognitive load when working across multiple ACIs and makes the entire platform feel cohesive.

Zero configuration required. Import, call, done. Works anywhere JavaScript runs — Node.js, Deno, Bun, Cloudflare Workers, browsers. Dual ESM and CJS builds ship in a single package.

Section 02

Developer Experience

UX Helpers prioritizes developer productivity through consistent interfaces, comprehensive TypeScript types, and helpful error messages across all 100+ ACIs.

Progress Callbacks

Every long-running operation supports ProgressCallback for real-time status updates. Progress reporters work in both single-stage and multi-stage scenarios, automatically calculating percentages based on operation progress.

Multi-stage progress tracking
import { createStagedProgress } from '@private.me/ux-helpers';

async function deployService(onProgress?: ProgressCallback) {
  const progress = createStagedProgress(
    ['Building', 'Testing', 'Deploying'],
    onProgress
  );

  progress.start();          // "Building" (0%)
  await build();

  progress.nextStage();      // "Testing" (33%)
  await test();

  progress.nextStage();      // "Deploying" (66%)
  await deploy();

  progress.complete();       // "Deploying" (100%)
}

Structured Error Handling

All error utilities follow the ACIErrorDetail interface with machine-readable codes, human-readable messages, actionable hints, and documentation links. This standardization means developers can handle errors consistently across all ACIs.

Creating helpful errors
import { createDetailedError, formatErrorForUser } from '@private.me/ux-helpers';

const error = createDetailedError(
  'INVALID_PAGE',
  'Page number must be at least 1',
  {
    hint: 'Provide a positive page number (e.g., page: 1)',
    field: 'page',
    docs: 'https://private.me/docs/pagination'
  }
);

console.log(formatErrorForUser(error));
// Page number must be at least 1
// Field: page
// Hint: Provide a positive page number (e.g., page: 1)
// Docs: https://private.me/docs/pagination

Type Safety

Every function includes comprehensive TypeScript types with readonly arrays, strict null checks, and generic type parameters. IDEs provide full autocomplete and inline documentation for all exports.

ZERO CONFIGURATION
All utilities work out of the box with sensible defaults. Pagination defaults to 50 items per page. Search is case-insensitive by default. Progress callbacks are optional. Error formatting works with any error type.
Section 03

The Problem

Without shared UX primitives, every package implements pagination differently, error messages vary wildly in quality, progress reporting is inconsistent, and search behavior is unpredictable.

Pagination chaos. Some packages return arrays, others return objects. Page numbers start at 0 in one package, 1 in another. Total counts are missing. "Next page" logic requires manual calculation.

Error messages are useless. Generic "Error: invalid input" with no context. No hints on how to fix the problem. No documentation links. Developers resort to reading source code to understand what went wrong.

Progress is invisible. Long operations (XorIDA splitting, multi-share reconstruction, batch processing) appear frozen. No way to track completion percentage. No intermediate status updates.

Search is reinvented poorly. Every package implements its own fuzzy matching. Case sensitivity is inconsistent. Field filtering syntax varies. Result limits are hard-coded or missing.

Property Without UX Helpers With UX Helpers
Pagination Every package different Standardized metadata
Error messages Generic, unhelpful Actionable hints + docs
Progress tracking Missing or ad-hoc Consistent callbacks
Search behavior Varies by package Unified interface
Type safety Partial or missing Full TypeScript
Learning curve High (each ACI different) Low (one pattern)

The Old Way

Package A pages start at 0 Package B pages start at 1 Package C no pagination Developer reads docs 3 times Different interface for each ACI

The New Way

Package A uses ux-helpers Package B uses ux-helpers Package C uses ux-helpers UX HELPERS One interface, 100+ ACIs
Section 04

Real-World Use Cases

Six scenarios where UX Helpers delivers consistent developer experience across diverse ACIs.

📄
Registry
Trust Registry Pagination

List 10,000+ registered DIDs with consistent page navigation. Metadata includes total count, current page, and hasNext flag for infinite scroll UIs.

paginate() + PaginatedResult
🔍
Identity
DID Search

Find DIDs by name, email, or scope across federated registries. Case-insensitive fuzzy matching with configurable result limits.

search() + fields + fuzzy
📊
Crypto
XorIDA Progress

Track multi-share splitting and reconstruction. Real-time updates show "Splitting share 2/3" or "Reconstructing from 2 shares..."

ProgressReporter + onProgress
Validation
Helpful Error Messages

Convert cryptic validation failures into actionable guidance. Field attribution, resolution hints, and doc links reduce support burden.

createDetailedError() + formatErrorForUser()
📦
Batch
Batch Processing

Process 1000 envelopes with staged progress: "Encrypting" → "Signing" → "Sending". Users see exactly where they are in the pipeline.

createStagedProgress() + stages[]
📋
Audit
Audit Log Search

Search across millions of audit entries by DID, action, timestamp. Paginated results with search highlighting and total match counts.

search() + paginate() composition
Section 05

Solution Architecture

Four independent modules. Each can be used standalone or composed for powerful UX patterns.

Search
Fuzzy + Multi-Field
Case-insensitive by default
Field-specific matching
Optional result limit
Progress
Real-Time Updates
Single-stage or multi-stage
Percent-based or stage-based
Optional callbacks
Error Formatting
Actionable Messages
Code + message + hint
Field attribution
Documentation links

Pagination

paginate() slices a collection into pages and returns both the slice and metadata. createPaginationMetadata() generates metadata without slicing — useful for server-side pagination where you only return the current page.

Client-side pagination
import { paginate } from '@private.me/ux-helpers';

const allItems = [/* 1000 items */];
const result = paginate(allItems, { page: 2, limit: 20 });

console.log(result.data);              // Items 21-40
console.log(result.pagination.hasNext);  // true
console.log(result.pagination.totalPages); // 50

search() filters a collection based on a query string. Matches across multiple fields with case-insensitive fuzzy matching. Returns the filtered subset.

Multi-field search
import { search } from '@private.me/ux-helpers';

const users = [
  { name: 'Alice', email: 'alice@example.com', role: 'admin' },
  { name: 'Bob', email: 'bob@example.com', role: 'user' },
];

const results = search(users, {
  query: 'alice',
  fields: ['name', 'email'],
  limit: 10
});
// Returns: [{ name: 'Alice', ... }]

Progress Reporting

ProgressReporter class provides start/update/complete methods. createStagedProgress() divides operations into named stages and automatically calculates percentages.

Staged progress for pipelines
import { createStagedProgress } from '@private.me/ux-helpers';

async function processData(onProgress?: ProgressCallback) {
  const progress = createStagedProgress(
    ['Validating', 'Encrypting', 'Uploading'],
    onProgress
  );

  progress.start();       // "Validating" (0%)
  await validate();
  
  progress.nextStage();  // "Encrypting" (33%)
  await encrypt();
  
  progress.nextStage();  // "Uploading" (66%)
  await upload();
  
  progress.complete();   // "Uploading" (100%)
}

Error Formatting

createDetailedError() produces structured errors with machine-readable codes and human-readable messages. formatErrorForUser() and formatErrorForLog() render errors for different audiences.

User-friendly errors
import { createDetailedError, formatErrorForUser } from '@private.me/ux-helpers';

const error = createDetailedError(
  'INVALID_PAGE',
  'Page number must be at least 1',
  {
    hint: 'Page numbers start at 1. Try page: 1 instead.',
    field: 'page',
    docs: 'https://private.me/docs/pagination#page-numbers'
  }
);

// For users:
console.log(formatErrorForUser(error));

// For logs:
console.error(formatErrorForLog(error));
Section 06

Integration

Install once, import anywhere. Works in Node.js, Deno, Bun, Cloudflare Workers, and browsers.

Installation

npm / pnpm / yarn
pnpm add @private.me/ux-helpers

Basic Usage

Import and use
import {
  paginate,
  search,
  ProgressReporter,
  createDetailedError
} from '@private.me/ux-helpers';

// Paginate
const page1 = paginate(items, { page: 1, limit: 50 });

// Search
const results = search(users, { query: 'admin', fields: ['role'] });

// Progress
const progress = new ProgressReporter((status, pct) => {
  console.log(`${status}: ${pct}%`);
});
progress.start('Initializing');
progress.update('Processing', 50);
progress.complete();

// Errors
const error = createDetailedError('INVALID_INPUT', 'Field is required');

CommonJS

Dual ESM/CJS builds support both import and require.

CommonJS usage
const { paginate, search } = require('@private.me/ux-helpers');
ZERO CONFIGURATION
No setup required. Import and call. All defaults are production-ready.
Section 07

Security

UX Helpers is a pure utility library with no cryptographic operations. Security considerations focus on input validation and preventing information leakage through error messages.

Input Validation

Pagination bounds: Page numbers clamped to [1, totalPages]. Limit clamped to [1, 100]. Negative or non-numeric inputs rejected with clear error messages.

Search sanitization: Query strings are not evaluated or executed. Field names are validated against object keys. No regex injection risk — queries are literal string matching.

Error Message Safety

No stack traces in user-facing errors. formatErrorForUser() strips technical details. formatErrorForLog() includes full context for server-side logging only.

Field attribution: Error messages never leak sensitive field values. Only field names are included (e.g., "Field: email" not "Field: alice@example.com").

Progress Callback Isolation

Progress callbacks are optional and never block operations. Callback exceptions are caught and logged, preventing denial-of-service via malicious callback implementations.

CAUTION: CLIENT-SIDE PAGINATION
Client-side pagination loads the entire collection into memory. For large datasets (10,000+ items), use server-side pagination with createPaginationMetadata() to avoid memory exhaustion.
Section 08

Benchmarks

Performance measurements for common operations on realistic dataset sizes.

Operation Dataset Size Latency Throughput
paginate() 100,000 items <1ms Constant time (slice only)
createPaginationMetadata() N/A <0.1ms Pure calculation, no I/O
search() (single field) 10,000 items ~5ms 2,000 items/ms
search() (3 fields) 10,000 items ~12ms 833 items/ms
ProgressReporter.update() N/A <0.01ms Callback execution only
createDetailedError() N/A <0.01ms Object creation only
formatErrorForUser() N/A <0.1ms String formatting only

Memory Usage

<50KB
Bundle size (ESM)
~2KB
Runtime overhead
O(1)
Pagination memory
O(n)
Search memory

Benchmarks run on Node.js v22.0, Intel i7-12700K, 32GB RAM. Measurements via process.hrtime.bigint(). Real-world performance depends on JavaScript engine, dataset characteristics, and garbage collection.

Section 09

Honest Limitations

UX Helpers is intentionally simple. Here's what it doesn't do and when you should choose alternatives.

Pagination

Client-side only by default. paginate() loads the entire collection into memory. For datasets >100,000 items, implement server-side pagination and use createPaginationMetadata() to generate the metadata without slicing.

No cursor-based pagination. Page numbers only. For infinite scroll with stable cursors (e.g., "messages after timestamp X"), implement your own cursor logic.

Search

Linear scan. Search is O(n) over the entire collection. For large datasets (>10,000 items), use a real search engine (Elasticsearch, Meilisearch) or database full-text index.

No stemming, no fuzzy distance. Matching is simple case-insensitive substring search. No Levenshtein distance, no phonetic matching, no query parsing (AND/OR/NOT).

In-memory only. Cannot search across distributed shards or paginated API results. You must fetch all data before searching.

Progress Reporting

Synchronous callbacks only. ProgressCallback is void-returning. Cannot await promises. For async progress sinks (WebSocket, SSE), wrap the callback and queue updates.

No progress persistence. If the process crashes mid-operation, progress is lost. For resumable operations, store progress externally (database, Redis).

Error Formatting

English only. Error messages are hardcoded in English. For internationalization, map error codes to localized strings in your application layer.

No error recovery. This package formats errors but does not provide retry logic, circuit breakers, or automatic fallbacks.

ALTERNATIVES
For advanced use cases: Pagination → database LIMIT/OFFSET or cursor-based. Search → Elasticsearch, Meilisearch. Progress → Bull, Agenda (job queues with persistence). Errors → i18next (internationalization).
Advanced Topics

Appendices

Type definitions, full API surface, error taxonomy, and codebase statistics.

Appendix A1

Type Definitions

Complete TypeScript interfaces for all UX Helpers exports.

Core types
interface PaginationOptions {
  readonly page?: number;     // 1-based, default: 1
  readonly limit?: number;    // default: 50, max: 100
}

interface PaginatedResult<T> {
  readonly data: readonly T[];
  readonly pagination: {
    readonly page: number;
    readonly limit: number;
    readonly total: number;
    readonly totalPages: number;
    readonly hasNext: boolean;
    readonly hasPrev: boolean;
  };
}

interface SearchOptions {
  readonly query: string;
  readonly fields?: readonly string[];  // optional field list
  readonly fuzzy?: boolean;              // default: true
  readonly limit?: number;              // max results
}

type ProgressCallback = (status: string, percent?: number) => void;

interface ACIErrorDetail {
  readonly code: string;         // Machine-readable error code
  readonly message: string;      // Human-readable description
  readonly hint?: string;        // Actionable resolution hint
  readonly field?: string;       // Field that caused the error
  readonly docs?: string;        // Documentation URL
}
Appendix A2

Full API Surface

Complete function signatures organized by module.

Pagination

paginate<T>(items: readonly T[], options?: PaginationOptions) → PaginatedResult<T>

Slice collection into pages and return data + metadata. Client-side pagination.

createPaginationMetadata(total: number, options?: PaginationOptions) → PaginationMetadata

Generate pagination metadata without slicing. For server-side pagination.

Search

search<T>(items: readonly T[], options: SearchOptions) → readonly T[]

Filter collection by query string. Supports multi-field fuzzy matching.

Progress Reporting

new ProgressReporter(callback?: ProgressCallback)

Create progress reporter with optional callback.

report(status: string, percent?: number) → void

Report progress update.

start(status: string) → void

Report start (0%).

update(status: string, percent: number) → void

Update progress to specific percentage.

complete() → void

Report completion (100%).

createStagedProgress(stages: readonly string[], callback?: ProgressCallback)

Create multi-stage progress reporter with automatic percentage calculation.

Error Formatting

createDetailedError(code: string, message: string, options?: ACIErrorOptions) → ACIErrorDetail

Create structured error with code, message, hint, field, and docs URL.

formatErrorForUser(error: ACIErrorDetail) → string

Format error for display to end users. Excludes technical details.

formatErrorForLog(error: ACIErrorDetail) → string

Format error for server-side logging. Includes error code and all fields.

isACIError(error: unknown) → boolean

Type guard to check if an error is ACIErrorDetail.

toACIError(error: unknown) → ACIErrorDetail

Convert any error (Error, string, unknown) to ACIErrorDetail.

Appendix A3

Error Taxonomy

Standard error codes returned by UX Helpers utilities.

Code Module When
INVALID_PAGEPaginationPage number < 1 or non-numeric
INVALID_LIMITPaginationLimit < 1, > 100, or non-numeric
EMPTY_QUERYSearchSearch query is empty string
INVALID_FIELDSearchField does not exist on objects
INVALID_PERCENTProgressPercent < 0 or > 100
NO_STAGESProgressStage array is empty
STAGE_OVERFLOWProgressnextStage() called beyond final stage
INVALID_ERROR_CODEErrorsError code is empty or whitespace-only
MISSING_MESSAGEErrorsError message is empty
Appendix A4

Codebase Stats

UX Helpers v0.1.0 — lightweight, well-tested, zero dependencies.

6
Source files
4
Test files
101
Tests passing
1
dependency

Module Inventory

Module Source File Purpose
Paginationpagination.tspaginate() + createPaginationMetadata()
Searchsearch.tsMulti-field fuzzy search
Progressprogress.tsProgressReporter + createStagedProgress()
Errorserrors.tscreateDetailedError() + format helpers
Typestypes.tsShared TypeScript interfaces
Indexindex.tsBarrel exports

Usage Across Platform

UX Helpers is integrated into 100+ ACIs across the PRIVATE.ME platform. Every package with pagination, search, or long-running operations uses these shared primitives to deliver consistent developer experience.

UNIVERSAL ADOPTION
Used by: Xlink, Xprove, Xpass, Xcompute, Xlock, Xstore, Xwallet, Xid, Xchange, Xredact, Xboot, Xfuse, Xghost, xGit, Xgate, and 85+ more packages.

Deployment Options

📦

SDK Integration

Embed directly in your application. Runs in your codebase with full programmatic control.

  • npm install @private.me/ux-helpers
  • TypeScript/JavaScript SDK
  • Full source access
  • Enterprise support available
Get Started →
🏢

On-Premise Upon Request

Enterprise CLI for compliance, air-gap, or data residency requirements.

  • Complete data sovereignty
  • Air-gap capable deployment
  • Custom SLA + dedicated support
  • Professional services included
Request Quote →

Enterprise On-Premise Deployment

While UX Helpers is primarily delivered as SaaS or SDK, we build dedicated on-premise infrastructure for customers with:

  • Regulatory mandates — HIPAA, SOX, FedRAMP, CMMC requiring self-hosted processing
  • Air-gapped environments — SCIF, classified networks, offline operations
  • Data residency requirements — EU GDPR, China data laws, government mandates
  • Custom integration needs — Embed in proprietary platforms, specialized workflows

Includes: Enterprise CLI, Docker/Kubernetes orchestration, RBAC, audit logging, and dedicated support.

Contact sales for assessment and pricing →