A TypeScript utility library providing async primitives, cancellation patterns, buffers, and crypto helpers. Published on JSR for Deno.
deno add jsr:@rdtlabs/ts-utilsOr import directly:
import { Mutex } from "jsr:@rdtlabs/ts-utils/async";npx jsr add @rdtlabs/ts-utilspnpm i jsr:@rdtlabs/ts-utilsyarn add jsr:@rdtlabs/ts-utilsbunx jsr add @rdtlabs/ts-utilsConcurrency patterns inspired by Go, Java, and C#:
- Synchronization:
Mutex,Semaphore,WaitGroup,Signal - Task Execution:
WorkerPool,JobPool,executor,executors - Reactive Streams:
Flowable,FlowProcessor,FlowPublisher - Promise Utilities:
Task,Deferred,Promises,delay - Adapters:
fromEvent,fromObservable,fromAsyncIterable,fromIterableLike - Queues: Async queue implementations
import { Mutex, Semaphore, WaitGroup } from "@rdtlabs/ts-utils/async";
const mutex = new Mutex();
await mutex.acquire();
try {
// critical section
} finally {
mutex.release();
}C#-inspired cancellation pattern for async operations:
CancellationToken- Token with states:active,cancelled,noneCancellationController- Create and manage cancellation tokensCancellationError- Error thrown when operations are cancelledcancellablePromise,cancellableIterable- Wrap operations with cancellation support
import { CancellationToken } from "@rdtlabs/ts-utils/cancellation";
const controller = CancellationToken.create();
const token = controller.token;
// Register a callback
token.register(() => console.log("Cancelled!"));
// Convert to AbortSignal for fetch, etc.
const signal = token.toAbortSignal();
// Cancel the token
controller.cancel();Buffers for adapting unbounded push to pull-based iteration:
Buffer- Standard buffer implementationRingBuffer- Fixed-size circular bufferBufferStrategy- Controls overflow behavior (drop, keep latest, throw, keep all)
import { RingBuffer } from "@rdtlabs/ts-utils/buffer";
const buffer = new RingBuffer<number>(10);
buffer.push(1);
const value = buffer.shift();Simplified encryption/decryption using Web Crypto API:
Secret- Manage encryption with password/secretencryptOnce,decryptOnce- One-shot encryption/decryption
import { Secret } from "@rdtlabs/ts-utils/crypto";
const secret = await Secret.from("my-password");
const encrypted = await secret.encrypt("sensitive data");
const decrypted = await secret.decrypt(encrypted);Base64 and hex encoding/decoding:
import { base64Encode, base64Decode, hexEncode, hexDecode } from "@rdtlabs/ts-utils/encoding";
const encoded = base64Encode(new Uint8Array([1, 2, 3]));
const decoded = base64Decode(encoded);Utilities for detecting and handling transient errors:
import { isTransientError } from "@rdtlabs/ts-utils/errors";
try {
await fetchData();
} catch (error) {
if (isTransientError(error)) {
// Retry logic
}
}Persistent, immutable Set and Map implementations with a builder pattern. All mutation operations return new instances, leaving the original unchanged.
ImmutableSet<T>- Immutable set withadd,delete,map,filter,intersect, and ES2024 set operationsImmutableMap<K, V>- Immutable map withset,delete,merge,map,filter- Builder pattern for efficient batch construction
import { ImmutableSet, ImmutableMap } from "@rdtlabs/ts-utils/collections";
const set = ImmutableSet.of([1, 2, 3]);
const withFour = set.add(4); // new set: {1, 2, 3, 4}
console.log(set.size); // 3 (original unchanged)
const map = ImmutableMap.builder<string, number>()
.set("a", 1)
.set("b", 2)
.build();
const updated = map.set("c", 3); // new map with entry addedImmutable, branded value objects inspired by DDD. Enforces a max 3-level nesting hierarchy: CompositeValueObject → ValueObject → ValuePrimitive. Exported as VO for convenience.
VO.object(props)- Create a flat value object (primitives only)VO.composite(props)- Create a composite containing flat value objectsVO.map(entries)/VO.set(items)- Branded immutable collections of value objectsVO.parseObject(json)/VO.parseComposite(json)- Parse from JSONVO.isValueObject(),VO.isFlat(),VO.isComposite()- Type guardsBranded<T, B>- Nominal typing for primitives
import { VO } from "@rdtlabs/ts-utils/value";
import type { ValueObject, CompositeValueObject, Branded } from "@rdtlabs/ts-utils/value";
type UserId = Branded<string, "UserId">;
type Address = ValueObject<{
street: string;
city: string;
zip: string;
}>;
type Person = CompositeValueObject<{
name: string;
address: Address;
pastAddresses: readonly Address[];
}>;
const address = VO.object<Address>({ street: "123 Main", city: "Springfield", zip: "62704" });
const person = VO.composite<Person>({ name: "Alice", address, pastAddresses: [] });- Deno runtime
# Run tests
deno test src/
# Run a single test file
deno test src/path/to/file.test.ts
# Lint
deno lint
# Format
deno fmt
# Type check
deno checkMIT License - see LICENSE for details.