lseq/typescript
2025-12-12 21:45:24 -08:00
..
src feat: conformance tests pass for first time 2025-12-12 21:05:31 -08:00
.npmignore feat: experiment with different implementations of LSEQ 2025-07-08 16:49:52 -07:00
package.json feat: prepare for publishing npm package 2025-12-12 21:45:24 -08:00
publish.sh feat: prepare for publishing npm package 2025-12-12 21:45:24 -08:00
README.md feat: experiment with different implementations of LSEQ 2025-07-08 16:49:52 -07:00
tsconfig.json feat: experiment with different implementations of LSEQ 2025-07-08 16:49:52 -07:00

@peoplesgrocers/lseq

TypeScript implementation of the L-SEQ algorithm for fractional indexing and list CRDTs.

Installation

npm install @peoplesgrocers/lseq

Usage

import { LSEQ, compareLSEQ } from '@peoplesgrocers/lseq';

// Create a new L-SEQ instance
const lseq = new LSEQ();

// Allocate identifiers
const id1 = lseq.alloc(null, null);        // First identifier
const id2 = lseq.alloc(id1, null);         // After id1
const id3 = lseq.alloc(id1, id2);          // Between id1 and id2

// Sort identifiers
const ids = [id3, id1, id2];
ids.sort(compareLSEQ);
console.log(ids); // [id1, id3, id2] - properly ordered

// Custom random function (useful for deterministic testing)
const deterministicLSEQ = new LSEQ(() => 0.5);

API

LSEQ

constructor(random?: () => number)

Creates a new L-SEQ instance.

  • random: Optional custom random function (defaults to Math.random)

alloc(before: string | null, after: string | null): string

Allocates a new identifier between two existing identifiers.

  • before: The identifier that should come before the new one (or null for beginning)
  • after: The identifier that should come after the new one (or null for end)
  • Returns: A new identifier that sorts between before and after

compareLSEQ(a: string, b: string): number

Compares two L-SEQ identifiers for sorting.

  • Returns: -1 if a < b, 1 if a > b, 0 if a === b

How it works

L-SEQ generates identifiers using a base-64 alphabet that maintains lexicographic ordering. Each identifier is a sequence of characters from this alphabet, and new identifiers are generated by finding space between existing ones at different depths.

The algorithm uses alternating allocation strategies (bias toward min or max) at different depths to avoid degenerative cases and maintain good performance characteristics.