@loadstrike/loadstrike-sdk 1.0.30201 → 1.0.30401

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.
@@ -0,0 +1,942 @@
1
+ import { createHash } from "node:crypto";
2
+ export function buildLoadEngineV2TrafficMixRunId(runId, declarationIndex, name) {
3
+ if (!runId || Buffer.byteLength(runId, "utf8") > 128) {
4
+ throw new Error("Load Engine V2 traffic-mix run ID is invalid.");
5
+ }
6
+ return buildLoadEngineV2TrafficMixId("LS-TM1\n", runId, declarationIndex, name);
7
+ }
8
+ export function buildLoadEngineV2TrafficMixSeedId(declarationIndex, name) {
9
+ return buildLoadEngineV2TrafficMixId("LS-TMS1\n", undefined, declarationIndex, name);
10
+ }
11
+ export function loadEngineV2TrafficMixRank(weights, laneIndex, laneOrdinal) {
12
+ validateLoadEngineV2TrafficMix(weights, laneIndex, laneOrdinal);
13
+ const denominator = BigInt(weights[laneIndex]);
14
+ const midpointNumerator = 2n * laneOrdinal + 1n;
15
+ let rank = 0n;
16
+ for (let otherLane = 0; otherLane < weights.length; otherLane += 1) {
17
+ const product = midpointNumerator * BigInt(weights[otherLane]);
18
+ const quotient = (product - 1n) / denominator;
19
+ const before = (quotient + 1n) / 2n;
20
+ const tie = otherLane < laneIndex
21
+ && product % denominator === 0n
22
+ && (product / denominator) % 2n !== 0n
23
+ ? 1n
24
+ : 0n;
25
+ rank += before + tie;
26
+ }
27
+ if (rank > 9223372036854775807n) {
28
+ throw new RangeError("Load Engine V2 traffic-mix rank exceeds signed 64-bit storage.");
29
+ }
30
+ return rank;
31
+ }
32
+ export function loadEngineV2TrafficMixLaneUnitCount(globalUnitCount, weights, laneIndex) {
33
+ if (globalUnitCount < 0n || globalUnitCount > 9223372036854775807n) {
34
+ throw new RangeError("Load Engine V2 traffic-mix global unit count is invalid.");
35
+ }
36
+ validateLoadEngineV2TrafficMix(weights, laneIndex, 0n);
37
+ let low = 0n;
38
+ let high = globalUnitCount;
39
+ while (low < high) {
40
+ const middle = low + ((high - low) >> 1n);
41
+ if (loadEngineV2TrafficMixRank(weights, laneIndex, middle) < globalUnitCount) {
42
+ low = middle + 1n;
43
+ }
44
+ else {
45
+ high = middle;
46
+ }
47
+ }
48
+ return low;
49
+ }
50
+ export function loadEngineV2TrafficMixOwnedUnits(globalUnitCount, weights, laneIndex, shardIndex, shardCount) {
51
+ if (!Number.isSafeInteger(shardCount) || shardCount <= 0
52
+ || !Number.isSafeInteger(shardIndex) || shardIndex < 0 || shardIndex >= shardCount) {
53
+ throw new RangeError("Load Engine V2 traffic-mix shard request is invalid.");
54
+ }
55
+ const laneCount = loadEngineV2TrafficMixLaneUnitCount(globalUnitCount, weights, laneIndex);
56
+ const result = [];
57
+ for (let laneOrdinal = BigInt(shardIndex); laneOrdinal < laneCount; laneOrdinal += BigInt(shardCount)) {
58
+ result.push({
59
+ laneOrdinal,
60
+ globalRank: loadEngineV2TrafficMixRank(weights, laneIndex, laneOrdinal)
61
+ });
62
+ }
63
+ return result;
64
+ }
65
+ function buildLoadEngineV2TrafficMixId(magic, runId, declarationIndex, name) {
66
+ if (!Number.isSafeInteger(declarationIndex) || declarationIndex < 0) {
67
+ throw new RangeError("Load Engine V2 traffic-mix declaration index is invalid.");
68
+ }
69
+ if (!name.trim()) {
70
+ throw new Error("Load Engine V2 traffic-mix name is required.");
71
+ }
72
+ const values = [...(runId === undefined ? [] : [runId]), declarationIndex.toString(), name];
73
+ const fields = values.map((value) => {
74
+ const bytes = Buffer.from(value, "utf8");
75
+ const framed = Buffer.allocUnsafe(4 + bytes.length);
76
+ framed.writeUInt32BE(bytes.length, 0);
77
+ bytes.copy(framed, 4);
78
+ return framed;
79
+ });
80
+ return createHash("sha256").update(Buffer.concat([Buffer.from(magic, "ascii"), ...fields])).digest("hex");
81
+ }
82
+ function validateLoadEngineV2TrafficMix(weights, laneIndex, laneOrdinal) {
83
+ if (!Array.isArray(weights) || weights.length === 0
84
+ || weights.some((weight) => !Number.isSafeInteger(weight) || weight <= 0)) {
85
+ throw new Error("Load Engine V2 traffic-mix weights must be positive integers.");
86
+ }
87
+ if (!Number.isSafeInteger(laneIndex) || laneIndex < 0 || laneIndex >= weights.length) {
88
+ throw new RangeError("Load Engine V2 traffic-mix lane index is invalid.");
89
+ }
90
+ if (laneOrdinal < 0n || laneOrdinal > 9223372036854775807n) {
91
+ throw new RangeError("Load Engine V2 traffic-mix lane ordinal is invalid.");
92
+ }
93
+ }
94
+ export class LoadEngineV2ExecutionBudget {
95
+ constructor(maxInFlight) {
96
+ this.maxInFlight = maxInFlight;
97
+ this.currentValue = 0;
98
+ this.highWaterValue = 0;
99
+ if (!Number.isSafeInteger(maxInFlight) || maxInFlight < 1 || maxInFlight > 1000000) {
100
+ throw new RangeError("maxInFlight must be an integer from 1 through 1000000.");
101
+ }
102
+ }
103
+ get current() {
104
+ return this.currentValue;
105
+ }
106
+ get highWater() {
107
+ return this.highWaterValue;
108
+ }
109
+ tryAcquire() {
110
+ if (this.currentValue >= this.maxInFlight) {
111
+ return undefined;
112
+ }
113
+ this.currentValue += 1;
114
+ this.highWaterValue = Math.max(this.highWaterValue, this.currentValue);
115
+ let released = false;
116
+ return () => {
117
+ if (released) {
118
+ return;
119
+ }
120
+ released = true;
121
+ this.currentValue -= 1;
122
+ };
123
+ }
124
+ }
125
+ /**
126
+ * Canonical bounded streaming histogram used by Load Engine V2.
127
+ *
128
+ * The first 2,048 normalized values remain exact. Larger streams are promoted
129
+ * into the portable quantized-v1 layout, whose 7,296 counters cover every
130
+ * non-negative signed 64-bit value with a maximum relative error of 1/128.
131
+ */
132
+ export class LoadStrikeHistogramV1 {
133
+ constructor() {
134
+ this.exactSamples = [];
135
+ this.countValue = 0n;
136
+ this.minimumValue = 0n;
137
+ this.maximumValue = 0n;
138
+ this.originValue = 0n;
139
+ this.meanOffsetValue = 0;
140
+ this.m2 = 0;
141
+ this.exactTotalValue = 0n;
142
+ }
143
+ get count() { return this.countValue; }
144
+ get minimum() { return this.countValue === 0n ? 0n : this.minimumValue; }
145
+ get maximum() { return this.countValue === 0n ? 0n : this.maximumValue; }
146
+ get origin() { return this.countValue === 0n ? 0n : this.originValue; }
147
+ get meanOffset() { return this.countValue === 0n ? 0 : this.meanOffsetValue; }
148
+ get mean() { return this.countValue === 0n ? 0 : Number(this.originValue) + this.meanOffsetValue; }
149
+ get populationStandardDeviation() {
150
+ return this.countValue <= 1n ? 0 : Math.sqrt(this.m2 / Number(this.countValue));
151
+ }
152
+ get mode() {
153
+ return this.exactSamples ? "exact-normalized" : "quantized-v1";
154
+ }
155
+ get maxRelativeError() { return this.exactSamples ? 0 : 0.0078125; }
156
+ get retainedValueCount() {
157
+ return this.exactSamples?.length ?? this.buckets.reduce((total, value) => total + (value === 0n ? 0 : 1), 0);
158
+ }
159
+ get exactTotal() { return this.exactTotalValue; }
160
+ toSidecar() {
161
+ const exactSamples = this.exactSamples
162
+ ? [...this.exactSamples].sort(compareBigInt).map((value) => value.toString())
163
+ : [];
164
+ const buckets = [];
165
+ let zeroCount = 0n;
166
+ if (this.exactSamples) {
167
+ zeroCount = this.exactSamples.reduce((count, value) => count + (value === 0n ? 1n : 0n), 0n);
168
+ }
169
+ else {
170
+ zeroCount = this.buckets[0];
171
+ for (let index = 1; index < LoadStrikeHistogramV1.bucketCount; index += 1) {
172
+ const count = this.buckets[index];
173
+ if (count === 0n)
174
+ continue;
175
+ buckets.push({
176
+ bucketKey64: LoadStrikeHistogramV1.bucketKeyFromIndex(index).toString(),
177
+ count64: count.toString()
178
+ });
179
+ }
180
+ }
181
+ return {
182
+ schemaVersion: "loadstrike.histogram/1",
183
+ mode: this.mode,
184
+ count64: this.countValue.toString(),
185
+ zeroCount64: zeroCount.toString(),
186
+ minimum64: this.minimum.toString(),
187
+ maximum64: this.maximum.toString(),
188
+ origin64: this.origin.toString(),
189
+ meanOffsetBits: binary64Bits(this.meanOffsetValue),
190
+ m2Bits: binary64Bits(this.m2),
191
+ exactTotal64: this.exactTotalValue.toString(),
192
+ exactSamples64: exactSamples,
193
+ buckets
194
+ };
195
+ }
196
+ static fromSidecar(sidecar) {
197
+ if (!sidecar || sidecar.schemaVersion !== "loadstrike.histogram/1") {
198
+ throw new Error("Histogram sidecar schema is unsupported.");
199
+ }
200
+ const count = parseCanonicalNonNegativeBigInt(sidecar.count64, "histogram count");
201
+ const zeroCount = parseCanonicalNonNegativeBigInt(sidecar.zeroCount64, "histogram zero count");
202
+ const minimum = parseCanonicalNonNegativeBigInt(sidecar.minimum64, "histogram minimum");
203
+ const maximum = parseCanonicalNonNegativeBigInt(sidecar.maximum64, "histogram maximum");
204
+ const origin = parseCanonicalNonNegativeBigInt(sidecar.origin64, "histogram origin");
205
+ const exactTotal = parseCanonicalNonNegativeBigInt(sidecar.exactTotal64, "histogram exact total");
206
+ if (count > 9223372036854775807n || minimum > maximum || zeroCount > count) {
207
+ throw new Error("Histogram sidecar counters do not reconcile.");
208
+ }
209
+ if (count === 0n && (minimum !== 0n || maximum !== 0n || origin !== 0n || exactTotal !== 0n)) {
210
+ throw new Error("Empty histogram sidecar state is invalid.");
211
+ }
212
+ if (count > 0n && (origin < minimum || origin > maximum)) {
213
+ throw new Error("Histogram sidecar origin is outside its range.");
214
+ }
215
+ const meanOffset = binary64FromBits(sidecar.meanOffsetBits, "histogram mean offset");
216
+ const m2 = binary64FromBits(sidecar.m2Bits, "histogram M2");
217
+ if (Object.is(m2, -0) || m2 < 0)
218
+ throw new Error("Histogram sidecar M2 must be non-negative.");
219
+ const restored = new LoadStrikeHistogramV1();
220
+ restored.countValue = count;
221
+ restored.minimumValue = minimum;
222
+ restored.maximumValue = maximum;
223
+ restored.originValue = origin;
224
+ restored.meanOffsetValue = meanOffset;
225
+ restored.m2 = m2;
226
+ restored.exactTotalValue = exactTotal;
227
+ if (sidecar.mode === "exact-normalized") {
228
+ if (sidecar.buckets.length !== 0 || sidecar.exactSamples64.length > LoadStrikeHistogramV1.exactLimit) {
229
+ throw new Error("Exact histogram sidecar shape is invalid.");
230
+ }
231
+ const samples = sidecar.exactSamples64.map((value) => parseCanonicalNonNegativeBigInt(value, "histogram exact sample"));
232
+ if (BigInt(samples.length) !== count || !isSortedBigInt(samples)
233
+ || samples.filter((value) => value === 0n).length !== Number(zeroCount)
234
+ || samples.some((value) => value < minimum || value > maximum)) {
235
+ throw new Error("Exact histogram sidecar samples do not reconcile.");
236
+ }
237
+ restored.exactSamples = samples;
238
+ restored.buckets = undefined;
239
+ return restored;
240
+ }
241
+ if (sidecar.mode !== "quantized-v1" || sidecar.exactSamples64.length !== 0) {
242
+ throw new Error("Histogram sidecar mode is invalid.");
243
+ }
244
+ restored.exactSamples = undefined;
245
+ restored.buckets = Array.from({ length: LoadStrikeHistogramV1.bucketCount }, () => 0n);
246
+ restored.buckets[0] = zeroCount;
247
+ let previousKey = -1n;
248
+ let total = zeroCount;
249
+ for (const row of sidecar.buckets) {
250
+ const key = parseCanonicalNonNegativeBigInt(row.bucketKey64, "histogram bucket key");
251
+ const bucketCount = parseCanonicalNonNegativeBigInt(row.count64, "histogram bucket count");
252
+ if (key <= previousKey || bucketCount <= 0n) {
253
+ throw new Error("Histogram sidecar buckets must be sorted, unique, and positive.");
254
+ }
255
+ restored.buckets[LoadStrikeHistogramV1.bucketIndexFromKey(key)] = bucketCount;
256
+ previousKey = key;
257
+ total += bucketCount;
258
+ }
259
+ if (total !== count)
260
+ throw new Error("Histogram sidecar bucket counts do not reconcile.");
261
+ return restored;
262
+ }
263
+ record(input) {
264
+ if (input > 9223372036854775807n) {
265
+ throw new RangeError("Histogram values must fit in a non-negative signed 64-bit integer.");
266
+ }
267
+ const value = input < 0n ? 0n : input;
268
+ this.updateMoments(value);
269
+ if (this.exactSamples && this.exactSamples.length < LoadStrikeHistogramV1.exactLimit) {
270
+ this.exactSamples.push(value);
271
+ return;
272
+ }
273
+ if (this.exactSamples)
274
+ this.promote();
275
+ this.addBucket(value, 1n);
276
+ }
277
+ clone() {
278
+ const clone = new LoadStrikeHistogramV1();
279
+ clone.copyFrom(this);
280
+ return clone;
281
+ }
282
+ merge(other) {
283
+ if (other.countValue === 0n)
284
+ return;
285
+ if (this.countValue === 0n) {
286
+ this.copyFrom(other);
287
+ return;
288
+ }
289
+ const leftCount = this.countValue;
290
+ const rightCount = other.countValue;
291
+ const combinedCount = leftCount + rightCount;
292
+ if (combinedCount > 9223372036854775807n) {
293
+ throw new RangeError("Merged histogram count exceeds signed 64-bit storage.");
294
+ }
295
+ const delta = Number(other.originValue - this.originValue) + other.meanOffsetValue - this.meanOffsetValue;
296
+ const mergedM2 = this.m2 + other.m2
297
+ + delta * delta * Number(leftCount) * Number(rightCount) / Number(combinedCount);
298
+ if (!Number.isFinite(mergedM2) || mergedM2 < 0) {
299
+ throw new Error("Histogram merge produced invalid variance state.");
300
+ }
301
+ this.meanOffsetValue += delta * Number(rightCount) / Number(combinedCount);
302
+ this.m2 = mergedM2 === 0 ? 0 : mergedM2;
303
+ this.countValue = combinedCount;
304
+ this.minimumValue = this.minimumValue < other.minimumValue ? this.minimumValue : other.minimumValue;
305
+ this.maximumValue = this.maximumValue > other.maximumValue ? this.maximumValue : other.maximumValue;
306
+ this.exactTotalValue += other.exactTotalValue;
307
+ if (this.exactSamples && other.exactSamples && combinedCount <= BigInt(LoadStrikeHistogramV1.exactLimit)) {
308
+ this.exactSamples.push(...other.exactSamples);
309
+ return;
310
+ }
311
+ if (this.exactSamples)
312
+ this.promote();
313
+ if (other.exactSamples) {
314
+ for (const sample of other.exactSamples)
315
+ this.addBucket(sample, 1n);
316
+ }
317
+ else {
318
+ for (let index = 0; index < LoadStrikeHistogramV1.bucketCount; index += 1) {
319
+ if (other.buckets[index] !== 0n)
320
+ this.buckets[index] += other.buckets[index];
321
+ }
322
+ }
323
+ }
324
+ percentile(percentile) {
325
+ if (!Number.isFinite(percentile) || percentile < 0 || percentile > 1) {
326
+ throw new RangeError("percentile must be from 0 through 1.");
327
+ }
328
+ if (this.countValue === 0n)
329
+ return 0n;
330
+ if (percentile === 0)
331
+ return this.minimumValue;
332
+ if (percentile === 1)
333
+ return this.maximumValue;
334
+ const scale = 1000000000000n;
335
+ const numerator = BigInt(Math.ceil(percentile * Number(scale)));
336
+ const rank = maximumBigInt(1n, divideCeiling(this.countValue * numerator, scale));
337
+ if (this.exactSamples) {
338
+ const ordered = [...this.exactSamples].sort((left, right) => left < right ? -1 : left > right ? 1 : 0);
339
+ return ordered[Number(rank - 1n)];
340
+ }
341
+ let cumulative = 0n;
342
+ for (let index = 0; index < LoadStrikeHistogramV1.bucketCount; index += 1) {
343
+ cumulative += this.buckets[index];
344
+ if (cumulative >= rank) {
345
+ const upper = LoadStrikeHistogramV1.bucketUpperBound(index);
346
+ return upper < this.maximumValue ? upper : this.maximumValue;
347
+ }
348
+ }
349
+ throw new Error("Histogram counts do not reconcile.");
350
+ }
351
+ updateMoments(value) {
352
+ if (this.countValue === 0n) {
353
+ this.countValue = 1n;
354
+ this.minimumValue = value;
355
+ this.maximumValue = value;
356
+ this.originValue = value;
357
+ this.exactTotalValue = value;
358
+ return;
359
+ }
360
+ const nextCount = this.countValue + 1n;
361
+ if (nextCount > 9223372036854775807n)
362
+ throw new RangeError("Histogram count exceeds signed 64-bit storage.");
363
+ const offset = Number(value - this.originValue);
364
+ const delta = offset - this.meanOffsetValue;
365
+ this.meanOffsetValue += delta / Number(nextCount);
366
+ const updatedM2 = this.m2 + delta * (offset - this.meanOffsetValue);
367
+ if (!Number.isFinite(updatedM2) || updatedM2 < 0)
368
+ throw new Error("Histogram update produced invalid variance state.");
369
+ this.m2 = updatedM2 === 0 ? 0 : updatedM2;
370
+ this.countValue = nextCount;
371
+ if (value < this.minimumValue)
372
+ this.minimumValue = value;
373
+ if (value > this.maximumValue)
374
+ this.maximumValue = value;
375
+ this.exactTotalValue += value;
376
+ }
377
+ promote() {
378
+ this.buckets = Array.from({ length: LoadStrikeHistogramV1.bucketCount }, () => 0n);
379
+ for (const sample of this.exactSamples)
380
+ this.addBucket(sample, 1n);
381
+ this.exactSamples = undefined;
382
+ }
383
+ addBucket(value, count) {
384
+ this.buckets[LoadStrikeHistogramV1.bucketIndex(value)] += count;
385
+ }
386
+ copyFrom(other) {
387
+ this.countValue = other.countValue;
388
+ this.minimumValue = other.minimumValue;
389
+ this.maximumValue = other.maximumValue;
390
+ this.originValue = other.originValue;
391
+ this.meanOffsetValue = other.meanOffsetValue;
392
+ this.m2 = other.m2;
393
+ this.exactTotalValue = other.exactTotalValue;
394
+ this.exactSamples = other.exactSamples ? [...other.exactSamples] : undefined;
395
+ this.buckets = other.buckets ? [...other.buckets] : undefined;
396
+ }
397
+ static bucketIndex(value) {
398
+ if (value === 0n)
399
+ return 0;
400
+ const exponent = value.toString(2).length - 1;
401
+ const shift = Math.max(exponent - 7, 0);
402
+ const mantissa = Number(value >> BigInt(shift));
403
+ return shift === 0 ? mantissa : 256 + (shift - 1) * 128 + (mantissa - 128);
404
+ }
405
+ static bucketUpperBound(index) {
406
+ if (index === 0)
407
+ return 0n;
408
+ if (index <= 255)
409
+ return BigInt(index);
410
+ const shift = 1 + Math.floor((index - 256) / 128);
411
+ const mantissa = 128 + (index - 256) % 128;
412
+ return (BigInt(mantissa) << BigInt(shift)) + (1n << BigInt(shift)) - 1n;
413
+ }
414
+ static bucketKeyFromIndex(index) {
415
+ if (index <= 0 || index >= LoadStrikeHistogramV1.bucketCount) {
416
+ throw new RangeError("Histogram bucket index is invalid.");
417
+ }
418
+ if (index <= 255)
419
+ return BigInt(index);
420
+ const shift = 1 + Math.floor((index - 256) / 128);
421
+ const mantissa = 128 + (index - 256) % 128;
422
+ return BigInt((shift << 8) | mantissa);
423
+ }
424
+ static bucketIndexFromKey(key) {
425
+ if (key > BigInt(Number.MAX_SAFE_INTEGER))
426
+ throw new Error("Histogram bucket key is invalid.");
427
+ const numeric = Number(key);
428
+ const shift = numeric >> 8;
429
+ const mantissa = numeric & 255;
430
+ if (shift === 0 && mantissa >= 1 && mantissa <= 255)
431
+ return mantissa;
432
+ if (shift < 1 || shift > 55 || mantissa < 128 || mantissa > 255) {
433
+ throw new Error("Histogram bucket key is invalid.");
434
+ }
435
+ return 256 + (shift - 1) * 128 + (mantissa - 128);
436
+ }
437
+ }
438
+ LoadStrikeHistogramV1.exactLimit = 2048;
439
+ LoadStrikeHistogramV1.bucketCount = 7296;
440
+ /** Serializes the canonical cumulative LoadStrikeHistogramArtifactV1 (`LS-H1`). */
441
+ export function serializeLoadEngineV2HistogramArtifact(artifact) {
442
+ const distributions = [...artifact.distributions].sort(compareV2DistributionRecords);
443
+ const summaries = [...artifact.measurementSummaries].sort(compareV2MeasurementSummaries);
444
+ if (distributions.length > 100000 || summaries.length > 100000) {
445
+ throw new Error("Load Engine V2 histogram artifact record count exceeds the supported bound.");
446
+ }
447
+ if (distributions.length !== summaries.length * 6
448
+ && (distributions.length < summaries.length * 6
449
+ || (distributions.length - summaries.length * 6) % 2 !== 0)) {
450
+ throw new Error("Load Engine V2 histogram artifact distribution/summary counts do not reconcile.");
451
+ }
452
+ const fields = [Buffer.from("LS-H1\n", "ascii")];
453
+ const write = (value) => { fields.push(frameV2Text(value)); };
454
+ write("1");
455
+ write("1");
456
+ write(distributions.length.toString());
457
+ distributions.forEach((record) => fields.push(serializeV2DistributionRecord(record)));
458
+ write(summaries.length.toString());
459
+ summaries.forEach((summary) => fields.push(frameV2Bytes(serializeV2MeasurementSummary(summary))));
460
+ const encoded = Buffer.concat(fields);
461
+ if (encoded.length > 67108864) {
462
+ throw new Error("Load Engine V2 histogram artifact exceeds the signed non-detail artifact bound.");
463
+ }
464
+ return encoded;
465
+ }
466
+ /** Strictly parses, validates, and canonical-byte checks an `LS-H1` artifact. */
467
+ export function parseLoadEngineV2HistogramArtifact(bytes) {
468
+ const input = Buffer.from(bytes);
469
+ if (input.length > 67108864 || !input.subarray(0, 6).equals(Buffer.from("LS-H1\n", "ascii"))) {
470
+ throw new Error("Load Engine V2 histogram artifact magic or byte bound is invalid.");
471
+ }
472
+ const cursor = new V2ArtifactCursor(input, 6);
473
+ if (cursor.text() !== "1" || cursor.text() !== "1") {
474
+ throw new Error("Load Engine V2 histogram artifact version is unsupported.");
475
+ }
476
+ const distributionCount = cursor.count("distribution record count", 100000);
477
+ const distributions = [];
478
+ for (let index = 0; index < distributionCount; index += 1) {
479
+ distributions.push(parseV2DistributionRecord(cursor));
480
+ }
481
+ const summaryCount = cursor.count("measurement summary count", 100000);
482
+ const measurementSummaries = [];
483
+ for (let index = 0; index < summaryCount; index += 1) {
484
+ const nested = new V2ArtifactCursor(cursor.bytes(), 0);
485
+ measurementSummaries.push(parseV2MeasurementSummary(nested));
486
+ nested.requireEnd();
487
+ }
488
+ cursor.requireEnd();
489
+ const artifact = { distributions, measurementSummaries };
490
+ if (!serializeLoadEngineV2HistogramArtifact(artifact).equals(input)) {
491
+ throw new Error("Load Engine V2 histogram artifact is not in canonical byte order.");
492
+ }
493
+ return artifact;
494
+ }
495
+ function serializeV2DistributionRecord(record) {
496
+ validateV2SeriesKind(record.seriesKind);
497
+ parseCanonicalNonNegativeBigInt(record.scenarioIndex64, "distribution scenario index");
498
+ validateV2BoundedText(record.scenarioName, "distribution scenario name", 1024);
499
+ validateV2Hex(record.identityKeyHex, "distribution identity key");
500
+ if (!["ok", "fail", "all", "none"].includes(record.outcome)
501
+ || !["microseconds", "bytes", "count"].includes(record.unit)) {
502
+ throw new Error("Load Engine V2 distribution outcome or unit is invalid.");
503
+ }
504
+ const histogram = LoadStrikeHistogramV1.fromSidecar(record.histogram).toSidecar();
505
+ const exactTotal = record.exactTotalDecimalOrEmpty ?? histogram.exactTotal64;
506
+ if (exactTotal !== "")
507
+ parseCanonicalNonNegativeBigInt(exactTotal, "distribution exact total");
508
+ const bands = [...(record.bands ?? [])].sort((left, right) => compareCanonicalV2Integers(left.bandId64, right.bandId64));
509
+ if (bands.length > 64 || new Set(bands.map((value) => value.bandId64)).size !== bands.length) {
510
+ throw new Error("Load Engine V2 distribution band records are invalid.");
511
+ }
512
+ bands.forEach((band) => {
513
+ parseCanonicalNonNegativeBigInt(band.bandId64, "distribution band ID");
514
+ parseCanonicalNonNegativeBigInt(band.count64, "distribution band count");
515
+ });
516
+ const fields = [];
517
+ const write = (value) => { fields.push(frameV2Text(value)); };
518
+ ["distribution", record.seriesKind, record.scenarioIndex64, record.scenarioName,
519
+ record.identityKeyHex, record.outcome, record.unit, histogram.mode,
520
+ histogram.mode === "exact-normalized" ? "0" : "0.0078125",
521
+ histogram.count64, histogram.zeroCount64, histogram.minimum64, histogram.maximum64,
522
+ histogram.origin64, histogram.meanOffsetBits, histogram.m2Bits, exactTotal,
523
+ bands.length.toString()].forEach(write);
524
+ bands.forEach((band) => { write(band.bandId64); write(band.count64); });
525
+ write(histogram.exactSamples64.length.toString());
526
+ histogram.exactSamples64.forEach(write);
527
+ write(histogram.buckets.length.toString());
528
+ histogram.buckets.forEach((bucket) => { write(bucket.bucketKey64); write(bucket.count64); });
529
+ return Buffer.concat(fields);
530
+ }
531
+ function parseV2DistributionRecord(cursor) {
532
+ if (cursor.text() !== "distribution")
533
+ throw new Error("Load Engine V2 distribution kind is invalid.");
534
+ const seriesKind = cursor.text();
535
+ const scenarioIndex64 = cursor.text();
536
+ const scenarioName = cursor.text();
537
+ const identityKeyHex = cursor.text();
538
+ const outcome = cursor.text();
539
+ const unit = cursor.text();
540
+ const mode = cursor.text();
541
+ const maxRelativeError = cursor.text();
542
+ const count64 = cursor.text();
543
+ const zeroCount64 = cursor.text();
544
+ const minimum64 = cursor.text();
545
+ const maximum64 = cursor.text();
546
+ const origin64 = cursor.text();
547
+ const meanOffsetBits = cursor.text();
548
+ const m2Bits = cursor.text();
549
+ const exactTotal64 = cursor.text();
550
+ const bandCount = cursor.count("distribution band count", 64);
551
+ const bands = Array.from({ length: bandCount }, () => ({ bandId64: cursor.text(), count64: cursor.text() }));
552
+ const exactSampleCount = cursor.count("histogram exact sample count", LoadStrikeHistogramV1.exactLimit);
553
+ const exactSamples64 = Array.from({ length: exactSampleCount }, () => cursor.text());
554
+ const bucketCount = cursor.count("histogram bucket count", LoadStrikeHistogramV1.bucketCount);
555
+ const buckets = Array.from({ length: bucketCount }, () => ({
556
+ bucketKey64: cursor.text(), count64: cursor.text()
557
+ }));
558
+ if ((mode === "exact-normalized" ? "0" : "0.0078125") !== maxRelativeError) {
559
+ throw new Error("Load Engine V2 distribution relative-error field is invalid.");
560
+ }
561
+ return {
562
+ seriesKind, scenarioIndex64, scenarioName, identityKeyHex, outcome, unit,
563
+ histogram: {
564
+ schemaVersion: "loadstrike.histogram/1", mode, count64, zeroCount64,
565
+ minimum64, maximum64, origin64, meanOffsetBits, m2Bits, exactTotal64,
566
+ exactSamples64, buckets
567
+ },
568
+ exactTotalDecimalOrEmpty: exactTotal64,
569
+ bands
570
+ };
571
+ }
572
+ function serializeV2MeasurementSummary(summary) {
573
+ if (summary.seriesKind !== "scenario" && summary.seriesKind !== "step") {
574
+ throw new Error("Load Engine V2 measurement summary kind is invalid.");
575
+ }
576
+ parseCanonicalNonNegativeBigInt(summary.scenarioIndex64, "summary scenario index");
577
+ validateV2BoundedText(summary.scenarioName, "summary scenario name", 1024);
578
+ validateV2Hex(summary.identityKeyHex, "summary identity key");
579
+ const observation = parseCanonicalNonNegativeBigInt(summary.observationCount64, "summary observation count");
580
+ const success = parseCanonicalNonNegativeBigInt(summary.successCount64, "summary success count");
581
+ const failure = parseCanonicalNonNegativeBigInt(summary.failureCount64, "summary failure count");
582
+ const aggregated = parseCanonicalNonNegativeBigInt(summary.aggregatedObservationCount64, "summary aggregated observation count");
583
+ if (observation !== success + failure || aggregated > observation
584
+ || summary.hasAggregatedIdentities !== (aggregated > 0n)
585
+ || summary.outcomes.length !== 2 || summary.outcomes[0].outcome !== "ok"
586
+ || summary.outcomes[1].outcome !== "fail") {
587
+ throw new Error("Load Engine V2 measurement summary counts do not reconcile.");
588
+ }
589
+ const fields = [Buffer.from("LS-MS1\n", "ascii")];
590
+ const write = (value) => { fields.push(frameV2Text(value)); };
591
+ ["1", summary.seriesKind, summary.scenarioIndex64, summary.scenarioName,
592
+ summary.identityKeyHex, summary.display, summary.observationCount64,
593
+ summary.successCount64, summary.failureCount64, summary.aggregatedObservationCount64,
594
+ summary.hasAggregatedIdentities ? "1" : "0"].forEach(write);
595
+ summary.outcomes.forEach((body) => {
596
+ const statuses = [...body.statuses].sort((left, right) => Buffer.compare(Buffer.from(left.statusIdentityKeyHex, "hex"), Buffer.from(right.statusIdentityKeyHex, "hex")));
597
+ const statusObservation = parseCanonicalNonNegativeBigInt(body.statusObservationCount64, "status observation count");
598
+ const sum = statuses.reduce((total, row) => total + parseCanonicalNonNegativeBigInt(row.count64, "status count"), 0n);
599
+ if (sum !== statusObservation)
600
+ throw new Error("Load Engine V2 status counts do not reconcile.");
601
+ write(body.outcome);
602
+ write(body.statusObservationCount64);
603
+ write(statuses.length.toString());
604
+ statuses.forEach((status) => {
605
+ validateV2Hex(status.statusIdentityKeyHex, "status identity key");
606
+ const statusCount = parseCanonicalNonNegativeBigInt(status.count64, "status count");
607
+ const statusAggregated = parseCanonicalNonNegativeBigInt(status.aggregatedObservationCount64, "status aggregated count");
608
+ if (statusAggregated > statusCount
609
+ || status.hasAggregatedIdentities !== (statusAggregated > 0n)) {
610
+ throw new Error("Load Engine V2 status aggregation does not reconcile.");
611
+ }
612
+ [status.statusIdentityKeyHex, status.display, status.count64,
613
+ status.aggregatedObservationCount64, status.hasAggregatedIdentities ? "1" : "0"].forEach(write);
614
+ });
615
+ });
616
+ return Buffer.concat(fields);
617
+ }
618
+ function parseV2MeasurementSummary(cursor) {
619
+ if (!cursor.raw(7).equals(Buffer.from("LS-MS1\n", "ascii")) || cursor.text() !== "1") {
620
+ throw new Error("Load Engine V2 measurement summary magic or version is invalid.");
621
+ }
622
+ const seriesKind = cursor.text();
623
+ const scenarioIndex64 = cursor.text();
624
+ const scenarioName = cursor.text();
625
+ const identityKeyHex = cursor.text();
626
+ const display = cursor.text();
627
+ const observationCount64 = cursor.text();
628
+ const successCount64 = cursor.text();
629
+ const failureCount64 = cursor.text();
630
+ const aggregatedObservationCount64 = cursor.text();
631
+ const hasAggregatedIdentities = cursor.bit();
632
+ const outcomes = ["ok", "fail"].map((expectedOutcome) => {
633
+ const outcome = cursor.text();
634
+ if (outcome !== expectedOutcome)
635
+ throw new Error("Load Engine V2 summary outcome order is invalid.");
636
+ const statusObservationCount64 = cursor.text();
637
+ const statusCount = cursor.count("summary status count", 10000);
638
+ const statuses = Array.from({ length: statusCount }, () => ({
639
+ statusIdentityKeyHex: cursor.text(), display: cursor.text(), count64: cursor.text(),
640
+ aggregatedObservationCount64: cursor.text(), hasAggregatedIdentities: cursor.bit()
641
+ }));
642
+ return { outcome, statusObservationCount64, statuses };
643
+ });
644
+ return {
645
+ seriesKind, scenarioIndex64, scenarioName, identityKeyHex, display,
646
+ observationCount64, successCount64, failureCount64, aggregatedObservationCount64,
647
+ hasAggregatedIdentities, outcomes
648
+ };
649
+ }
650
+ class V2ArtifactCursor {
651
+ constructor(input, offset) {
652
+ this.input = input;
653
+ this.offset = offset;
654
+ }
655
+ raw(length) {
656
+ if (!Number.isSafeInteger(length) || length < 0 || this.offset + length > this.input.length) {
657
+ throw new Error("Load Engine V2 artifact is truncated.");
658
+ }
659
+ const value = this.input.subarray(this.offset, this.offset + length);
660
+ this.offset += length;
661
+ return value;
662
+ }
663
+ bytes() {
664
+ const header = this.raw(4);
665
+ const length = header.readUInt32BE(0);
666
+ return this.raw(length);
667
+ }
668
+ text() {
669
+ const bytes = this.bytes();
670
+ const value = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
671
+ requireValidUnicodeScalars(value);
672
+ return value;
673
+ }
674
+ count(field, maximum) {
675
+ const value = parseCanonicalNonNegativeBigInt(this.text(), field);
676
+ if (value > BigInt(maximum))
677
+ throw new Error(`${field} exceeds the supported bound.`);
678
+ return Number(value);
679
+ }
680
+ bit() {
681
+ const value = this.text();
682
+ if (value !== "0" && value !== "1")
683
+ throw new Error("Load Engine V2 artifact bit is invalid.");
684
+ return value === "1";
685
+ }
686
+ requireEnd() {
687
+ if (this.offset !== this.input.length)
688
+ throw new Error("Load Engine V2 artifact has trailing bytes.");
689
+ }
690
+ }
691
+ function compareV2DistributionRecords(left, right) {
692
+ return compareUtf8V2(left.seriesKind, right.seriesKind)
693
+ || compareCanonicalV2Integers(left.scenarioIndex64, right.scenarioIndex64)
694
+ || Buffer.compare(Buffer.from(left.identityKeyHex, "hex"), Buffer.from(right.identityKeyHex, "hex"))
695
+ || compareUtf8V2(left.outcome, right.outcome)
696
+ || compareUtf8V2(left.unit, right.unit);
697
+ }
698
+ function compareV2MeasurementSummaries(left, right) {
699
+ return compareUtf8V2(left.seriesKind, right.seriesKind)
700
+ || compareCanonicalV2Integers(left.scenarioIndex64, right.scenarioIndex64)
701
+ || Buffer.compare(Buffer.from(left.identityKeyHex, "hex"), Buffer.from(right.identityKeyHex, "hex"));
702
+ }
703
+ function compareUtf8V2(left, right) {
704
+ requireValidUnicodeScalars(left);
705
+ requireValidUnicodeScalars(right);
706
+ return Buffer.compare(Buffer.from(left, "utf8"), Buffer.from(right, "utf8"));
707
+ }
708
+ function compareCanonicalV2Integers(left, right) {
709
+ const a = parseCanonicalNonNegativeBigInt(left, "canonical integer");
710
+ const b = parseCanonicalNonNegativeBigInt(right, "canonical integer");
711
+ return a < b ? -1 : a > b ? 1 : 0;
712
+ }
713
+ function validateV2SeriesKind(value) {
714
+ if (!["scenario", "step", "scheduler-decision-lag", "scheduler-start-lag", "correlation"]
715
+ .includes(value))
716
+ throw new Error("Load Engine V2 distribution series kind is invalid.");
717
+ }
718
+ function validateV2Hex(value, field) {
719
+ if (!/^(?:[0-9a-f]{2})+$/.test(value))
720
+ throw new Error(`${field} must be non-empty lowercase hexadecimal.`);
721
+ }
722
+ function validateV2BoundedText(value, field, maximumBytes) {
723
+ requireValidUnicodeScalars(value);
724
+ if (Buffer.byteLength(value, "utf8") > maximumBytes)
725
+ throw new Error(`${field} exceeds its UTF-8 bound.`);
726
+ }
727
+ function frameV2Text(value) {
728
+ requireValidUnicodeScalars(value);
729
+ return frameV2Bytes(Buffer.from(value, "utf8"));
730
+ }
731
+ function frameV2Bytes(value) {
732
+ const output = Buffer.allocUnsafe(4 + value.length);
733
+ output.writeUInt32BE(value.length, 0);
734
+ value.copy(output, 4);
735
+ return output;
736
+ }
737
+ function compareBigInt(left, right) {
738
+ return left < right ? -1 : left > right ? 1 : 0;
739
+ }
740
+ function isSortedBigInt(values) {
741
+ return values.every((value, index) => index === 0 || values[index - 1] <= value);
742
+ }
743
+ function parseCanonicalNonNegativeBigInt(value, field) {
744
+ if (!/^(0|[1-9][0-9]*)$/.test(value))
745
+ throw new Error(`${field} must be a canonical decimal string.`);
746
+ const parsed = BigInt(value);
747
+ if (parsed > 9223372036854775807n)
748
+ throw new Error(`${field} exceeds signed 64-bit storage.`);
749
+ return parsed;
750
+ }
751
+ function binary64Bits(value) {
752
+ if (!Number.isFinite(value))
753
+ throw new Error("Histogram binary64 state must be finite.");
754
+ const bytes = Buffer.allocUnsafe(8);
755
+ bytes.writeDoubleBE(value, 0);
756
+ return bytes.toString("hex");
757
+ }
758
+ function binary64FromBits(value, field) {
759
+ if (!/^[0-9a-f]{16}$/.test(value)) {
760
+ throw new Error(`${field} bits must be 16 lowercase hexadecimal characters.`);
761
+ }
762
+ const parsed = Buffer.from(value, "hex").readDoubleBE(0);
763
+ if (!Number.isFinite(parsed))
764
+ throw new Error(`${field} must be finite.`);
765
+ return parsed;
766
+ }
767
+ export function createDefaultLoadEngineV2Settings() {
768
+ return {
769
+ contractVersion: 2,
770
+ maxInFlight: 10000,
771
+ clusterLoadScope: "Global",
772
+ statisticsReportingIntervalNs: 1000000000n,
773
+ maxStatusGroupsPerSeries: 64
774
+ };
775
+ }
776
+ export function fnv1a32(value) {
777
+ requireValidUnicodeScalars(value);
778
+ let hash = 0x811c9dc5;
779
+ for (const valueByte of new TextEncoder().encode(value)) {
780
+ hash ^= valueByte;
781
+ hash = Math.imul(hash, 0x01000193) >>> 0;
782
+ }
783
+ return hash >>> 0;
784
+ }
785
+ export function planFixedDeadlines(rate, intervalNs, durationNs) {
786
+ validateFixedInputs(rate, intervalNs);
787
+ if (durationNs <= 0n) {
788
+ throw new RangeError("durationNs must be positive.");
789
+ }
790
+ const count = divideCeiling(durationNs * BigInt(rate), intervalNs);
791
+ if (count > BigInt(Number.MAX_SAFE_INTEGER)) {
792
+ throw new RangeError("The planned ordinal count is too large to materialize.");
793
+ }
794
+ return Array.from({ length: Number(count) }, (_, ordinal) => deadline(BigInt(ordinal), intervalNs, rate));
795
+ }
796
+ export function planFixedIterationDeadlines(rate, intervalNs, iterations) {
797
+ validateFixedInputs(rate, intervalNs);
798
+ requirePositiveSafeInteger(iterations, "iterations");
799
+ return Array.from({ length: iterations }, (_, ordinal) => deadline(BigInt(ordinal), intervalNs, rate));
800
+ }
801
+ export function planRampingInjectionDeadlines(rate, intervalNs, durationNs) {
802
+ validateFixedInputs(rate, intervalNs);
803
+ validateDuration(durationNs);
804
+ const count = divideCeiling(BigInt(rate) * durationNs, 2n * intervalNs);
805
+ if (count > BigInt(Number.MAX_SAFE_INTEGER)) {
806
+ throw new RangeError("The planned ordinal count is too large to materialize.");
807
+ }
808
+ return Array.from({ length: Number(count) }, (_, ordinal) => integerSquareRoot(2n * BigInt(ordinal) * intervalNs * durationNs / BigInt(rate)));
809
+ }
810
+ export function planRampingConstantDeadlines(copies, durationNs) {
811
+ requirePositiveSafeInteger(copies, "copies");
812
+ validateDuration(durationNs);
813
+ return Array.from({ length: copies }, (_, slot) => BigInt(slot) * durationNs / BigInt(copies));
814
+ }
815
+ export function planRandomInjectionDeadlines(minRate, maxRate, intervalNs, durationNs, seed) {
816
+ if (!Number.isSafeInteger(minRate) || minRate < 0 || !Number.isSafeInteger(maxRate) || maxRate < minRate) {
817
+ throw new RangeError("random injection rates must be non-negative integers with minRate <= maxRate.");
818
+ }
819
+ requirePositiveSafeInteger(maxRate, "maxRate");
820
+ if (intervalNs <= 0n) {
821
+ throw new RangeError("intervalNs must be positive.");
822
+ }
823
+ validateDuration(durationNs);
824
+ let state = (seed >>> 0) || 0x6d2b79f5;
825
+ const result = [];
826
+ for (let windowStart = 0n; windowStart < durationNs; windowStart += intervalNs) {
827
+ state = xorshift32(state);
828
+ const selectedRate = minRate + state % (maxRate - minRate + 1);
829
+ for (let ordinal = 0; ordinal < selectedRate; ordinal += 1) {
830
+ const planned = windowStart + BigInt(ordinal) * intervalNs / BigInt(selectedRate);
831
+ if (planned < durationNs) {
832
+ result.push(planned);
833
+ }
834
+ }
835
+ }
836
+ return result;
837
+ }
838
+ export function xorshift32(input) {
839
+ let state = (input >>> 0) || 0x6d2b79f5;
840
+ state = (state ^ (state << 13)) >>> 0;
841
+ state = (state ^ (state >>> 17)) >>> 0;
842
+ state = (state ^ (state << 5)) >>> 0;
843
+ return state >>> 0;
844
+ }
845
+ export function loadEngineV2FixedDeadlineNs(ordinal, rate, intervalNs) {
846
+ validateFixedInputs(rate, intervalNs);
847
+ if (ordinal < 0n) {
848
+ throw new RangeError("ordinal cannot be negative.");
849
+ }
850
+ return deadline(ordinal, intervalNs, rate);
851
+ }
852
+ export function loadEngineV2FixedArrivalCount(rate, intervalNs, durationNs) {
853
+ validateFixedInputs(rate, intervalNs);
854
+ if (durationNs <= 0n) {
855
+ throw new RangeError("durationNs must be positive.");
856
+ }
857
+ const count = divideCeiling(durationNs * BigInt(rate), intervalNs);
858
+ if (count > 9223372036854775807n) {
859
+ throw new RangeError("The planned arrival count exceeds signed 64-bit storage.");
860
+ }
861
+ return count;
862
+ }
863
+ export function loadEngineV2LatenessToleranceNs(rate, intervalNs) {
864
+ validateFixedInputs(rate, intervalNs);
865
+ const quantum = maximumBigInt(1n, intervalNs / BigInt(rate));
866
+ return minimumBigInt(100000000n, maximumBigInt(2000000n, quantum * 4n));
867
+ }
868
+ export function classifyLoadEngineV2Arrival(nowNs, deadlineNs, toleranceNs, permitAvailable) {
869
+ if (nowNs < deadlineNs) {
870
+ return "wait";
871
+ }
872
+ if (toleranceNs < 0n) {
873
+ throw new RangeError("toleranceNs cannot be negative.");
874
+ }
875
+ if (nowNs - deadlineNs > toleranceNs) {
876
+ return "scheduler_late";
877
+ }
878
+ return permitAvailable ? "start" : "max_in_flight";
879
+ }
880
+ function deadline(ordinal, intervalNs, rate) {
881
+ const value = ordinal * intervalNs / BigInt(rate);
882
+ if (value > 9223372036854775807n) {
883
+ throw new RangeError("The canonical deadline exceeds signed 64-bit nanoseconds.");
884
+ }
885
+ return value;
886
+ }
887
+ function validateFixedInputs(rate, intervalNs) {
888
+ requirePositiveSafeInteger(rate, "rate");
889
+ if (intervalNs <= 0n || intervalNs > 9223372036854775807n) {
890
+ throw new RangeError("intervalNs must be a positive signed 64-bit value.");
891
+ }
892
+ }
893
+ function validateDuration(durationNs) {
894
+ if (durationNs <= 0n || durationNs > 9223372036854775807n) {
895
+ throw new RangeError("durationNs must be a positive signed 64-bit value.");
896
+ }
897
+ }
898
+ function integerSquareRoot(value) {
899
+ if (value < 0n) {
900
+ throw new RangeError("value cannot be negative.");
901
+ }
902
+ if (value < 2n) {
903
+ return value;
904
+ }
905
+ let estimate = 1n << BigInt((value.toString(2).length + 1) >> 1);
906
+ for (;;) {
907
+ const next = (estimate + value / estimate) >> 1n;
908
+ if (next >= estimate) {
909
+ return estimate;
910
+ }
911
+ estimate = next;
912
+ }
913
+ }
914
+ function requirePositiveSafeInteger(value, name) {
915
+ if (!Number.isSafeInteger(value) || value <= 0 || value > 2147483647) {
916
+ throw new RangeError(`${name} must be an integer from 1 through 2147483647.`);
917
+ }
918
+ }
919
+ function requireValidUnicodeScalars(value) {
920
+ for (let index = 0; index < value.length; index += 1) {
921
+ const code = value.charCodeAt(index);
922
+ if (code >= 0xd800 && code <= 0xdbff) {
923
+ const next = value.charCodeAt(index + 1);
924
+ if (!(next >= 0xdc00 && next <= 0xdfff)) {
925
+ throw new TypeError("value contains an unpaired UTF-16 surrogate.");
926
+ }
927
+ index += 1;
928
+ }
929
+ else if (code >= 0xdc00 && code <= 0xdfff) {
930
+ throw new TypeError("value contains an unpaired UTF-16 surrogate.");
931
+ }
932
+ }
933
+ }
934
+ function divideCeiling(dividend, divisor) {
935
+ return (dividend + divisor - 1n) / divisor;
936
+ }
937
+ function minimumBigInt(left, right) {
938
+ return left < right ? left : right;
939
+ }
940
+ function maximumBigInt(left, right) {
941
+ return left > right ? left : right;
942
+ }