@holonograph/client 0.2.0 → 0.4.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/dist/index.d.ts +326 -102
- package/dist/index.js +721 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4691,7 +4691,9 @@ var LightSnapshotSchema = external_exports.object({
|
|
|
4691
4691
|
|
|
4692
4692
|
vendorMetadata: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
|
|
4693
4693
|
|
|
4694
|
-
rawRequestOmitted: external_exports.boolean().optional()
|
|
4694
|
+
rawRequestOmitted: external_exports.boolean().optional(),
|
|
4695
|
+
|
|
4696
|
+
rawResponsePresence: external_exports.enum(["present", "omitted-by-policy", "pending-attach", "failed-attach"]).optional()
|
|
4695
4697
|
});
|
|
4696
4698
|
var DimensionResultSchema = external_exports.object({
|
|
4697
4699
|
dimensionId: DimensionIdSchema,
|
|
@@ -4765,7 +4767,11 @@ var EvaluationEventKindSchema = external_exports.enum([
|
|
|
4765
4767
|
|
|
4766
4768
|
"analysis.eval-recommendation",
|
|
4767
4769
|
|
|
4768
|
-
"analysis.conformance-fixture"
|
|
4770
|
+
"analysis.conformance-fixture",
|
|
4771
|
+
|
|
4772
|
+
"analysis.emission-coverage",
|
|
4773
|
+
|
|
4774
|
+
"analysis.delivery-orphan"
|
|
4769
4775
|
]);
|
|
4770
4776
|
var AvailabilityTransitionDirectionSchema = external_exports.enum([
|
|
4771
4777
|
"reachable->unreachable",
|
|
@@ -4941,6 +4947,28 @@ var ConformanceFixtureRecordSchema = external_exports.object({
|
|
|
4941
4947
|
|
|
4942
4948
|
sourceSurfaceId: external_exports.string().min(1).optional()
|
|
4943
4949
|
});
|
|
4950
|
+
var EmissionCoverageSchema = external_exports.object({
|
|
4951
|
+
|
|
4952
|
+
streamId: external_exports.string().min(1),
|
|
4953
|
+
|
|
4954
|
+
observedOrdinals: external_exports.array(external_exports.number().int().nonnegative()),
|
|
4955
|
+
|
|
4956
|
+
sentinelHighWater: external_exports.number().int().nonnegative().nullable(),
|
|
4957
|
+
|
|
4958
|
+
finalSeen: external_exports.boolean(),
|
|
4959
|
+
|
|
4960
|
+
observedAtMs: external_exports.number().int().nonnegative()
|
|
4961
|
+
});
|
|
4962
|
+
var DeliveryOrphanSchema = external_exports.object({
|
|
4963
|
+
|
|
4964
|
+
darkEventId: external_exports.string().min(1),
|
|
4965
|
+
|
|
4966
|
+
emissionStreamId: external_exports.string().min(1),
|
|
4967
|
+
|
|
4968
|
+
surfaceId: external_exports.string().min(1),
|
|
4969
|
+
|
|
4970
|
+
witnessedAtMs: external_exports.number().int().nonnegative()
|
|
4971
|
+
});
|
|
4944
4972
|
var EvaluationEventSchema = external_exports.object({
|
|
4945
4973
|
|
|
4946
4974
|
eventId: external_exports.string().min(1),
|
|
@@ -4951,6 +4979,8 @@ var EvaluationEventSchema = external_exports.object({
|
|
|
4951
4979
|
|
|
4952
4980
|
correlationId: CorrelationIdSchema,
|
|
4953
4981
|
|
|
4982
|
+
emissionStreamId: external_exports.string().min(1).optional(),
|
|
4983
|
+
|
|
4954
4984
|
lensVersion: external_exports.string().min(1),
|
|
4955
4985
|
|
|
4956
4986
|
kind: EvaluationEventKindSchema.default("evaluation"),
|
|
@@ -4971,31 +5001,41 @@ var EvaluationEventSchema = external_exports.object({
|
|
|
4971
5001
|
|
|
4972
5002
|
evalRecommendation: EvalRecommendationSchema.optional(),
|
|
4973
5003
|
|
|
4974
|
-
conformanceFixtureRecord: ConformanceFixtureRecordSchema.optional()
|
|
5004
|
+
conformanceFixtureRecord: ConformanceFixtureRecordSchema.optional(),
|
|
5005
|
+
|
|
5006
|
+
emissionCoverage: EmissionCoverageSchema.optional(),
|
|
5007
|
+
|
|
5008
|
+
deliveryOrphan: DeliveryOrphanSchema.optional()
|
|
4975
5009
|
}).refine(
|
|
4976
5010
|
(e) => {
|
|
4977
5011
|
if (e.kind === "evaluation") {
|
|
4978
|
-
return e.light !== void 0 && e.substrate !== void 0 && e.surface !== void 0 && e.availability === void 0 && e.noiseFloorCalibration === void 0 && e.varianceDecomposition === void 0 && e.lifecycleTransition === void 0 && e.evalRecommendation === void 0 && e.conformanceFixtureRecord === void 0;
|
|
5012
|
+
return e.light !== void 0 && e.substrate !== void 0 && e.surface !== void 0 && e.availability === void 0 && e.noiseFloorCalibration === void 0 && e.varianceDecomposition === void 0 && e.lifecycleTransition === void 0 && e.evalRecommendation === void 0 && e.conformanceFixtureRecord === void 0 && e.emissionCoverage === void 0 && e.deliveryOrphan === void 0;
|
|
4979
5013
|
}
|
|
4980
5014
|
if (e.kind === "availability.transition") {
|
|
4981
|
-
return e.availability !== void 0 && e.light === void 0 && e.substrate === void 0 && e.surface === void 0 && e.noiseFloorCalibration === void 0 && e.varianceDecomposition === void 0 && e.lifecycleTransition === void 0 && e.evalRecommendation === void 0 && e.conformanceFixtureRecord === void 0;
|
|
5015
|
+
return e.availability !== void 0 && e.light === void 0 && e.substrate === void 0 && e.surface === void 0 && e.noiseFloorCalibration === void 0 && e.varianceDecomposition === void 0 && e.lifecycleTransition === void 0 && e.evalRecommendation === void 0 && e.conformanceFixtureRecord === void 0 && e.emissionCoverage === void 0 && e.deliveryOrphan === void 0;
|
|
4982
5016
|
}
|
|
4983
5017
|
if (e.kind === "analysis.noise-floor-calibration") {
|
|
4984
|
-
return e.noiseFloorCalibration !== void 0 && e.light === void 0 && e.substrate === void 0 && e.surface === void 0 && e.availability === void 0 && e.varianceDecomposition === void 0 && e.lifecycleTransition === void 0 && e.evalRecommendation === void 0 && e.conformanceFixtureRecord === void 0;
|
|
5018
|
+
return e.noiseFloorCalibration !== void 0 && e.light === void 0 && e.substrate === void 0 && e.surface === void 0 && e.availability === void 0 && e.varianceDecomposition === void 0 && e.lifecycleTransition === void 0 && e.evalRecommendation === void 0 && e.conformanceFixtureRecord === void 0 && e.emissionCoverage === void 0 && e.deliveryOrphan === void 0;
|
|
4985
5019
|
}
|
|
4986
5020
|
if (e.kind === "analysis.variance-decomposition") {
|
|
4987
|
-
return e.varianceDecomposition !== void 0 && e.light === void 0 && e.substrate === void 0 && e.surface === void 0 && e.availability === void 0 && e.noiseFloorCalibration === void 0 && e.lifecycleTransition === void 0 && e.evalRecommendation === void 0 && e.conformanceFixtureRecord === void 0;
|
|
5021
|
+
return e.varianceDecomposition !== void 0 && e.light === void 0 && e.substrate === void 0 && e.surface === void 0 && e.availability === void 0 && e.noiseFloorCalibration === void 0 && e.lifecycleTransition === void 0 && e.evalRecommendation === void 0 && e.conformanceFixtureRecord === void 0 && e.emissionCoverage === void 0 && e.deliveryOrphan === void 0;
|
|
4988
5022
|
}
|
|
4989
5023
|
if (e.kind === "analysis.lifecycle-transition") {
|
|
4990
|
-
return e.lifecycleTransition !== void 0 && e.light === void 0 && e.substrate === void 0 && e.surface === void 0 && e.availability === void 0 && e.noiseFloorCalibration === void 0 && e.varianceDecomposition === void 0 && e.evalRecommendation === void 0 && e.conformanceFixtureRecord === void 0;
|
|
5024
|
+
return e.lifecycleTransition !== void 0 && e.light === void 0 && e.substrate === void 0 && e.surface === void 0 && e.availability === void 0 && e.noiseFloorCalibration === void 0 && e.varianceDecomposition === void 0 && e.evalRecommendation === void 0 && e.conformanceFixtureRecord === void 0 && e.emissionCoverage === void 0 && e.deliveryOrphan === void 0;
|
|
4991
5025
|
}
|
|
4992
5026
|
if (e.kind === "analysis.eval-recommendation") {
|
|
4993
|
-
return e.evalRecommendation !== void 0 && e.light === void 0 && e.substrate === void 0 && e.surface === void 0 && e.availability === void 0 && e.noiseFloorCalibration === void 0 && e.varianceDecomposition === void 0 && e.lifecycleTransition === void 0 && e.conformanceFixtureRecord === void 0;
|
|
5027
|
+
return e.evalRecommendation !== void 0 && e.light === void 0 && e.substrate === void 0 && e.surface === void 0 && e.availability === void 0 && e.noiseFloorCalibration === void 0 && e.varianceDecomposition === void 0 && e.lifecycleTransition === void 0 && e.conformanceFixtureRecord === void 0 && e.emissionCoverage === void 0 && e.deliveryOrphan === void 0;
|
|
5028
|
+
}
|
|
5029
|
+
if (e.kind === "analysis.conformance-fixture") {
|
|
5030
|
+
return e.conformanceFixtureRecord !== void 0 && e.light === void 0 && e.substrate === void 0 && e.surface === void 0 && e.availability === void 0 && e.noiseFloorCalibration === void 0 && e.varianceDecomposition === void 0 && e.lifecycleTransition === void 0 && e.evalRecommendation === void 0 && e.emissionCoverage === void 0 && e.deliveryOrphan === void 0;
|
|
5031
|
+
}
|
|
5032
|
+
if (e.kind === "analysis.emission-coverage") {
|
|
5033
|
+
return e.emissionCoverage !== void 0 && e.light === void 0 && e.substrate === void 0 && e.surface === void 0 && e.availability === void 0 && e.noiseFloorCalibration === void 0 && e.varianceDecomposition === void 0 && e.lifecycleTransition === void 0 && e.evalRecommendation === void 0 && e.conformanceFixtureRecord === void 0 && e.deliveryOrphan === void 0;
|
|
4994
5034
|
}
|
|
4995
|
-
return e.
|
|
5035
|
+
return e.deliveryOrphan !== void 0 && e.emissionCoverage === void 0 && e.light === void 0 && e.substrate === void 0 && e.surface === void 0 && e.availability === void 0 && e.noiseFloorCalibration === void 0 && e.varianceDecomposition === void 0 && e.lifecycleTransition === void 0 && e.evalRecommendation === void 0 && e.conformanceFixtureRecord === void 0;
|
|
4996
5036
|
},
|
|
4997
5037
|
{
|
|
4998
|
-
message: "EvaluationEvent shape invariant: each kind requires exactly its corresponding payload and forbids the others. kind='evaluation' \u2192 light+substrate+surface; kind='availability.transition' \u2192 availability; kind='analysis.noise-floor-calibration' \u2192 noiseFloorCalibration; kind='analysis.variance-decomposition' \u2192 varianceDecomposition; kind='analysis.lifecycle-transition' \u2192 lifecycleTransition; kind='analysis.eval-recommendation' \u2192 evalRecommendation; kind='analysis.conformance-fixture' \u2192 conformanceFixtureRecord."
|
|
5038
|
+
message: "EvaluationEvent shape invariant: each kind requires exactly its corresponding payload and forbids the others. kind='evaluation' \u2192 light+substrate+surface; kind='availability.transition' \u2192 availability; kind='analysis.noise-floor-calibration' \u2192 noiseFloorCalibration; kind='analysis.variance-decomposition' \u2192 varianceDecomposition; kind='analysis.lifecycle-transition' \u2192 lifecycleTransition; kind='analysis.eval-recommendation' \u2192 evalRecommendation; kind='analysis.conformance-fixture' \u2192 conformanceFixtureRecord; kind='analysis.emission-coverage' \u2192 emissionCoverage; kind='analysis.delivery-orphan' \u2192 deliveryOrphan."
|
|
4999
5039
|
}
|
|
5000
5040
|
);
|
|
5001
5041
|
function newEventId(occurredAt = new Date()) {
|
|
@@ -5310,6 +5350,602 @@ var InProcessTransport = class {
|
|
|
5310
5350
|
}
|
|
5311
5351
|
};
|
|
5312
5352
|
|
|
5353
|
+
var BoundedEmitBuffer = class {
|
|
5354
|
+
capacity;
|
|
5355
|
+
items = [];
|
|
5356
|
+
_offeredTotal = 0;
|
|
5357
|
+
_droppedTotal = 0;
|
|
5358
|
+
|
|
5359
|
+
constructor(capacity) {
|
|
5360
|
+
if (!Number.isInteger(capacity) || capacity < 1) {
|
|
5361
|
+
throw new RangeError(
|
|
5362
|
+
`BoundedEmitBuffer capacity must be a positive integer, got ${String(capacity)}`
|
|
5363
|
+
);
|
|
5364
|
+
}
|
|
5365
|
+
this.capacity = capacity;
|
|
5366
|
+
}
|
|
5367
|
+
|
|
5368
|
+
offer(item) {
|
|
5369
|
+
this._offeredTotal += 1;
|
|
5370
|
+
if (this.items.length >= this.capacity) {
|
|
5371
|
+
this._droppedTotal += 1;
|
|
5372
|
+
return false;
|
|
5373
|
+
}
|
|
5374
|
+
this.items.push(item);
|
|
5375
|
+
return true;
|
|
5376
|
+
}
|
|
5377
|
+
|
|
5378
|
+
drain() {
|
|
5379
|
+
if (this.items.length === 0) return [];
|
|
5380
|
+
const out = this.items;
|
|
5381
|
+
this.items = [];
|
|
5382
|
+
return out;
|
|
5383
|
+
}
|
|
5384
|
+
|
|
5385
|
+
get size() {
|
|
5386
|
+
return this.items.length;
|
|
5387
|
+
}
|
|
5388
|
+
|
|
5389
|
+
get maxSize() {
|
|
5390
|
+
return this.capacity;
|
|
5391
|
+
}
|
|
5392
|
+
|
|
5393
|
+
get offeredTotal() {
|
|
5394
|
+
return this._offeredTotal;
|
|
5395
|
+
}
|
|
5396
|
+
|
|
5397
|
+
get droppedTotal() {
|
|
5398
|
+
return this._droppedTotal;
|
|
5399
|
+
}
|
|
5400
|
+
};
|
|
5401
|
+
|
|
5402
|
+
var CompletenessAccounting = class {
|
|
5403
|
+
constructor(lensVersion, config, hooks = {}) {
|
|
5404
|
+
this.lensVersion = lensVersion;
|
|
5405
|
+
this.config = config;
|
|
5406
|
+
this.hooks = hooks;
|
|
5407
|
+
}
|
|
5408
|
+
lensVersion;
|
|
5409
|
+
config;
|
|
5410
|
+
hooks;
|
|
5411
|
+
windowStartMs = null;
|
|
5412
|
+
offered = 0;
|
|
5413
|
+
dropped = 0;
|
|
5414
|
+
delivered = 0;
|
|
5415
|
+
failed = 0;
|
|
5416
|
+
|
|
5417
|
+
channels = new Map();
|
|
5418
|
+
|
|
5419
|
+
sustainedSinceMs = null;
|
|
5420
|
+
|
|
5421
|
+
alerted = false;
|
|
5422
|
+
|
|
5423
|
+
recordOffer(nowMs, accepted) {
|
|
5424
|
+
this.openWindowIfNeeded(nowMs);
|
|
5425
|
+
this.offered += 1;
|
|
5426
|
+
if (!accepted) this.dropped += 1;
|
|
5427
|
+
}
|
|
5428
|
+
|
|
5429
|
+
recordFlush(nowMs, channel, delivered, failed) {
|
|
5430
|
+
this.openWindowIfNeeded(nowMs);
|
|
5431
|
+
this.delivered += delivered;
|
|
5432
|
+
this.failed += failed;
|
|
5433
|
+
const entry = this.channels.get(channel) ?? { attempted: 0, delivered: 0, failed: 0 };
|
|
5434
|
+
entry.attempted += delivered + failed;
|
|
5435
|
+
entry.delivered += delivered;
|
|
5436
|
+
entry.failed += failed;
|
|
5437
|
+
this.channels.set(channel, entry);
|
|
5438
|
+
}
|
|
5439
|
+
|
|
5440
|
+
maybeRollover(nowMs) {
|
|
5441
|
+
if (this.windowStartMs === null) return;
|
|
5442
|
+
if (nowMs - this.windowStartMs < this.config.windowMs) return;
|
|
5443
|
+
this.finalize(this.windowStartMs + this.config.windowMs);
|
|
5444
|
+
}
|
|
5445
|
+
|
|
5446
|
+
snapshot(nowMs) {
|
|
5447
|
+
if (this.windowStartMs === null) return null;
|
|
5448
|
+
return this.buildWindow(this.windowStartMs, nowMs);
|
|
5449
|
+
}
|
|
5450
|
+
|
|
5451
|
+
flushOpenWindow(nowMs) {
|
|
5452
|
+
if (this.windowStartMs === null) return;
|
|
5453
|
+
this.finalize(Math.max(nowMs, this.windowStartMs));
|
|
5454
|
+
}
|
|
5455
|
+
openWindowIfNeeded(nowMs) {
|
|
5456
|
+
this.windowStartMs ??= nowMs;
|
|
5457
|
+
}
|
|
5458
|
+
finalize(windowEndMs) {
|
|
5459
|
+
const start = this.windowStartMs;
|
|
5460
|
+
if (start === null) return;
|
|
5461
|
+
const window = this.buildWindow(start, windowEndMs);
|
|
5462
|
+
this.windowStartMs = null;
|
|
5463
|
+
this.offered = 0;
|
|
5464
|
+
this.dropped = 0;
|
|
5465
|
+
this.delivered = 0;
|
|
5466
|
+
this.failed = 0;
|
|
5467
|
+
this.channels.clear();
|
|
5468
|
+
this.hooks.onWindow?.(window);
|
|
5469
|
+
this.evaluateSustainedLoad(window);
|
|
5470
|
+
}
|
|
5471
|
+
buildWindow(startMs, endMs) {
|
|
5472
|
+
const completenessLowerBound = this.offered === 0 ? 1 : (this.offered - this.dropped) / this.offered;
|
|
5473
|
+
const channels = {};
|
|
5474
|
+
for (const [channel, entry] of this.channels) {
|
|
5475
|
+
channels[channel] = { ...entry };
|
|
5476
|
+
}
|
|
5477
|
+
return {
|
|
5478
|
+
lensVersion: this.lensVersion,
|
|
5479
|
+
windowStartMs: startMs,
|
|
5480
|
+
windowEndMs: endMs,
|
|
5481
|
+
offered: this.offered,
|
|
5482
|
+
dropped: this.dropped,
|
|
5483
|
+
delivered: this.delivered,
|
|
5484
|
+
failed: this.failed,
|
|
5485
|
+
channels,
|
|
5486
|
+
completenessLowerBound,
|
|
5487
|
+
biasFlag: this.dropped > 0
|
|
5488
|
+
};
|
|
5489
|
+
}
|
|
5490
|
+
evaluateSustainedLoad(window) {
|
|
5491
|
+
const rate = window.offered === 0 ? 0 : window.dropped / window.offered;
|
|
5492
|
+
if (rate >= this.config.dropRateThreshold && window.dropped > 0) {
|
|
5493
|
+
this.sustainedSinceMs ??= window.windowStartMs;
|
|
5494
|
+
const sustainedForMs = window.windowEndMs - this.sustainedSinceMs;
|
|
5495
|
+
if (sustainedForMs >= this.config.sustainedForMs && !this.alerted) {
|
|
5496
|
+
this.alerted = true;
|
|
5497
|
+
this.hooks.onExtremeSustainedLoad?.({
|
|
5498
|
+
lensVersion: this.lensVersion,
|
|
5499
|
+
sinceMs: this.sustainedSinceMs,
|
|
5500
|
+
firedAtMs: window.windowEndMs,
|
|
5501
|
+
sustainedForMs,
|
|
5502
|
+
dropRate: rate,
|
|
5503
|
+
dropRateThreshold: this.config.dropRateThreshold
|
|
5504
|
+
});
|
|
5505
|
+
}
|
|
5506
|
+
} else {
|
|
5507
|
+
this.sustainedSinceMs = null;
|
|
5508
|
+
this.alerted = false;
|
|
5509
|
+
}
|
|
5510
|
+
}
|
|
5511
|
+
};
|
|
5512
|
+
|
|
5513
|
+
var DEFAULT_BUFFER_SIZE = 2048;
|
|
5514
|
+
var DEFAULT_FLUSH_INTERVAL_MS = 1e3;
|
|
5515
|
+
var DEFAULT_WINDOW_MS = 1e4;
|
|
5516
|
+
var DEFAULT_DROP_RATE_THRESHOLD = 0.01;
|
|
5517
|
+
var DEFAULT_SUSTAINED_FOR_MS = 6e4;
|
|
5518
|
+
var DEFAULT_SENTINEL_INTERVAL_MS = 3e4;
|
|
5519
|
+
var streamIdFallbackCounter = 0;
|
|
5520
|
+
function generateStreamId(nowMs) {
|
|
5521
|
+
const cryptoObj = globalThis.crypto;
|
|
5522
|
+
if (typeof cryptoObj?.randomUUID === "function") return cryptoObj.randomUUID();
|
|
5523
|
+
streamIdFallbackCounter += 1;
|
|
5524
|
+
return `stream-${String(nowMs)}-${String(streamIdFallbackCounter)}`;
|
|
5525
|
+
}
|
|
5526
|
+
function defaultScheduleInterval(fn, ms) {
|
|
5527
|
+
const handle = setInterval(fn, ms);
|
|
5528
|
+
handle.unref?.();
|
|
5529
|
+
return () => {
|
|
5530
|
+
clearInterval(handle);
|
|
5531
|
+
};
|
|
5532
|
+
}
|
|
5533
|
+
var EvaluationEventEmitter = class {
|
|
5534
|
+
buffer;
|
|
5535
|
+
flushTargets;
|
|
5536
|
+
|
|
5537
|
+
sentinelTargets;
|
|
5538
|
+
accounting;
|
|
5539
|
+
now;
|
|
5540
|
+
onFlushError;
|
|
5541
|
+
stopInterval;
|
|
5542
|
+
stopSentinelInterval;
|
|
5543
|
+
|
|
5544
|
+
streamId;
|
|
5545
|
+
nextSeq = 0;
|
|
5546
|
+
|
|
5547
|
+
lastSeq = -1;
|
|
5548
|
+
|
|
5549
|
+
emitsSentinels;
|
|
5550
|
+
|
|
5551
|
+
inFlight = null;
|
|
5552
|
+
stopped = false;
|
|
5553
|
+
constructor(opts) {
|
|
5554
|
+
this.buffer = new BoundedEmitBuffer(opts.bufferSize ?? DEFAULT_BUFFER_SIZE);
|
|
5555
|
+
if (opts.flushTargets.length === 0) {
|
|
5556
|
+
throw new Error("EvaluationEventEmitter requires at least one flush target");
|
|
5557
|
+
}
|
|
5558
|
+
this.flushTargets = [...opts.flushTargets];
|
|
5559
|
+
this.sentinelTargets = this.flushTargets.filter((t) => typeof t.emitSentinel === "function");
|
|
5560
|
+
this.now = opts.now ?? Date.now;
|
|
5561
|
+
this.streamId = opts.streamId ?? generateStreamId(this.now());
|
|
5562
|
+
this.emitsSentinels = opts.deployment !== "serverless";
|
|
5563
|
+
this.onFlushError = opts.onFlushError ?? ((error) => {
|
|
5564
|
+
console.warn("[holonograph] emit flush error:", error);
|
|
5565
|
+
});
|
|
5566
|
+
const config = {
|
|
5567
|
+
windowMs: opts.windowMs ?? DEFAULT_WINDOW_MS,
|
|
5568
|
+
dropRateThreshold: opts.extremeSustainedLoad?.dropRateThreshold ?? DEFAULT_DROP_RATE_THRESHOLD,
|
|
5569
|
+
sustainedForMs: opts.extremeSustainedLoad?.sustainedForMs ?? DEFAULT_SUSTAINED_FOR_MS
|
|
5570
|
+
};
|
|
5571
|
+
this.accounting = new CompletenessAccounting(opts.lensVersion, config, {
|
|
5572
|
+
...opts.onWindow !== void 0 ? { onWindow: opts.onWindow } : {},
|
|
5573
|
+
...opts.onExtremeSustainedLoad !== void 0 ? { onExtremeSustainedLoad: opts.onExtremeSustainedLoad } : {}
|
|
5574
|
+
});
|
|
5575
|
+
const schedule = opts.scheduleInterval ?? defaultScheduleInterval;
|
|
5576
|
+
this.stopInterval = schedule(() => {
|
|
5577
|
+
this.tick();
|
|
5578
|
+
}, opts.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS);
|
|
5579
|
+
this.stopSentinelInterval = this.emitsSentinels ? schedule(() => {
|
|
5580
|
+
this.sentinelTick();
|
|
5581
|
+
}, opts.sentinelIntervalMs ?? DEFAULT_SENTINEL_INTERVAL_MS) : () => {
|
|
5582
|
+
};
|
|
5583
|
+
}
|
|
5584
|
+
|
|
5585
|
+
enqueue(event) {
|
|
5586
|
+
const nowMs = this.now();
|
|
5587
|
+
const seq = this.nextSeq;
|
|
5588
|
+
this.nextSeq += 1;
|
|
5589
|
+
this.lastSeq = seq;
|
|
5590
|
+
const stamped = event.emissionStreamId === void 0 ? { ...event, emissionStreamId: this.streamId } : event;
|
|
5591
|
+
const accepted = this.buffer.offer({ event: stamped, seq, streamId: this.streamId });
|
|
5592
|
+
this.accounting.recordOffer(nowMs, accepted);
|
|
5593
|
+
this.accounting.maybeRollover(nowMs);
|
|
5594
|
+
return event.eventId;
|
|
5595
|
+
}
|
|
5596
|
+
|
|
5597
|
+
tick() {
|
|
5598
|
+
void this.flushNow();
|
|
5599
|
+
this.accounting.maybeRollover(this.now());
|
|
5600
|
+
}
|
|
5601
|
+
|
|
5602
|
+
sentinelTick() {
|
|
5603
|
+
if (this.lastSeq < 0) return;
|
|
5604
|
+
void this.emitSentinelNow(false);
|
|
5605
|
+
}
|
|
5606
|
+
|
|
5607
|
+
async emitSentinelNow(final) {
|
|
5608
|
+
if (!this.emitsSentinels) return;
|
|
5609
|
+
if (this.sentinelTargets.length === 0) return;
|
|
5610
|
+
const sentinel = { streamId: this.streamId, seq: this.lastSeq, final };
|
|
5611
|
+
await Promise.all(
|
|
5612
|
+
this.sentinelTargets.map(
|
|
5613
|
+
(t) => (t.emitSentinel?.(sentinel) ?? Promise.resolve()).catch((error) => {
|
|
5614
|
+
this.onFlushError(error);
|
|
5615
|
+
})
|
|
5616
|
+
)
|
|
5617
|
+
);
|
|
5618
|
+
}
|
|
5619
|
+
|
|
5620
|
+
flushNow() {
|
|
5621
|
+
if (this.inFlight) return this.inFlight;
|
|
5622
|
+
const batch = this.buffer.drain();
|
|
5623
|
+
if (batch.length === 0) return Promise.resolve();
|
|
5624
|
+
const flush = this.doFlush(batch).finally(() => {
|
|
5625
|
+
this.inFlight = null;
|
|
5626
|
+
});
|
|
5627
|
+
this.inFlight = flush;
|
|
5628
|
+
return flush;
|
|
5629
|
+
}
|
|
5630
|
+
async doFlush(batch) {
|
|
5631
|
+
await Promise.all(this.flushTargets.map((target) => this.flushToTarget(target, batch)));
|
|
5632
|
+
}
|
|
5633
|
+
async flushToTarget(target, batch) {
|
|
5634
|
+
const channel = target.channel;
|
|
5635
|
+
try {
|
|
5636
|
+
const result = await target.flushBatch(batch);
|
|
5637
|
+
this.accounting.recordFlush(this.now(), channel, result.delivered, result.failed);
|
|
5638
|
+
for (const error of result.errors) this.onFlushError(error);
|
|
5639
|
+
} catch (error) {
|
|
5640
|
+
this.accounting.recordFlush(this.now(), channel, 0, batch.length);
|
|
5641
|
+
this.onFlushError(error);
|
|
5642
|
+
}
|
|
5643
|
+
}
|
|
5644
|
+
|
|
5645
|
+
snapshotWindow() {
|
|
5646
|
+
return this.accounting.snapshot(this.now());
|
|
5647
|
+
}
|
|
5648
|
+
|
|
5649
|
+
async shutdown() {
|
|
5650
|
+
if (this.stopped) return;
|
|
5651
|
+
this.stopped = true;
|
|
5652
|
+
this.stopInterval();
|
|
5653
|
+
this.stopSentinelInterval();
|
|
5654
|
+
while (this.buffer.size > 0 || this.inFlight) {
|
|
5655
|
+
await this.flushNow();
|
|
5656
|
+
}
|
|
5657
|
+
if (this.lastSeq >= 0) await this.emitSentinelNow(true);
|
|
5658
|
+
await Promise.all(this.flushTargets.map((t) => t.shutdown?.() ?? Promise.resolve()));
|
|
5659
|
+
this.accounting.flushOpenWindow(this.now());
|
|
5660
|
+
}
|
|
5661
|
+
};
|
|
5662
|
+
|
|
5663
|
+
var HttpEventFlushTarget = class {
|
|
5664
|
+
|
|
5665
|
+
constructor(postEvent) {
|
|
5666
|
+
this.postEvent = postEvent;
|
|
5667
|
+
}
|
|
5668
|
+
postEvent;
|
|
5669
|
+
|
|
5670
|
+
channel = "http";
|
|
5671
|
+
async flushBatch(items) {
|
|
5672
|
+
let delivered = 0;
|
|
5673
|
+
let failed = 0;
|
|
5674
|
+
const errors = [];
|
|
5675
|
+
for (const item of items) {
|
|
5676
|
+
try {
|
|
5677
|
+
await this.postEvent(item.event);
|
|
5678
|
+
delivered += 1;
|
|
5679
|
+
} catch (error) {
|
|
5680
|
+
failed += 1;
|
|
5681
|
+
errors.push(error);
|
|
5682
|
+
}
|
|
5683
|
+
}
|
|
5684
|
+
return { delivered, failed, errors };
|
|
5685
|
+
}
|
|
5686
|
+
};
|
|
5687
|
+
|
|
5688
|
+
var EVALUATION_SPAN_NAME = "holonograph.evaluation";
|
|
5689
|
+
var DIMENSION_EVENT_NAME = "holonograph.dimension";
|
|
5690
|
+
var SENTINEL_SPAN_NAME = "holonograph.session.sentinel";
|
|
5691
|
+
var SPAN_ATTR = {
|
|
5692
|
+
eventId: "holonograph.event.id",
|
|
5693
|
+
correlationId: "holonograph.correlation_id",
|
|
5694
|
+
surfaceId: "holonograph.surface.id",
|
|
5695
|
+
fixtureId: "holonograph.surface.fixture_id",
|
|
5696
|
+
passed: "holonograph.surface.passed",
|
|
5697
|
+
cohortTags: "holonograph.surface.cohort_tags",
|
|
5698
|
+
lensVersion: "holonograph.lens.version",
|
|
5699
|
+
lightSourceId: "holonograph.light_source.id",
|
|
5700
|
+
runMode: "holonograph.run_mode",
|
|
5701
|
+
provenance: "holonograph.provenance",
|
|
5702
|
+
latencyMs: "holonograph.light.latency_ms",
|
|
5703
|
+
tokensInput: "holonograph.light.tokens.input",
|
|
5704
|
+
tokensOutput: "holonograph.light.tokens.output",
|
|
5705
|
+
ok: "holonograph.light.ok",
|
|
5706
|
+
|
|
5707
|
+
rawResponseLocation: "holonograph.raw_response.location",
|
|
5708
|
+
|
|
5709
|
+
substratePrefix: "holonograph.substrate.",
|
|
5710
|
+
dimensionId: "holonograph.dimension.id",
|
|
5711
|
+
dimensionPassed: "holonograph.dimension.passed",
|
|
5712
|
+
dimensionScore: "holonograph.dimension.score",
|
|
5713
|
+
|
|
5714
|
+
emissionSeq: "holonograph.emission.seq",
|
|
5715
|
+
emissionStream: "holonograph.emission.stream",
|
|
5716
|
+
|
|
5717
|
+
emissionFinal: "holonograph.emission.final"
|
|
5718
|
+
};
|
|
5719
|
+
function buildEvaluationSpanData(event, emission, options) {
|
|
5720
|
+
const light = event.light;
|
|
5721
|
+
const surface = event.surface;
|
|
5722
|
+
const substrate = event.substrate;
|
|
5723
|
+
const startTimeMs = Date.parse(event.occurredAt);
|
|
5724
|
+
const latencyMs = typeof light?.latencyMs === "number" ? light.latencyMs : 0;
|
|
5725
|
+
const endTimeMs = startTimeMs + latencyMs;
|
|
5726
|
+
const isError = light?.error !== void 0;
|
|
5727
|
+
const attributes = {
|
|
5728
|
+
[SPAN_ATTR.eventId]: event.eventId,
|
|
5729
|
+
[SPAN_ATTR.correlationId]: event.correlationId,
|
|
5730
|
+
[SPAN_ATTR.surfaceId]: event.surfaceId,
|
|
5731
|
+
[SPAN_ATTR.lensVersion]: event.lensVersion,
|
|
5732
|
+
[SPAN_ATTR.ok]: !isError,
|
|
5733
|
+
|
|
5734
|
+
[SPAN_ATTR.rawResponseLocation]: options?.rawResponseLocation ?? "store"
|
|
5735
|
+
};
|
|
5736
|
+
if (surface !== void 0) {
|
|
5737
|
+
attributes[SPAN_ATTR.fixtureId] = surface.fixtureId;
|
|
5738
|
+
attributes[SPAN_ATTR.passed] = surface.passed;
|
|
5739
|
+
attributes[SPAN_ATTR.cohortTags] = [...surface.cohortTags];
|
|
5740
|
+
}
|
|
5741
|
+
if (substrate !== void 0) {
|
|
5742
|
+
attributes[SPAN_ATTR.lightSourceId] = substrate.lightSourceIdentifier;
|
|
5743
|
+
attributes[SPAN_ATTR.runMode] = substrate.runMode;
|
|
5744
|
+
attributes[SPAN_ATTR.provenance] = substrate.provenance;
|
|
5745
|
+
for (const [key, value] of Object.entries(substrate.columns)) {
|
|
5746
|
+
attributes[`${SPAN_ATTR.substratePrefix}${key}`] = value;
|
|
5747
|
+
}
|
|
5748
|
+
}
|
|
5749
|
+
if (typeof light?.latencyMs === "number") attributes[SPAN_ATTR.latencyMs] = light.latencyMs;
|
|
5750
|
+
if (light?.tokens?.input !== void 0) attributes[SPAN_ATTR.tokensInput] = light.tokens.input;
|
|
5751
|
+
if (light?.tokens?.output !== void 0) attributes[SPAN_ATTR.tokensOutput] = light.tokens.output;
|
|
5752
|
+
if (emission !== void 0) {
|
|
5753
|
+
attributes[SPAN_ATTR.emissionSeq] = emission.seq;
|
|
5754
|
+
attributes[SPAN_ATTR.emissionStream] = emission.streamId;
|
|
5755
|
+
}
|
|
5756
|
+
const dimensionEvents = (surface?.dimensions ?? []).map((d) => {
|
|
5757
|
+
const attrs = {
|
|
5758
|
+
[SPAN_ATTR.dimensionId]: d.dimensionId,
|
|
5759
|
+
[SPAN_ATTR.dimensionPassed]: d.passed
|
|
5760
|
+
};
|
|
5761
|
+
if (d.score !== void 0) attrs[SPAN_ATTR.dimensionScore] = d.score;
|
|
5762
|
+
return { name: DIMENSION_EVENT_NAME, attributes: attrs };
|
|
5763
|
+
});
|
|
5764
|
+
return {
|
|
5765
|
+
name: EVALUATION_SPAN_NAME,
|
|
5766
|
+
startTimeMs,
|
|
5767
|
+
endTimeMs,
|
|
5768
|
+
attributes,
|
|
5769
|
+
dimensionEvents,
|
|
5770
|
+
isError,
|
|
5771
|
+
errorMessage: light?.error?.message
|
|
5772
|
+
};
|
|
5773
|
+
}
|
|
5774
|
+
function writeEvaluationSpan(tracer, event, otel, emission, options) {
|
|
5775
|
+
const data = buildEvaluationSpanData(event, emission, options);
|
|
5776
|
+
const span = tracer.startSpan(data.name, {
|
|
5777
|
+
startTime: data.startTimeMs,
|
|
5778
|
+
kind: otel.SpanKindClient,
|
|
5779
|
+
attributes: data.attributes
|
|
5780
|
+
});
|
|
5781
|
+
for (const ev of data.dimensionEvents) span.addEvent(ev.name, ev.attributes);
|
|
5782
|
+
if (data.isError) {
|
|
5783
|
+
span.setStatus(
|
|
5784
|
+
data.errorMessage !== void 0 ? { code: otel.statusError, message: data.errorMessage } : { code: otel.statusError }
|
|
5785
|
+
);
|
|
5786
|
+
} else {
|
|
5787
|
+
span.setStatus({ code: otel.statusOk });
|
|
5788
|
+
}
|
|
5789
|
+
span.end(data.endTimeMs);
|
|
5790
|
+
}
|
|
5791
|
+
function writeSentinelSpan(tracer, sentinel, otel) {
|
|
5792
|
+
const span = tracer.startSpan(SENTINEL_SPAN_NAME, {
|
|
5793
|
+
kind: otel.SpanKindClient,
|
|
5794
|
+
attributes: {
|
|
5795
|
+
[SPAN_ATTR.emissionStream]: sentinel.streamId,
|
|
5796
|
+
[SPAN_ATTR.emissionSeq]: sentinel.seq,
|
|
5797
|
+
[SPAN_ATTR.emissionFinal]: sentinel.final
|
|
5798
|
+
}
|
|
5799
|
+
});
|
|
5800
|
+
span.setStatus({ code: otel.statusOk });
|
|
5801
|
+
span.end();
|
|
5802
|
+
}
|
|
5803
|
+
|
|
5804
|
+
function reconcileBatchDelivery(batchSize, delivered, exportFailed) {
|
|
5805
|
+
const shed = Math.max(0, batchSize - delivered - exportFailed);
|
|
5806
|
+
return { delivered, failed: exportFailed + shed };
|
|
5807
|
+
}
|
|
5808
|
+
var CountingExporter = class {
|
|
5809
|
+
constructor(inner, tally, successCode) {
|
|
5810
|
+
this.inner = inner;
|
|
5811
|
+
this.tally = tally;
|
|
5812
|
+
this.successCode = successCode;
|
|
5813
|
+
}
|
|
5814
|
+
inner;
|
|
5815
|
+
tally;
|
|
5816
|
+
successCode;
|
|
5817
|
+
export(spans, resultCallback) {
|
|
5818
|
+
this.inner.export(spans, (result) => {
|
|
5819
|
+
if (result.code === this.successCode) {
|
|
5820
|
+
this.tally.delivered += spans.length;
|
|
5821
|
+
} else {
|
|
5822
|
+
this.tally.failed += spans.length;
|
|
5823
|
+
if (result.error) this.tally.errors.push(result.error);
|
|
5824
|
+
}
|
|
5825
|
+
resultCallback(result);
|
|
5826
|
+
});
|
|
5827
|
+
}
|
|
5828
|
+
shutdown() {
|
|
5829
|
+
return this.inner.shutdown();
|
|
5830
|
+
}
|
|
5831
|
+
forceFlush() {
|
|
5832
|
+
return this.inner.forceFlush?.() ?? Promise.resolve();
|
|
5833
|
+
}
|
|
5834
|
+
};
|
|
5835
|
+
var OtlpEventFlushTarget = class {
|
|
5836
|
+
channel = "otlp";
|
|
5837
|
+
options;
|
|
5838
|
+
tally = { delivered: 0, failed: 0, errors: [] };
|
|
5839
|
+
provider;
|
|
5840
|
+
tracer;
|
|
5841
|
+
otel;
|
|
5842
|
+
initPromise;
|
|
5843
|
+
|
|
5844
|
+
opLock = Promise.resolve();
|
|
5845
|
+
constructor(options) {
|
|
5846
|
+
this.options = options;
|
|
5847
|
+
}
|
|
5848
|
+
|
|
5849
|
+
serialize(fn) {
|
|
5850
|
+
const run = this.opLock.then(fn, fn);
|
|
5851
|
+
this.opLock = run.then(
|
|
5852
|
+
() => void 0,
|
|
5853
|
+
() => void 0
|
|
5854
|
+
);
|
|
5855
|
+
return run;
|
|
5856
|
+
}
|
|
5857
|
+
flushBatch(items) {
|
|
5858
|
+
return this.serialize(() => this.doFlushBatch(items));
|
|
5859
|
+
}
|
|
5860
|
+
async doFlushBatch(items) {
|
|
5861
|
+
await this.ensureInit();
|
|
5862
|
+
const tracer = this.tracer;
|
|
5863
|
+
const otel = this.otel;
|
|
5864
|
+
const provider = this.provider;
|
|
5865
|
+
if (!tracer || !otel || !provider) {
|
|
5866
|
+
return {
|
|
5867
|
+
delivered: 0,
|
|
5868
|
+
failed: items.length,
|
|
5869
|
+
errors: [new Error("OTLP target not initialized")]
|
|
5870
|
+
};
|
|
5871
|
+
}
|
|
5872
|
+
const beforeDelivered = this.tally.delivered;
|
|
5873
|
+
const beforeFailed = this.tally.failed;
|
|
5874
|
+
const beforeErrors = this.tally.errors.length;
|
|
5875
|
+
const spanOptions = {
|
|
5876
|
+
rawResponseLocation: this.options.rawResponseLocation ?? "store"
|
|
5877
|
+
};
|
|
5878
|
+
for (const item of items) {
|
|
5879
|
+
writeEvaluationSpan(
|
|
5880
|
+
tracer,
|
|
5881
|
+
item.event,
|
|
5882
|
+
otel,
|
|
5883
|
+
{ seq: item.seq, streamId: item.streamId },
|
|
5884
|
+
spanOptions
|
|
5885
|
+
);
|
|
5886
|
+
}
|
|
5887
|
+
await provider.forceFlush();
|
|
5888
|
+
const delivered = this.tally.delivered - beforeDelivered;
|
|
5889
|
+
const exportFailed = this.tally.failed - beforeFailed;
|
|
5890
|
+
const reconciled = reconcileBatchDelivery(items.length, delivered, exportFailed);
|
|
5891
|
+
return { ...reconciled, errors: this.tally.errors.slice(beforeErrors) };
|
|
5892
|
+
}
|
|
5893
|
+
|
|
5894
|
+
emitSentinel(sentinel) {
|
|
5895
|
+
return this.serialize(async () => {
|
|
5896
|
+
await this.ensureInit();
|
|
5897
|
+
if (!this.tracer || !this.otel || !this.provider) return;
|
|
5898
|
+
writeSentinelSpan(this.tracer, sentinel, this.otel);
|
|
5899
|
+
await this.provider.forceFlush();
|
|
5900
|
+
});
|
|
5901
|
+
}
|
|
5902
|
+
async shutdown() {
|
|
5903
|
+
if (this.provider) await this.provider.shutdown();
|
|
5904
|
+
}
|
|
5905
|
+
|
|
5906
|
+
ensureInit() {
|
|
5907
|
+
this.initPromise ??= this.doInit();
|
|
5908
|
+
return this.initPromise;
|
|
5909
|
+
}
|
|
5910
|
+
async doInit() {
|
|
5911
|
+
const [api, sdk, resources, core] = await Promise.all([
|
|
5912
|
+
import('@opentelemetry/api'),
|
|
5913
|
+
import('@opentelemetry/sdk-trace-base'),
|
|
5914
|
+
import('@opentelemetry/resources'),
|
|
5915
|
+
import('@opentelemetry/core')
|
|
5916
|
+
]);
|
|
5917
|
+
let exporter;
|
|
5918
|
+
if (this.options.exporter) {
|
|
5919
|
+
exporter = this.options.exporter;
|
|
5920
|
+
} else {
|
|
5921
|
+
const otlp = await import('@opentelemetry/exporter-trace-otlp-http');
|
|
5922
|
+
const exporterConfig = {};
|
|
5923
|
+
if (this.options.endpoint !== void 0) exporterConfig.url = this.options.endpoint;
|
|
5924
|
+
if (this.options.headers !== void 0) exporterConfig.headers = this.options.headers;
|
|
5925
|
+
exporter = new otlp.OTLPTraceExporter(exporterConfig);
|
|
5926
|
+
}
|
|
5927
|
+
const counting = new CountingExporter(exporter, this.tally, core.ExportResultCode.SUCCESS);
|
|
5928
|
+
const resource = resources.resourceFromAttributes({
|
|
5929
|
+
"service.name": "holonograph-client",
|
|
5930
|
+
"holonograph.lens.version": this.options.lensVersion
|
|
5931
|
+
});
|
|
5932
|
+
this.provider = new sdk.BasicTracerProvider({
|
|
5933
|
+
resource,
|
|
5934
|
+
spanProcessors: [
|
|
5935
|
+
new sdk.BatchSpanProcessor(counting, {
|
|
5936
|
+
maxQueueSize: this.options.maxQueueSize ?? 4096
|
|
5937
|
+
})
|
|
5938
|
+
]
|
|
5939
|
+
});
|
|
5940
|
+
this.tracer = this.provider.getTracer("holonograph-client");
|
|
5941
|
+
this.otel = {
|
|
5942
|
+
SpanKindClient: api.SpanKind.CLIENT,
|
|
5943
|
+
statusOk: api.SpanStatusCode.OK,
|
|
5944
|
+
statusError: api.SpanStatusCode.ERROR
|
|
5945
|
+
};
|
|
5946
|
+
}
|
|
5947
|
+
};
|
|
5948
|
+
|
|
5313
5949
|
var HolonographHttpError = class extends Error {
|
|
5314
5950
|
constructor(status, code, message, details) {
|
|
5315
5951
|
super(message);
|
|
@@ -5327,11 +5963,53 @@ var HttpTransport = class {
|
|
|
5327
5963
|
token;
|
|
5328
5964
|
fetchImpl;
|
|
5329
5965
|
runMode;
|
|
5966
|
+
|
|
5967
|
+
emitter;
|
|
5330
5968
|
constructor(opts) {
|
|
5331
5969
|
this.endpoint = opts.endpoint.replace(/\/$/, "");
|
|
5332
5970
|
this.token = opts.token;
|
|
5333
5971
|
this.fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
5334
5972
|
this.runMode = opts.runMode;
|
|
5973
|
+
const e = opts.emit;
|
|
5974
|
+
const mode = e?.mode;
|
|
5975
|
+
if (e !== void 0 && (mode === "buffered" || mode === "otlp" || mode === "dual")) {
|
|
5976
|
+
const lensVersion = opts.lensVersion ?? "unknown";
|
|
5977
|
+
const flushTargets = [];
|
|
5978
|
+
if (mode === "buffered" || mode === "dual") {
|
|
5979
|
+
flushTargets.push(new HttpEventFlushTarget((event) => this.postEvent(event)));
|
|
5980
|
+
}
|
|
5981
|
+
if (mode === "otlp" || mode === "dual") {
|
|
5982
|
+
const otlpOpts = { lensVersion };
|
|
5983
|
+
if (e.otlp?.endpoint !== void 0) otlpOpts.endpoint = e.otlp.endpoint;
|
|
5984
|
+
if (e.otlp?.headers !== void 0) otlpOpts.headers = e.otlp.headers;
|
|
5985
|
+
otlpOpts.maxQueueSize = e.otlp?.maxQueueSize ?? (e.bufferSize ?? 2048) * 2;
|
|
5986
|
+
otlpOpts.rawResponseLocation = mode === "dual" ? "http-channel" : "store";
|
|
5987
|
+
flushTargets.push(new OtlpEventFlushTarget(otlpOpts));
|
|
5988
|
+
}
|
|
5989
|
+
if (e.deployment === "serverless" && e.streamId === void 0) {
|
|
5990
|
+
throw new Error(
|
|
5991
|
+
"emit.deployment 'serverless' requires a stable emit.streamId (e.g. the function name) \u2014 a per-request id would make streamCount track calls, not emitters. Completeness for a serverless emitter comes from reconciliation over that stable stream."
|
|
5992
|
+
);
|
|
5993
|
+
}
|
|
5994
|
+
const emitterOpts = { flushTargets, lensVersion };
|
|
5995
|
+
if (e.deployment !== void 0) emitterOpts.deployment = e.deployment;
|
|
5996
|
+
if (e.streamId !== void 0) emitterOpts.streamId = e.streamId;
|
|
5997
|
+
if (e.bufferSize !== void 0) emitterOpts.bufferSize = e.bufferSize;
|
|
5998
|
+
if (e.flushIntervalMs !== void 0) emitterOpts.flushIntervalMs = e.flushIntervalMs;
|
|
5999
|
+
if (e.sentinelIntervalMs !== void 0) emitterOpts.sentinelIntervalMs = e.sentinelIntervalMs;
|
|
6000
|
+
if (e.windowMs !== void 0) emitterOpts.windowMs = e.windowMs;
|
|
6001
|
+
if (e.extremeSustainedLoad !== void 0) {
|
|
6002
|
+
emitterOpts.extremeSustainedLoad = e.extremeSustainedLoad;
|
|
6003
|
+
}
|
|
6004
|
+
if (e.onWindow !== void 0) emitterOpts.onWindow = e.onWindow;
|
|
6005
|
+
if (e.onExtremeSustainedLoad !== void 0) {
|
|
6006
|
+
emitterOpts.onExtremeSustainedLoad = e.onExtremeSustainedLoad;
|
|
6007
|
+
}
|
|
6008
|
+
if (e.onFlushError !== void 0) emitterOpts.onFlushError = e.onFlushError;
|
|
6009
|
+
this.emitter = new EvaluationEventEmitter(emitterOpts);
|
|
6010
|
+
} else {
|
|
6011
|
+
this.emitter = void 0;
|
|
6012
|
+
}
|
|
5335
6013
|
}
|
|
5336
6014
|
async dispatch(req) {
|
|
5337
6015
|
const wire = await this.post(
|
|
@@ -5366,9 +6044,24 @@ var HttpTransport = class {
|
|
|
5366
6044
|
return result;
|
|
5367
6045
|
}
|
|
5368
6046
|
async appendEvent(event) {
|
|
6047
|
+
if (this.emitter) {
|
|
6048
|
+
return this.emitter.enqueue(event);
|
|
6049
|
+
}
|
|
5369
6050
|
const result = await this.post("/lens/events", event, event.correlationId);
|
|
5370
6051
|
return result.eventId;
|
|
5371
6052
|
}
|
|
6053
|
+
|
|
6054
|
+
async postEvent(event) {
|
|
6055
|
+
await this.post("/lens/events", event, event.correlationId);
|
|
6056
|
+
}
|
|
6057
|
+
|
|
6058
|
+
completenessWindow() {
|
|
6059
|
+
return this.emitter?.snapshotWindow() ?? null;
|
|
6060
|
+
}
|
|
6061
|
+
|
|
6062
|
+
async shutdown() {
|
|
6063
|
+
if (this.emitter) await this.emitter.shutdown();
|
|
6064
|
+
}
|
|
5372
6065
|
async postContract(contract) {
|
|
5373
6066
|
return this.post("/holonograph/contract", contract);
|
|
5374
6067
|
}
|
|
@@ -5494,6 +6187,7 @@ function flattenSystemBlocks(blocks) {
|
|
|
5494
6187
|
var HolonographClient = class {
|
|
5495
6188
|
transport;
|
|
5496
6189
|
inProcessTransport;
|
|
6190
|
+
httpTransport;
|
|
5497
6191
|
lensVersion;
|
|
5498
6192
|
substrate;
|
|
5499
6193
|
|
|
@@ -5513,12 +6207,17 @@ var HolonographClient = class {
|
|
|
5513
6207
|
constructor(options) {
|
|
5514
6208
|
if (isHttpOptions(options)) {
|
|
5515
6209
|
const httpOpts = {
|
|
5516
|
-
endpoint: options.endpoint
|
|
6210
|
+
endpoint: options.endpoint,
|
|
6211
|
+
|
|
6212
|
+
lensVersion: options.lensVersion
|
|
5517
6213
|
};
|
|
5518
6214
|
if (options.token !== void 0) httpOpts.token = options.token;
|
|
5519
6215
|
if (options.fetch !== void 0) httpOpts.fetch = options.fetch;
|
|
5520
6216
|
if (options.runMode !== void 0) httpOpts.runMode = options.runMode;
|
|
5521
|
-
|
|
6217
|
+
if (options.emit !== void 0) httpOpts.emit = options.emit;
|
|
6218
|
+
const t = new HttpTransport(httpOpts);
|
|
6219
|
+
this.transport = t;
|
|
6220
|
+
this.httpTransport = t;
|
|
5522
6221
|
this.inProcessTransport = void 0;
|
|
5523
6222
|
} else {
|
|
5524
6223
|
const inProcOpts = {
|
|
@@ -5529,6 +6228,7 @@ var HolonographClient = class {
|
|
|
5529
6228
|
const t = new InProcessTransport(inProcOpts);
|
|
5530
6229
|
this.transport = t;
|
|
5531
6230
|
this.inProcessTransport = t;
|
|
6231
|
+
this.httpTransport = void 0;
|
|
5532
6232
|
}
|
|
5533
6233
|
this.lensVersion = options.lensVersion;
|
|
5534
6234
|
this.substrate = options.substrate;
|
|
@@ -5588,6 +6288,14 @@ var HolonographClient = class {
|
|
|
5588
6288
|
return this.inProcessTransport ? this.inProcessTransport.topology : null;
|
|
5589
6289
|
}
|
|
5590
6290
|
|
|
6291
|
+
completenessWindow() {
|
|
6292
|
+
return this.httpTransport?.completenessWindow() ?? null;
|
|
6293
|
+
}
|
|
6294
|
+
|
|
6295
|
+
async shutdown() {
|
|
6296
|
+
if (this.httpTransport) await this.httpTransport.shutdown();
|
|
6297
|
+
}
|
|
6298
|
+
|
|
5591
6299
|
fetchDeclaredColumns(force = false) {
|
|
5592
6300
|
const getContract = this.transport.getContract?.bind(this.transport);
|
|
5593
6301
|
if (getContract === void 0) return Promise.resolve(null);
|