npm package: @sovereignbase/sharding
Description: Deterministic shard-index derivation for string and byte inputs.
Latest version: 1.0.0

[![npm version](https://img.shields.io/npm/v/@sovereignbase/sharding)](https://www.npmjs.com/package/@sovereignbase/sharding)
[![CI](https://github.com/sovereignbase/sharding/actions/workflows/ci.yaml/badge.svg?branch=master)](https://github.com/sovereignbase/sharding/actions/workflows/ci.yaml)
[![codecov](https://codecov.io/gh/sovereignbase/sharding/branch/master/graph/badge.svg)](https://codecov.io/gh/sovereignbase/sharding)
[![license](https://img.shields.io/npm/l/@sovereignbase/sharding)](LICENSE)

# sharding

Deterministic shard-index derivation for string and byte inputs. Use it when every caller must route the same payload into the same shard without shared state, caches, or runtime-local coordination.

## Compatibility

- Runtimes: Node >= 20; Browsers: modern browsers with `crypto.subtle` and `TextEncoder`; Workers/Edge: runtimes with `crypto.subtle`, `TextEncoder`, and `BigInt`.
- Module format: ESM and CJS.
- Required globals / APIs: `crypto`, `crypto.subtle`, `TextEncoder`, `BigInt`.
- TypeScript: bundled types. `ShardingErrorCode` is exported as a type; the runtime error class is intentionally not public API.

## Goals

- Deterministic routing from the same input and shard count.
- Byte-oriented behavior with support for strings and normalized `ByteSource` inputs.
- Small public API surface: one runtime function, one exported error-code type.
- No hidden state, caches, or environment-specific routing behavior.
- Consistent results across Node, Bun, Deno, browsers, Cloudflare Workers, and edge runtimes.

## Installation

```sh
npm install @sovereignbase/sharding
# or
pnpm add @sovereignbase/sharding
# or
yarn add @sovereignbase/sharding
# or
bun add @sovereignbase/sharding
# or
deno add jsr:@sovereignbase/sharding
# or
vlt install jsr:@sovereignbase/sharding
```

## Usage

### String input

```ts
import { shardIndexFor } from '@sovereignbase/sharding'

const shards = ['s0', 's1', 's2', 's3', 's4', 's5', 's6', 's7']

const index = await shardIndexFor('alpha', shards.length)
const shard = shards[index]

console.log(index) // 5
console.log(shard) // "s5"
```

### Byte input

```ts
import { fromJSON } from '@sovereignbase/bytecodec'
import { shardIndexFor } from '@sovereignbase/sharding'

const payload = fromJSON({ ok: true })
const index = await shardIndexFor(payload, 8)

console.log(index) // 0
```

### Validation errors

```ts
import { shardIndexFor, type ShardingErrorCode } from '@sovereignbase/sharding'

try {
  await shardIndexFor('alpha', 0)
} catch (error) {
  const code = (error as { code?: ShardingErrorCode }).code

  if (code === 'SHARD_COUNT_INVALID') {
    console.error('Shard count must be a positive integer.')
  }
}
```

## Runtime behavior

### Node

Uses the host WebCrypto implementation via `globalThis.crypto.subtle.digest`.

### Browsers / Edge runtimes / Workers

Uses the same `crypto.subtle.digest('SHA-512', ...)` flow as Node, so routing remains deterministic across tested hosts.

### Validation & errors

Invalid `shardsLength` values throw an error with:

- `name`: `ShardingError`
- `code`: `SHARD_COUNT_INVALID`
- `message`: `@sovereignbase/sharding shardsLength must be a positive integer`

`ShardingErrorCode` is public as a type for tooling and IntelliSense. The `ShardingError` class itself is internal.

### State & caching

The package is stateless. It does not cache inputs, hashes, or shard mappings.

## Tests

Suite: unit + integration (Node), E2E across runtimes

Matrix:

- Node ESM and CJS
- Bun ESM and CJS
- Deno ESM
- Cloudflare Workers ESM via local Wrangler dev
- Edge Runtime ESM
- Playwright browsers: Chromium, Firefox, WebKit, Pixel 5 emulation, iPhone 12 emulation

Coverage: `c8` — 100% statements / branches / functions / lines

Latest verified local run:

- `npm test`
- Node v22.14.0 (`win32 x64`)
- Bun 1.3.10
- Deno 2.7.7

## Benchmarks

How it was run: `node benchmark/bench.js`

Environment: Node v22.14.0 (`win32 x64`)

Results:

| Benchmark    | Result                              |
| ------------ | ----------------------------------- |
| string short | 7,579 ops/s (0.132 ms/op, 2000 ops) |
| string long  | 6,229 ops/s (0.161 ms/op, 2000 ops) |
| bytes json   | 9,712 ops/s (0.103 ms/op, 2000 ops) |
| bytes raw    | 9,539 ops/s (0.105 ms/op, 2000 ops) |

Results vary by machine.

## License

Apache-2.0