@energy8platform/stake-math-tools 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +223 -56
- package/package.json +1 -1
- package/src/index.ts +13 -0
- package/src/optimize-lookup.ts +174 -19
- package/src/stake-report.ts +145 -0
- package/src/tiered.ts +1832 -0
- package/src/transform-jsonl-zst.ts +285 -0
- package/src/types.ts +141 -0
- package/test/optimize-lookup.integration.test.ts +423 -0
- package/test/optimize-lookup.unit.test.ts +2 -0
- package/test/transform-jsonl-zst.test.ts +343 -0
package/README.md
CHANGED
|
@@ -1,30 +1,88 @@
|
|
|
1
1
|
# @energy8platform/stake-math-tools
|
|
2
2
|
|
|
3
|
-
Node-only dev-time utilities for building [Stake Engine](https://stake-engine.com/docs) **lookup tables (force matrices)** from raw simulation output. Companion to [`@energy8platform/stake-bridge`](../stake-bridge).
|
|
3
|
+
Node-only dev-time utilities for building [Stake Engine](https://stake-engine.com/docs) **lookup tables (force matrices)** from raw simulation output. Compresses millions of source simulations into a small weighted table that passes Stake's publish-time validation gates (Liability Limits, Gaps in Hit Rate Table, Unique Events). Companion to [`@energy8platform/stake-bridge`](../stake-bridge).
|
|
4
4
|
|
|
5
5
|
## Why
|
|
6
6
|
|
|
7
|
-
Stake Engine games ship a pre-built weighted lookup table: each row is `(
|
|
7
|
+
Stake Engine games ship a pre-built weighted lookup table: each row is `(sim_id, weight, payout_cents)` and the RGS samples a row at runtime to decide each round's outcome. The math team's job is to compress millions of raw simulations down to a much smaller weighted table whose aggregate distribution still hits the design's target **RTP / volatility / hit-rate** under a hard `capMaxWin` ceiling, **and** passes Stake's risk-management checks.
|
|
8
8
|
|
|
9
9
|
This package does that compression in one call.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Two algorithms, one entry point
|
|
12
12
|
|
|
13
13
|
```
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
optimizeLookupTable(rows, params)
|
|
15
|
+
│
|
|
16
|
+
├─ algorithm: 'tiered' (default, recommended for Stake)
|
|
17
|
+
│ └─ tier rows by payout magnitude; cap+large rows get weight 1;
|
|
18
|
+
│ small rows get weight W calibrated to preserve cap rate.
|
|
19
|
+
│ Three refinement passes — composition (hit-rate),
|
|
20
|
+
│ RTP-aware partition (mean), Σ-preserving 2-swap (variance).
|
|
21
|
+
│ Stake-Liability-safe by design.
|
|
22
|
+
│
|
|
23
|
+
└─ algorithm: 'nnls' (legacy, exact target-fitting)
|
|
24
|
+
└─ Lawson–Hanson NNLS over sampled candidates.
|
|
25
|
+
Hits RTP/CV/hit-rate exactly but tends to concentrate
|
|
26
|
+
weight on few rows — typically fails Stake's
|
|
27
|
+
"Within Liability Limits" check on volatile games.
|
|
23
28
|
```
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
The default is `'tiered'`. Pick `'nnls'` only when Stake-compatibility is not a concern (custom RGS, internal tooling, etc.).
|
|
26
31
|
|
|
27
|
-
|
|
32
|
+
## Architecture (tiered, default)
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
raw simulations (1M–10M rows) lookup table (10K–100K rows)
|
|
36
|
+
│ ▲
|
|
37
|
+
▼ │
|
|
38
|
+
filter (payout ≤ capMaxWin) │
|
|
39
|
+
│ │
|
|
40
|
+
▼ │
|
|
41
|
+
classify by payout multiplier: │
|
|
42
|
+
cap (pm ≥ capPmThreshold) weight = 1 │
|
|
43
|
+
large (largePm ≤ pm < cap) weight = 1 ◄── rare │
|
|
44
|
+
small (zero + bulk) weight = W │
|
|
45
|
+
│ │
|
|
46
|
+
▼ │
|
|
47
|
+
sample composition biased by targetHitRate │
|
|
48
|
+
(n_nonzero / n_zero proportion in small tier) │
|
|
49
|
+
│ │
|
|
50
|
+
▼ │
|
|
51
|
+
RTP-aware partition of non-zero small: │
|
|
52
|
+
solve n_high·μ_high + n_low·μ_low = n_B · μ_target │
|
|
53
|
+
then stratified log-payout sample within each side │
|
|
54
|
+
│ │
|
|
55
|
+
▼ │
|
|
56
|
+
refineRtpBySwap — single-row in↔out swaps close the residual │
|
|
57
|
+
RTP gap within toleranceRTP budget │
|
|
58
|
+
│ │
|
|
59
|
+
▼ │
|
|
60
|
+
refineCvBySwap — Σ-preserving 2-swaps adjust Σ payout² toward │
|
|
61
|
+
target without disturbing the RTP we just │
|
|
62
|
+
achieved (Σ-drift bounded by toleranceRTP) │
|
|
63
|
+
│ │
|
|
64
|
+
▼ │
|
|
65
|
+
fillStakeRangeGaps — for each Stake distribution range up to │
|
|
66
|
+
maxPayout that's empty but source has rows,│
|
|
67
|
+
swap in a source row. Prevents "Gaps in │
|
|
68
|
+
the Hit Rate Table" rejection. │
|
|
69
|
+
│ │
|
|
70
|
+
▼ │
|
|
71
|
+
diversifyPayouts — if uniqueEvents < minUniqueEventsRate × │
|
|
72
|
+
nRowsOut, swap duplicate-payout rows for │
|
|
73
|
+
source rows with new payout values until │
|
|
74
|
+
target unique count reached or RTP budget │
|
|
75
|
+
exhausted. Prevents "Insufficient Unique │
|
|
76
|
+
Events" rejection. │
|
|
77
|
+
│ │
|
|
78
|
+
▼ │
|
|
79
|
+
W = n_high·(1 − target_cap_rate) / (n_small · target_cap_rate) │
|
|
80
|
+
│ │
|
|
81
|
+
▼ │
|
|
82
|
+
compute stakeReport (top-K, distribution, unique events) ───────┘
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Determinism is preserved through a single `seed` parameter that threads every RNG call.
|
|
28
86
|
|
|
29
87
|
## Install
|
|
30
88
|
|
|
@@ -36,77 +94,186 @@ The package is a monorepo workspace member; consumers inside the repo just impor
|
|
|
36
94
|
import { optimizeLookupTable, type LookupRow } from '@energy8platform/stake-math-tools';
|
|
37
95
|
|
|
38
96
|
// 1. Parse simulation dump (CSV → array). No CSV parser is included on purpose —
|
|
39
|
-
// the math team's pipeline already has one. The input is just
|
|
97
|
+
// the math team's pipeline already has one. The input is just Iterable<LookupRow>.
|
|
40
98
|
const rows: LookupRow[] = parseCsv('./sim_output.csv');
|
|
41
99
|
|
|
42
|
-
// 2. Compress
|
|
100
|
+
// 2. Compress.
|
|
43
101
|
const result = optimizeLookupTable(rows, {
|
|
44
|
-
targetRTP: 0.96, toleranceRTP: 0.
|
|
45
|
-
targetCV: 8.0, toleranceCV: 0
|
|
102
|
+
targetRTP: 0.96, toleranceRTP: 0.005,
|
|
103
|
+
targetCV: 8.0, toleranceCV: 1.0,
|
|
46
104
|
targetHitRate: 0.30, toleranceHitRate: 0.01,
|
|
47
|
-
capMaxWin: 5_000_000, // payout cents (50000.00x)
|
|
48
|
-
nRowsOut:
|
|
105
|
+
capMaxWin: 5_000_000, // payout cents (50000.00x bet)
|
|
106
|
+
nRowsOut: 100_000,
|
|
107
|
+
|
|
108
|
+
// Stake-tuning knobs (recommended for production):
|
|
109
|
+
largePmThreshold: 50, // pm ≥ 50 → large tier (weight=1). Lower = lower concentration,
|
|
110
|
+
// slower convergence. 50–500 is a typical range.
|
|
49
111
|
});
|
|
50
112
|
|
|
51
|
-
// 3. Inspect
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
console.log(result.
|
|
113
|
+
// 3. Inspect.
|
|
114
|
+
console.log(result.achieved); // { rtp, cv, hitRate, maxPayout, totalWeight }
|
|
115
|
+
console.log(result.toleranceMet); // booleans per target
|
|
116
|
+
console.log(result.maxRowRtpShare); // top-1 RTP share — Stake Liability indicator
|
|
117
|
+
console.log(result.stakeReport); // full Stake-style report (see below)
|
|
118
|
+
if (result.warnings.length) console.warn(result.warnings);
|
|
56
119
|
|
|
57
|
-
// 4. Write rows out in the format Stake expects
|
|
58
|
-
writeCsv('./
|
|
120
|
+
// 4. Write rows out in the format Stake expects: (sim_id, weight, payoutCents)
|
|
121
|
+
writeCsv('./lookUpTable_BASE_0.csv', result.rows);
|
|
59
122
|
```
|
|
60
123
|
|
|
61
124
|
## Public API
|
|
62
125
|
|
|
63
126
|
| Export | Purpose |
|
|
64
127
|
|---|---|
|
|
65
|
-
|
|
|
128
|
+
| **`optimizeLookupTable(rows, params)`** | Main entry. Dispatches to tiered or nnls. |
|
|
129
|
+
| `buildTieredLookup(rows, params)` | Tier-based algorithm directly (bypasses dispatcher). |
|
|
130
|
+
| `computeStakeReport(rows, achieved, betCostCents)` | Compute Stake-style report from a built table. |
|
|
131
|
+
| `detectHitRateGaps(distribution)` | Find intermediate empty buckets in the hit-rate table. |
|
|
66
132
|
| `computeMetrics(rows)` | Weighted RTP / CV / hit-rate / maxPayout. BigInt-safe accumulators. |
|
|
67
|
-
| `bucketize(rows, opts)` | Zero / log-spaced / near-max partition. |
|
|
133
|
+
| `bucketize(rows, opts)` | Zero / log-spaced / near-max payout partition. |
|
|
68
134
|
| `mulberry32(seed)` | Tiny deterministic PRNG. |
|
|
69
135
|
| `weightedReservoirSample(indices, weights, k, rng)` | Algorithm A-Res. |
|
|
70
|
-
| `computeQuotas(buckets, params)` | Min-per-bucket + variance-proportional distribution. |
|
|
71
|
-
| `stratifiedSample(buckets, rows, quotas, rng)` | Apply quotas via A-Res, dedupe overlaps. |
|
|
72
136
|
| `solveNNLS(A, b, opts?)` | Lawson–Hanson NNLS with Tikhonov regularization. |
|
|
137
|
+
| `solveQP(A, b, opts)` | FISTA + simplex projection (alternative QP solver). |
|
|
73
138
|
| `quantizeWeights(weights, total)` | Largest-remainder, `wᵢ ≥ 1`, exact `Σ = total`. |
|
|
74
139
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
Full types in [`src/types.ts`](./src/types.ts).
|
|
140
|
+
Full types in [`src/types.ts`](./src/types.ts). Internal helpers (`lawsonHansonNNLS`, `solveLS`, …) are not exported.
|
|
78
141
|
|
|
79
142
|
## `optimizeLookupTable(rows, params)`
|
|
80
143
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
|
84
|
-
|
|
85
|
-
| `
|
|
86
|
-
| `
|
|
87
|
-
| `
|
|
88
|
-
| `
|
|
89
|
-
| `
|
|
90
|
-
| `
|
|
91
|
-
| `
|
|
92
|
-
| `
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
144
|
+
### Required
|
|
145
|
+
|
|
146
|
+
| Param | Type | Description |
|
|
147
|
+
|---|---|---|
|
|
148
|
+
| `targetRTP` | `number` | LUT-RTP target (`Σ(w·payout) / (Σw · betCostCents)`). E.g. `0.96`. For buy-bonus modes, set to `gameRtp × cost`. |
|
|
149
|
+
| `toleranceRTP` | `number` | Tight tolerance drives refinement-loop precision. E.g. `0.001`. |
|
|
150
|
+
| `targetCV` | `number` | Coefficient of variation (volatility). |
|
|
151
|
+
| `toleranceCV` | `number` | Exits CV refinement when gap drops below this. |
|
|
152
|
+
| `targetHitRate` | `number` | Fraction of weighted output landing on `payout > 0`. |
|
|
153
|
+
| `toleranceHitRate` | `number` | |
|
|
154
|
+
| `capMaxWin` | `number` | Hard cap in payout cents. Rows above are dropped. |
|
|
155
|
+
| `nRowsOut` | `number` | Exact output row count. |
|
|
156
|
+
|
|
157
|
+
### Tier-based knobs (recommended for Stake)
|
|
158
|
+
|
|
159
|
+
| Param | Default | Description |
|
|
160
|
+
|---|---|---|
|
|
161
|
+
| `algorithm` | `'tiered'` | `'tiered'` or `'nnls'`. |
|
|
162
|
+
| `capPmThreshold` | `0.95 × maxPm` | pm ≥ this → cap tier (weight 1). |
|
|
163
|
+
| `largePmThreshold` | `undefined` | pm in `[largePm, cap)` → large tier (weight 1). Set this to **lower the top-K RTP share** and improve Stake-Liability margin. Typical: 50–500. |
|
|
164
|
+
| `largeTarget` | natural rate | Effective P(cap+large) in output. Override with Stake's per-tier limits if needed. |
|
|
165
|
+
| `betCostCents` | `100` | Bet cost (1 bet = 100 cents). Used for pm = payoutCents / betCostCents. |
|
|
166
|
+
| `ensureRangeCoverage` | `true` | Run a 4th refinement pass that guarantees every Stake distribution range up to actual maxPayout has ≥ 1 output row when source has rows in it. Prevents "Gaps in the Hit Rate Table" rejection. Set to `false` to disable. |
|
|
167
|
+
| `minUniqueEventsRate` | `0.01` | Minimum fraction of `nRowsOut` that must be distinct `payoutCents` values. Stake rejects "Insufficient Unique Events" when too few outcomes exist. 100K output → ≥1K unique. 300K → ≥3K. Set to `0` to disable. When source can't supply enough new payouts, optimizer maximizes under budget and emits a warning. |
|
|
168
|
+
|
|
169
|
+
### Output sizing
|
|
170
|
+
|
|
171
|
+
| Param | Default | Description |
|
|
172
|
+
|---|---|---|
|
|
173
|
+
| `requireMaxReached` | `true` | Force ≥ 1 output row close to `capMaxWin`. |
|
|
174
|
+
| `maxReachedFraction` | `0.95` | What counts as "close". |
|
|
175
|
+
| `totalWeightOut` | `nRowsOut × 1_000_000` | Sum of integer output weights. |
|
|
176
|
+
| `seed` | `0xC0FFEE` | Deterministic seed for all RNG. |
|
|
177
|
+
|
|
178
|
+
### NNLS-only knobs
|
|
179
|
+
|
|
180
|
+
| Param | Default | Description |
|
|
181
|
+
|---|---|---|
|
|
182
|
+
| `maxIterations` | `5` | Expand-and-retry attempts on tolerance miss. |
|
|
183
|
+
| `bucketCount` | `100` | Log-buckets between min-nonzero and cap. |
|
|
184
|
+
| `minPerBucket` | `3` | Min sample slots per non-empty non-zero bucket. |
|
|
185
|
+
| `maxRowRtpShare` | `0.05` | Per-row cap on RTP contribution (iterative cap-and-resolve). |
|
|
186
|
+
| `maxWeightPerRow` | `10` | Per-row weight ≤ N × uniform-prior. |
|
|
187
|
+
|
|
188
|
+
### Returns
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
{
|
|
192
|
+
rows: LookupRow[], // exactly nRowsOut rows; sim_id preserved
|
|
193
|
+
achieved: {
|
|
194
|
+
rtp, cv, hitRate, maxPayout, totalWeight
|
|
195
|
+
},
|
|
196
|
+
toleranceMet: {
|
|
197
|
+
rtp, cv, hitRate, maxReached,
|
|
198
|
+
rtpConcentration, weightCap // NNLS-only constraints
|
|
199
|
+
},
|
|
200
|
+
maxRowRtpShare: number, // largest single-row RTP fraction
|
|
201
|
+
maxWeightRatio: number, // max weight / uniform-prior
|
|
202
|
+
refinement: { // per-pass swap counters
|
|
203
|
+
rtpSwaps, // refineRtpBySwap iterations
|
|
204
|
+
cvSwaps, // refineCvBySwap (Σ-preserving 2-swaps)
|
|
205
|
+
gapFillSwaps, // ensureRangeCoverage swaps
|
|
206
|
+
diversifySwaps, // minUniqueEventsRate swaps
|
|
207
|
+
gapsUnfillable, // ranges source couldn't fill
|
|
208
|
+
},
|
|
209
|
+
warnings: string[], // human-readable issues (gaps, target misses, …)
|
|
210
|
+
stakeReport: { // Stake-publish-UI-equivalent metrics
|
|
211
|
+
payoutMultMax, // ≡ Stake's "Payout Mult"
|
|
212
|
+
baseStd, // ≡ Stake's "Base STD"
|
|
213
|
+
prob5K, prob10K, // ≡ "Within 5K/10K Probability Limits"
|
|
214
|
+
topKShare: [{k: 1, share}, …], // top-1/5/10/100 RTP shares
|
|
215
|
+
hitRateDistribution: HitRateBucket[], // 16-bucket pm table mirroring Stake's UI
|
|
216
|
+
uniqueEvents: number, // distinct payoutCents — ≡ "Insufficient Unique Events"
|
|
217
|
+
betCostCents
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Never throws on tolerance miss — returns the best-effort result with `warnings`. Only throws when the filtered input has fewer than `nRowsOut` rows.
|
|
223
|
+
|
|
224
|
+
Determinism: same `(rows, params)` → bit-identical output.
|
|
225
|
+
|
|
226
|
+
## Hit-rate distribution table
|
|
227
|
+
|
|
228
|
+
`result.stakeReport.hitRateDistribution` mirrors what Stake Engine shows in the publish UI. 16 payout-multiplier buckets:
|
|
229
|
+
|
|
230
|
+
```
|
|
231
|
+
[0, 0.1) [0.1, 1) [1, 2) [2, 5) [5, 10) [10, 20)
|
|
232
|
+
[20, 50) [50, 100) [100, 200) [200, 500)
|
|
233
|
+
[500, 1000) [1000, 2000) [2000, 5000) [5000, 10000)
|
|
234
|
+
[10000, 20000) [20000, ∞)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
For each bucket: `count` (rows in range), `effectiveHitRate` (Σ weight in range / total weight).
|
|
238
|
+
|
|
239
|
+
`detectHitRateGaps(distribution)` returns the **intermediate** empty buckets (sandwiched between non-empty ones) — these are what Stake's "Gaps in the Hit Rate Table" check flags. Empty buckets at the tail (above the highest non-empty bucket) are natural and not flagged.
|
|
240
|
+
|
|
241
|
+
The optimizer **proactively prevents** intermediate gaps via the `ensureRangeCoverage` pass (default on for tier-based): after RTP+CV refinement, any empty intermediate bucket gets a row swapped in from source. If a range can't be filled (source has no rows in that pm range), a warning is emitted — that's a game-design issue your simulation needs to address.
|
|
242
|
+
|
|
243
|
+
## Stake publish-UI mapping
|
|
244
|
+
|
|
245
|
+
| Stake UI metric | `result.stakeReport` field | Notes |
|
|
246
|
+
|---|---|---|
|
|
247
|
+
| Payout Mult | `payoutMultMax` | max payout / bet |
|
|
248
|
+
| Base STD | `baseStd` | stddev in bet units |
|
|
249
|
+
| Within 5K/10K Probability Limits | `prob5K`, `prob10K` | typically 0 for non-progressive games |
|
|
250
|
+
| Within Liability Limits | `topKShare[0]` (top-1) | usually < 0.05 with `largePmThreshold` set |
|
|
251
|
+
| Within Risk Limits | (compute from `baseStd × betCost × maxBet`) | |
|
|
252
|
+
| Hit-Rate Distribution table | `hitRateDistribution` | full match by range |
|
|
253
|
+
| Insufficient Unique Events | `uniqueEvents` | distinct payoutCents in output. Auto-driven to `minUniqueEventsRate × nRowsOut` via the diversify pass. |
|
|
254
|
+
| Gaps in Hit Rate Table | `detectHitRateGaps(...)` returns `[]` | tail empties are natural |
|
|
255
|
+
|
|
256
|
+
## How tolerance flows
|
|
257
|
+
|
|
258
|
+
Both refinement passes derive their per-iteration Σ-drift budget from `params.toleranceRTP` so the user's `tolerance*` values **actually drive the precision**:
|
|
259
|
+
|
|
260
|
+
- `refineRtpBySwap` uses `0.5 × toleranceRTP × T × 100 / W` cents of Σ-drift budget.
|
|
261
|
+
- `refineCvBySwap` uses the other `0.5 × toleranceRTP × …`, and exits when `|Σ²_achieved − Σ²_target| ≤ 2 × targetCV × mean² × T × toleranceCV / W`.
|
|
262
|
+
|
|
263
|
+
Tighten `toleranceRTP` for sub-percent precision; loosen `toleranceCV` to let CV refinement exit earlier when the source distribution can't reach the target.
|
|
102
264
|
|
|
103
265
|
## Scripts
|
|
104
266
|
|
|
105
267
|
```bash
|
|
106
|
-
npm test #
|
|
268
|
+
npm test # vitest run — full suite (~15s)
|
|
107
269
|
npm run typecheck # tsc --noEmit
|
|
108
270
|
```
|
|
109
271
|
|
|
272
|
+
## Design history
|
|
273
|
+
|
|
274
|
+
- [`docs/superpowers/specs/2026-05-08-stake-lookup-optimizer-design.md`](../../docs/superpowers/specs/2026-05-08-stake-lookup-optimizer-design.md) — original NNLS-based design.
|
|
275
|
+
- Subsequent commits added the tiered algorithm in response to Stake's "Within Liability Limits" rejection of the NNLS-concentrated output. The tier-based approach is what Stake's reference implementations use; we converged independently on the same algorithm via empirical iteration.
|
|
276
|
+
|
|
110
277
|
## License
|
|
111
278
|
|
|
112
279
|
MIT
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
export { optimizeLookupTable } from './optimize-lookup.js';
|
|
3
|
+
export { buildTieredLookup } from './tiered.js';
|
|
3
4
|
export type {
|
|
4
5
|
LookupRow,
|
|
5
6
|
OptimizeParams,
|
|
6
7
|
OptimizeResult,
|
|
7
8
|
OptimizeAchieved,
|
|
8
9
|
ToleranceMet,
|
|
10
|
+
StakeReport,
|
|
11
|
+
TopKShare,
|
|
12
|
+
HitRateBucket,
|
|
13
|
+
RefinementStats,
|
|
9
14
|
} from './types.js';
|
|
15
|
+
export { computeStakeReport, detectHitRateGaps } from './stake-report.js';
|
|
16
|
+
export { transformJsonlZst } from './transform-jsonl-zst.js';
|
|
17
|
+
export type {
|
|
18
|
+
TransformJsonlZstParams,
|
|
19
|
+
TransformJsonlZstResult,
|
|
20
|
+
LineMapper,
|
|
21
|
+
BinaryLineMapper,
|
|
22
|
+
} from './transform-jsonl-zst.js';
|
|
10
23
|
|
|
11
24
|
// Lower-level pieces — exposed so callers can build alternative pipelines or test in isolation.
|
|
12
25
|
export { computeMetrics, isNearMax } from './metrics.js';
|