Skip to content

SubstrateSubclass-first TypeScript primitives.

A subclass-first toolkit of TypeScript primitives: retry, throttle, mutex, scheduler, clock, context, pipeline, logger, errors, json, and more. Every class is a usable primitive and an extension base.

Substrate

Stateful primitives

@studnicky/batchBatch concurrent execution for processing items in controlled parallel groups.@studnicky/boundary-kitComposes throttle, resilience, and retry into a fixed-order boundary call pattern.@studnicky/bounded-dispatcherComposes concurrency's Semaphore, event-bus, and scheduler into a bounded work dispatch pattern.@studnicky/cacheIn-process LRU cache with optional TTL and capacity eviction.@studnicky/circular-bufferGeneric ring buffer with O(1) push and shift operations.@studnicky/clockWall-clock and monotonic time with injectable providers for deterministic testing.@studnicky/concurrencyAsync concurrency primitives: channels, semaphores, coalescing, and iterable utilities.@studnicky/contextPer-request async context isolation using AsyncLocalStorage.@studnicky/entity-storeNormalized, ID-indexed entity collection with CRUD operations and O(1) lookup.@studnicky/event-busTyped multi-topic pub/sub with per-subscriber backpressure queues.@studnicky/file-lockProcess-level advisory file locking for CLI tools and daemons.@studnicky/flag-evaluatorLocal deterministic feature-flag evaluation with percentage rollout and observability hooks.@studnicky/fsmAbstract finite state machine with async effect dispatch and singleton registry.@studnicky/health-registryNamed async health-check registry with worst-status-wins aggregation.@studnicky/idempotency-guardIdempotency key guard that dedupes concurrent calls, replays cached results within a TTL window, and rejects key reuse with a different payload.@studnicky/keyed-rate-limiterPer-key rate limiting that lazily creates one rate-limiting strategy per key, evicting idle keys via LRU+TTL.@studnicky/keyed-work-gateKeyed single-flight and serialized work gate composing mutex and concurrency's Coalesce.@studnicky/loggerPluggable logging with transport architecture, child loggers, and structured builders.@studnicky/memoizePure function memoization with LRU+TTL result caching keyed by a caller-supplied key derivation, and in-flight call dedup.@studnicky/mutexKey-based async mutual exclusion with queue and timeout support.@studnicky/paginatorCursor/page-list state tracker for paginated data sources.@studnicky/pipelineGeneric typed async pipeline for sequential context transforms.@studnicky/process-kitReducer-with-effects process pattern composing fsm, scheduler, and signal.@studnicky/request-executorOne-shot request execution pattern composing fetch, retry, signal, timing, and context.@studnicky/resilienceComposable resilience primitives: circuit breaker, token bucket, and dead-letter queue.@studnicky/retryGeneric async retry with extensible error classification and backoff strategies.@studnicky/sample-bufferFixed-capacity numeric sample buffer with percentile calculation.@studnicky/schedulerReal-time and virtual scheduler primitives for deterministic testing.@studnicky/sliding-window-limiterSliding-window rate limiter using an exact timestamp-log or approximate blended-counter algorithm.@studnicky/throttleSliding-window concurrency throttle with adaptive limits and abort support.@studnicky/timingHigh-resolution operation timing tracker using process.hrtime.bigint().@studnicky/visible-rangePure index/offset arithmetic for computing the visible item range of a virtualized list.@studnicky/worker-poolBounded worker_threads pool that fans work items across workers with a typed message envelope and per-task timeout.

Stateless utilities

ESLint Plugins

Configuration rules

@studnicky/all-types-are-entitiesDisallows free-standing type aliases outside entity namespaces.@studnicky/constants-folder-requiredRequires files with more than one top-level const declaration to live under a constants/ folder.@studnicky/entity-namespaceEntity files must export a namespace with Schema as const, type Type derived via FromSchema, and a validate type guard.@studnicky/interface-must-be-contractInterfaces express runtime contracts. Pure data shapes — every member JSON-serializable — must be schema-derived type aliases.@studnicky/interface-suffixRequires every interface declaration's name to end with 'Interface'.@studnicky/interfaces-compose-named-typesDisallows inline object-literal types inside interface bodies.@studnicky/no-bind-apply-callDisallows .bind(), .call(), and .apply() on callable receivers.@studnicky/no-export-aliasDisallows aliased exports and any non-index re-export path.@studnicky/no-freestanding-verb-nounDisallows freestanding verbNoun functions at module scope.@studnicky/no-prefer-existing-typeDisallows locally declared object types that duplicate or are subsumed by an imported type.@studnicky/no-project-internal-acronymsDisallows internal shorthand identifiers (cb, dlq, cfg, opts, ctx, idx, etc.) in favour of descriptive names.@studnicky/no-readonly-in-data-typeForbids readonly modifiers baked into exported type alias data definitions. Detection is type-checker driven; consumers declare immutability at the use site.@studnicky/no-suppression-commentsDisallows all lint and type suppression comments.@studnicky/no-this-aliasDisallows assigning this to a variable or binding it via assignment.@studnicky/no-trivial-shimDisallows wrapper functions that only forward or delegate a value without adding logic.@studnicky/no-type-aliasingDisallows naked type re-aliases, generic forwarding shims, and import aliases that hide canonical names.@studnicky/no-underscore-privateDisallows underscore-prefixed class members; use real #private fields/methods instead.@studnicky/prefer-collection-typesPrefers Set/Map over arrays and POJOs for membership tests and keyed lookups.@studnicky/require-options-objectRequires functions with two or more optional parameters to collect them into a trailing options object.@studnicky/single-exportRequires each non-index file to export exactly one named symbol matching the filename, except for exempt directories and constrained enum files.@studnicky/type-alias-must-end-typeRequires exported type aliases to end in Type.@studnicky/types-derived-from-schemaDisallows inline object-literal type aliases; requires data shapes to be derived from JSON Schema.

V8 performance rules

@studnicky/v8/arguments-objectDisallows the arguments object in functions.@studnicky/v8/array-from-iteratorsDisallows Array.from on non-array iterators in hot paths.@studnicky/v8/array-from-map-callbackDisallows the two-argument Array.from(iterable, mapFn) form.@studnicky/v8/computed-class-propertiesDisallows computed property keys in class bodies.@studnicky/v8/computed-object-propertiesDisallows computed property keys in object literals.@studnicky/v8/conditional-property-assignmentDisallows conditional this-property assignment inside a constructor.@studnicky/v8/define-propertyDisallows Object.defineProperty.@studnicky/v8/delete-propertyDisallows the delete operator on object properties.@studnicky/v8/dynamic-property-accessDisallows computed member access inside an object literal.@studnicky/v8/eval-functionDisallows eval().@studnicky/v8/for-in-loopsDisallows for...in loops.@studnicky/v8/for-of-arraysDisallows for...of over arrays; prefer index loops.@studnicky/v8/inline-arrow-functionsDisallows inline multi-statement arrow functions in a dispatch map rebuilt on every call.@studnicky/v8/inline-functionsDisallows inline function expressions in a dispatch map rebuilt on every call.@studnicky/v8/max-switch-casesRequires a dispatch map once a switch statement reaches 20 non-default cases.@studnicky/v8/memoize-array-lengthDisallows re-reading array.length in a for-loop test on every iteration.@studnicky/v8/no-concat-in-loopsDisallows Array.concat inside for loops.@studnicky/v8/no-spread-in-loopsDisallows array spread assignments inside for loops.@studnicky/v8/object-spreadDisallows object spread inside a constructor.@studnicky/v8/prototype-modificationDisallows assigning to .prototype after class definition.@studnicky/v8/regexp-in-loopsDisallows RegExp construction inside loop bodies.@studnicky/v8/switch-statementsDisallows block statement bodies in switch cases.@studnicky/v8/try-catch-in-loopsDisallows try-catch blocks inside loop bodies.@studnicky/v8/with-statementDisallows with statements.

Substrate is built around three principles that make every primitive safe to subclass and safe to use as a bare instantiation:

Subclass-first seams. Public methods delegate to documented protected seams with no-op defaults where observation is needed. Subclass and override only what you need; no base class changes are required.

No observability in bare classes. The base class never logs, never emits metrics, never references a logger. Protected hooks are the extension points; observability lives in subclasses or decorators. Observer hooks stay observational; behavioral hooks are documented where they intentionally participate in control flow.

No exported singletons. Every stateful class is new-able and injectable. Static helpers are pure-static utility classes with no module-level state.

Every primitive exposes a protected hook at each observable stage, so you can inject tracing and metrics by subclassing. See Lifecycle Hooks for the full convention and a per-package map.