@eventual-ai/mcap-viewer 0.0.0-stage → 0.1.0-alpha.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/core.js ADDED
@@ -0,0 +1,534 @@
1
+ import { B as M, H as D, M as x } from "./recording-tVYbg6KM.js";
2
+ const w = "eventual.replay.v1.CompressedVideo";
3
+ function m(r) {
4
+ if (!r || typeof r != "object" || !("data" in r) || !(r.data instanceof Uint8Array) || !("format" in r) || typeof r.format != "string" || !("keyframe" in r) || typeof r.keyframe != "boolean")
5
+ throw new Error("Invalid CompressedVideo message");
6
+ return r;
7
+ }
8
+ function b(r) {
9
+ return r.schemaName === w;
10
+ }
11
+ function g(r) {
12
+ const e = m(r.value).decode_order;
13
+ if (typeof e != "string" || !/^\d+$/.test(e))
14
+ throw new Error("Video packet is missing a valid decode_order");
15
+ return BigInt(e);
16
+ }
17
+ const v = /* @__PURE__ */ new WeakMap();
18
+ function y(r, e) {
19
+ let t = v.get(e);
20
+ return t || (t = new E(r, e), v.set(e, t)), t;
21
+ }
22
+ class E {
23
+ constructor(e, t) {
24
+ this.channel = e, this.records = t;
25
+ const i = (s) => {
26
+ const o = e.metadata.get(s);
27
+ if (o === void 0 || !/^\d+$/.test(o))
28
+ throw new Error(`Missing or invalid ${s} video metadata`);
29
+ return BigInt(o);
30
+ };
31
+ if (this.start = i("video.decode_start"), this.end = i("video.decode_end"), this.lookahead = i("video.max_reorder_frames"), this.start > this.end) throw new Error("Invalid video decode interval");
32
+ this.contiguous = this.start - 1n;
33
+ }
34
+ channel;
35
+ records;
36
+ start;
37
+ end;
38
+ lookahead;
39
+ packets = /* @__PURE__ */ new Map();
40
+ keyframes = /* @__PURE__ */ new Map();
41
+ count = 0;
42
+ safeCount = 0;
43
+ contiguous;
44
+ update() {
45
+ for (; this.count < this.records.length; this.count++) {
46
+ const e = this.records[this.count], t = g(e);
47
+ if (t < this.start || t > this.end || this.packets.has(t))
48
+ throw new Error(
49
+ "Video decode_order is duplicated or outside the declared interval"
50
+ );
51
+ this.packets.set(t, e), m(e.value).keyframe && this.keyframes.set(t, e);
52
+ }
53
+ for (; this.packets.has(this.contiguous + 1n); ) this.contiguous++;
54
+ }
55
+ required(e) {
56
+ const t = g(e) + this.lookahead;
57
+ return t > this.end ? this.end : t;
58
+ }
59
+ target(e) {
60
+ let t = 0, i = this.records.length;
61
+ for (; t < i; ) {
62
+ const s = t + i >>> 1;
63
+ this.records[s].time <= e ? t = s + 1 : i = s;
64
+ }
65
+ return this.records[t - 1];
66
+ }
67
+ bufferedEnd(e, t) {
68
+ if (this.update(), t && this.contiguous !== this.end)
69
+ throw new Error("Incomplete video decode interval");
70
+ if (t) return e;
71
+ for (; this.safeCount < this.records.length && this.required(this.records[this.safeCount]) <= this.contiguous; )
72
+ this.safeCount++;
73
+ const i = this.records[this.safeCount];
74
+ return i && i.time <= e ? i.time - 1n : e;
75
+ }
76
+ snapshot(e) {
77
+ this.update();
78
+ const t = this.target(e);
79
+ if (!t) return [];
80
+ const i = g(t);
81
+ let s;
82
+ for (const [o, c] of this.keyframes)
83
+ o <= i && c.time <= e && (s === void 0 || o > s) && (s = o);
84
+ if (s === void 0)
85
+ throw new Error("MCAP is missing the preceding video keyframe");
86
+ return this.range(s, this.required(t));
87
+ }
88
+ after(e, t) {
89
+ this.update();
90
+ const i = this.target(e);
91
+ return i ? this.range(t + 1n, this.required(i)) : [];
92
+ }
93
+ range(e, t) {
94
+ if (t > this.contiguous)
95
+ throw new Error("Video decode dependencies are not buffered");
96
+ const i = [];
97
+ for (let s = e; s <= t; s++)
98
+ i.push(this.packets.get(s));
99
+ return i;
100
+ }
101
+ }
102
+ function k(r, e) {
103
+ const t = [];
104
+ for (const i of r.byTopic.values()) {
105
+ const s = i[0]?.channel;
106
+ s && b(s) && t.push(...y(s, i).snapshot(e));
107
+ }
108
+ return t;
109
+ }
110
+ const T = {
111
+ now: () => performance.now(),
112
+ request: (r) => requestAnimationFrame(r),
113
+ cancel: (r) => cancelAnimationFrame(r)
114
+ };
115
+ class q {
116
+ constructor(e, t = {}, i = T) {
117
+ this.recording = e, this.scheduler = i, this.time = e.start, this.subscribe(t), this.unsubscribeRecording = e.subscribe?.(() => this.onLoad());
118
+ }
119
+ recording;
120
+ scheduler;
121
+ time;
122
+ speed = 1;
123
+ playing = !1;
124
+ status = "paused";
125
+ closed = !1;
126
+ generation = 0;
127
+ frame;
128
+ anchorTime = 0n;
129
+ anchorWall = 0;
130
+ waitingForData = !1;
131
+ seekController;
132
+ video = /* @__PURE__ */ new Map();
133
+ submitted = /* @__PURE__ */ new Map();
134
+ unsubscribeRecording;
135
+ listeners = /* @__PURE__ */ new Set();
136
+ /** Subscribe a view or renderer to the shared playback clock and selected topics. */
137
+ subscribe(e, { topics: t } = {}) {
138
+ if (this.closed) throw new Error("Player is closed");
139
+ const i = {
140
+ listener: e,
141
+ topics: t ? new Set(t) : void 0
142
+ };
143
+ return this.listeners.add(i), () => {
144
+ this.listeners.delete(i);
145
+ };
146
+ }
147
+ emit() {
148
+ const e = {
149
+ time: this.time,
150
+ status: this.status,
151
+ playing: this.playing,
152
+ speed: this.speed
153
+ };
154
+ for (const { listener: t } of this.listeners) t.onState?.(e);
155
+ }
156
+ publish(e) {
157
+ this.submitted.set(e.channel.topic, g(e));
158
+ for (const { listener: t, topics: i } of this.listeners) {
159
+ if (this.closed) return;
160
+ (!i || i.has(e.channel.topic)) && t.onMessage?.(e.channel, e.time, e.value);
161
+ }
162
+ }
163
+ cancelFrame() {
164
+ this.frame !== void 0 && this.scheduler.cancel(this.frame), this.frame = void 0;
165
+ }
166
+ fail(e) {
167
+ this.generation++, this.seekController?.abort(), this.waitingForData = !1, this.playing = !1, this.status = "error", this.cancelFrame();
168
+ for (const { listener: t } of this.listeners)
169
+ t.onError?.(
170
+ e instanceof Error ? e : new Error(String(e))
171
+ );
172
+ this.emit();
173
+ }
174
+ availableEnd() {
175
+ for (const t of this.recording.byTopic.values()) {
176
+ const i = t[0]?.channel;
177
+ i && b(i) && !this.video.has(i.topic) && this.video.set(i.topic, y(i, t));
178
+ }
179
+ let e = this.recording.complete === !1 ? this.recording.bufferedEnd ?? this.recording.start - 1n : this.recording.end;
180
+ for (const t of this.video.values())
181
+ e = t.bufferedEnd(e, this.recording.complete !== !1);
182
+ return e;
183
+ }
184
+ endBuffered() {
185
+ return this.recording.complete !== !1 || this.recording.bounds !== void 0 && this.availableEnd() >= this.recording.end;
186
+ }
187
+ onLoad() {
188
+ if (this.closed) return;
189
+ if (this.recording.error) {
190
+ this.fail(this.recording.error);
191
+ return;
192
+ }
193
+ let e;
194
+ try {
195
+ e = this.availableEnd();
196
+ } catch (t) {
197
+ this.fail(t);
198
+ return;
199
+ }
200
+ this.waitingForData && this.playing && (this.recording.complete !== !1 || e !== void 0 && e > this.time) && (this.waitingForData = !1, this.anchorTime = this.time, this.anchorWall = this.scheduler.now(), this.status = "playing", this.frame = this.scheduler.request(() => {
201
+ this.tick();
202
+ })), this.emit();
203
+ }
204
+ waitForTime(e, t) {
205
+ return this.recording.error ? Promise.reject(this.recording.error) : this.availableEnd() >= e || this.recording.complete !== !1 ? Promise.resolve() : new Promise((i, s) => {
206
+ const o = () => {
207
+ a?.(), t.removeEventListener("abort", n);
208
+ }, c = () => {
209
+ if (this.recording.error)
210
+ o(), s(this.recording.error);
211
+ else
212
+ try {
213
+ (this.availableEnd() >= e || this.recording.complete !== !1) && (o(), i());
214
+ } catch (l) {
215
+ o(), s(l);
216
+ }
217
+ }, n = () => {
218
+ o(), s(t.reason);
219
+ }, a = this.recording.subscribe?.(c);
220
+ t.addEventListener("abort", n, { once: !0 }), t.aborted ? n() : c();
221
+ });
222
+ }
223
+ async endSnapshot(e) {
224
+ await Promise.all(
225
+ [...this.listeners].map(
226
+ ({ listener: t }) => t.onSnapshotEnd?.(e)
227
+ )
228
+ );
229
+ }
230
+ async seek(e) {
231
+ if (this.closed) return;
232
+ const t = ++this.generation;
233
+ this.seekController?.abort();
234
+ const i = new AbortController();
235
+ this.seekController = i, this.waitingForData = !1, this.cancelFrame(), this.time = e < this.recording.start ? this.recording.start : e > this.recording.end && (this.recording.complete !== !1 || this.recording.bounds !== void 0) ? this.recording.end : e, this.status = "buffering", this.emit();
236
+ try {
237
+ if (this.recording.error) throw this.recording.error;
238
+ if (this.recording.complete === !1 && this.availableEnd() < this.time && await this.waitForTime(this.time, i.signal), t !== this.generation || this.closed) return;
239
+ this.time > this.recording.end && (this.time = this.recording.end), this.submitted.clear();
240
+ for (const { listener: s } of this.listeners) s.onSnapshotStart?.();
241
+ for (const s of k(this.recording, this.time)) {
242
+ if (t !== this.generation || this.closed) return;
243
+ this.publish(s);
244
+ }
245
+ if (await this.endSnapshot(!this.playing), t !== this.generation || this.closed) return;
246
+ this.anchorTime = this.time, this.anchorWall = this.scheduler.now(), this.status = this.playing ? "playing" : "paused", this.emit(), this.playing && (this.frame = this.scheduler.request(() => {
247
+ this.tick();
248
+ }));
249
+ } catch (s) {
250
+ t === this.generation && !this.closed && this.fail(s);
251
+ }
252
+ }
253
+ play() {
254
+ if (!this.closed)
255
+ return this.playing = !0, this.seek(
256
+ this.endBuffered() && this.time >= this.recording.end ? this.recording.start : this.time
257
+ );
258
+ }
259
+ pause() {
260
+ if (!this.closed)
261
+ return this.playing = !1, this.seek(this.time);
262
+ }
263
+ setSpeed(e) {
264
+ if (!this.closed) {
265
+ if (!Number.isFinite(e) || e <= 0)
266
+ throw new Error("Playback speed must be positive");
267
+ this.speed = e, this.anchorTime = this.time, this.anchorWall = this.scheduler.now(), this.emit();
268
+ }
269
+ }
270
+ async tick() {
271
+ if (this.frame = void 0, this.closed || !this.playing) return;
272
+ const e = this.generation, t = this.anchorTime + BigInt(
273
+ Math.round((this.scheduler.now() - this.anchorWall) * 1e6 * this.speed)
274
+ );
275
+ try {
276
+ const i = this.availableEnd(), s = i < this.recording.end ? i : this.recording.end;
277
+ this.time = t > s ? s : t;
278
+ for (const [o, c] of this.video) {
279
+ const n = this.submitted.get(o), a = n === void 0 ? c.snapshot(this.time) : c.after(this.time, n);
280
+ for (const l of a)
281
+ if (this.publish(l), e !== this.generation || this.closed) return;
282
+ }
283
+ if (this.emit(), this.time === this.recording.end && this.endBuffered()) {
284
+ if (this.playing = !1, await this.endSnapshot(!0), e !== this.generation || this.closed) return;
285
+ this.status = "ended";
286
+ } else this.recording.complete === !1 && t >= s && (this.status = "buffering", this.waitingForData = !0);
287
+ this.emit(), this.playing && !this.waitingForData && (this.frame = this.scheduler.request(() => {
288
+ this.tick();
289
+ }));
290
+ } catch (i) {
291
+ e === this.generation && !this.closed && this.fail(i);
292
+ }
293
+ }
294
+ close() {
295
+ this.closed = !0, this.playing = !1, this.generation++, this.seekController?.abort(), this.unsubscribeRecording?.(), this.waitingForData = !1, this.cancelFrame(), this.listeners.clear();
296
+ }
297
+ }
298
+ function S(r) {
299
+ let e = !1, t;
300
+ for (let i = 0; i + 3 < r.length; i++) {
301
+ if (r[i] !== 0 || r[i + 1] !== 0) continue;
302
+ let s = -1;
303
+ if (r[i + 2] === 1 ? s = i + 3 : r[i + 2] === 0 && r[i + 3] === 1 && (s = i + 4), s < 0 || s >= r.length) continue;
304
+ const o = r[s] & 31;
305
+ o === 5 && (e = !0), o === 7 && s + 3 < r.length && (t = `avc1.${Array.from(r.slice(s + 1, s + 4), (c) => c.toString(16).padStart(2, "0")).join("")}`), i = s;
306
+ }
307
+ return { keyframe: e, codec: t };
308
+ }
309
+ function F(r, e) {
310
+ if (e === "h264") return S(r);
311
+ if (e !== "h265") throw new Error(`Unsupported video format: ${e}`);
312
+ let t = !1, i;
313
+ const s = [];
314
+ let o = -1;
315
+ for (let n = 0; n + 3 < r.length; n++) {
316
+ if (r[n] !== 0 || r[n + 1] !== 0) continue;
317
+ const a = r[n + 2] === 1 ? 3 : r[n + 2] === 0 && r[n + 3] === 1 ? 4 : 0;
318
+ a && (o >= 0 && s.push(r.subarray(o, n)), o = n + a, n = o - 1);
319
+ }
320
+ o >= 0 && s.push(r.subarray(o));
321
+ const c = /* @__PURE__ */ new Set();
322
+ for (const n of s) {
323
+ const a = n[0] >> 1 & 63;
324
+ if (a >= 16 && a <= 21 && (t = !0), a >= 32 && a <= 34 && c.add(a), a !== 33) continue;
325
+ const l = [];
326
+ for (let d = 2; d < n.length; d++)
327
+ d >= 4 && n[d] === 3 && n[d - 1] === 0 && n[d - 2] === 0 || l.push(n[d]);
328
+ if (l.length < 13) continue;
329
+ const h = l[1];
330
+ let f = 0;
331
+ for (let d = 0; d < 32; d++)
332
+ f += (l[2 + (d >> 3)] >> 7 - (d & 7) & 1) * 2 ** d;
333
+ const u = l.slice(6, 12);
334
+ for (; u.length && u.at(-1) === 0; ) u.pop();
335
+ const p = u.map((d) => d.toString(16).toUpperCase().padStart(2, "0")).join(".");
336
+ i = `hvc1.${["", "A", "B", "C"][h >> 6]}${h & 31}.${f.toString(16).toUpperCase()}.${h & 32 ? "H" : "L"}${l[12]}${p ? `.${p}` : ""}`;
337
+ }
338
+ return c.size !== 3 && (i = void 0), { keyframe: t, codec: i };
339
+ }
340
+ class C {
341
+ constructor(e, t) {
342
+ this.output = e, this.error = t;
343
+ }
344
+ output;
345
+ error;
346
+ decoder;
347
+ origin = 0n;
348
+ times = /* @__PURE__ */ new Map();
349
+ generation = 0;
350
+ initializing;
351
+ flushing;
352
+ pending = [];
353
+ failed = !1;
354
+ decode(e, t, i = "h264") {
355
+ if (!this.failed)
356
+ try {
357
+ const s = F(t, i);
358
+ if (!this.decoder && !this.initializing) {
359
+ if (!s.keyframe || !s.codec)
360
+ throw new Error(
361
+ `${i === "h265" ? "HEVC" : "H.264"} playback must begin at a keyframe with codec headers`
362
+ );
363
+ if (typeof VideoDecoder > "u")
364
+ throw new Error(
365
+ "This browser does not support WebCodecs video decoding"
366
+ );
367
+ this.origin = e;
368
+ const n = this.generation, a = { codec: s.codec, optimizeForLatency: !0 }, l = () => {
369
+ if (n === this.generation) {
370
+ this.decoder = new VideoDecoder({
371
+ output: (h) => {
372
+ if (n !== this.generation) {
373
+ h.close();
374
+ return;
375
+ }
376
+ const f = this.times.get(h.timestamp);
377
+ if (this.times.delete(h.timestamp), f === void 0) {
378
+ h.close();
379
+ return;
380
+ }
381
+ this.output(h, f);
382
+ },
383
+ error: (h) => {
384
+ n === this.generation && this.reject(h, a.codec);
385
+ }
386
+ }), this.decoder.configure(a);
387
+ for (const h of this.pending.splice(0))
388
+ this.decoder.decode(h);
389
+ }
390
+ };
391
+ typeof VideoDecoder.isConfigSupported == "function" ? this.initializing = VideoDecoder.isConfigSupported(a).then((h) => {
392
+ if (n === this.generation) {
393
+ if (!h.supported)
394
+ throw new Error(
395
+ `This browser or device does not support ${i === "h265" ? "HEVC" : "H.264"} video decoding (${a.codec})`
396
+ );
397
+ l();
398
+ }
399
+ }).catch((h) => {
400
+ n === this.generation && this.reject(h, a.codec);
401
+ }) : l();
402
+ }
403
+ const o = Number((e - this.origin) / 1000n);
404
+ this.times.set(o, e);
405
+ const c = new EncodedVideoChunk({
406
+ type: s.keyframe ? "key" : "delta",
407
+ timestamp: o,
408
+ data: Uint8Array.from(t)
409
+ });
410
+ this.decoder ? this.decoder.decode(c) : this.pending.push(c);
411
+ } catch (s) {
412
+ this.error(
413
+ s instanceof Error ? s : new Error("Video decode failed")
414
+ );
415
+ }
416
+ }
417
+ reject(e, t) {
418
+ this.failed = !0, this.pending = [], this.times.clear(), this.error(
419
+ new Error(
420
+ `Video decoding failed (${t}): ${e instanceof Error ? e.message : String(e)}`
421
+ )
422
+ );
423
+ }
424
+ flush() {
425
+ if (this.flushing) return this.flushing;
426
+ const e = this.generation;
427
+ return this.flushing = (async () => {
428
+ this.initializing && await this.initializing;
429
+ const t = this.decoder;
430
+ if (!(e !== this.generation || !t || t.state !== "configured"))
431
+ try {
432
+ await t.flush();
433
+ } catch (i) {
434
+ e === this.generation && this.error(
435
+ i instanceof Error ? i : new Error("Video decode failed")
436
+ );
437
+ }
438
+ })(), this.flushing;
439
+ }
440
+ reset() {
441
+ this.generation++, this.decoder && this.decoder.state !== "closed" && this.decoder.close(), this.decoder = void 0, this.initializing = void 0, this.flushing = void 0, this.pending = [], this.failed = !1, this.times.clear();
442
+ }
443
+ }
444
+ class V {
445
+ constructor(e, t = {}) {
446
+ this.canvas = e, this.options = t, this.imageTopic = t.imageTopic, this.video = new C(
447
+ (i, s) => this.present(i, s),
448
+ (i) => this.onError?.(i)
449
+ );
450
+ }
451
+ canvas;
452
+ options;
453
+ onFrame;
454
+ onError;
455
+ image;
456
+ frameTime = 0n;
457
+ presentationTime;
458
+ frames = /* @__PURE__ */ new Map();
459
+ latestInputTime;
460
+ presentationFloor = 0n;
461
+ requested;
462
+ generation = 0;
463
+ snapshot = !1;
464
+ imageTopic;
465
+ video;
466
+ onMessage(e, t, i) {
467
+ try {
468
+ if (e.schemaName !== w || (this.imageTopic ??= e.topic, this.imageTopic !== e.topic)) return;
469
+ const s = m(i);
470
+ (this.presentationTime === void 0 || t <= this.presentationTime) && (this.latestInputTime === void 0 || t > this.latestInputTime) && (this.latestInputTime = t), this.video.decode(t, s.data, s.format), s.decode_order === e.metadata.get("video.decode_end") && this.video.flush();
471
+ } catch (s) {
472
+ this.onError?.(s instanceof Error ? s : new Error(String(s)));
473
+ }
474
+ }
475
+ onState(e) {
476
+ this.presentationTime = e.time, e.status !== "buffering" && this.selectFrame();
477
+ }
478
+ onSnapshotStart() {
479
+ this.resetSnapshot(), this.snapshot = !0;
480
+ }
481
+ async onSnapshotEnd(e) {
482
+ const t = this.generation;
483
+ this.presentationFloor = this.latestInputTime ?? 0n, e && await this.video.flush(), t === this.generation && (this.snapshot = !1, (this.latestInputTime === void 0 || e && (!this.image || this.frameTime < this.presentationFloor)) && this.clearCanvas(), this.image && this.frameTime >= this.presentationFloor && (this.render(), this.onFrame?.(this.frameTime)));
484
+ }
485
+ present(e, t) {
486
+ if (this.image && t < this.frameTime) {
487
+ e.close();
488
+ return;
489
+ }
490
+ this.frames.get(t)?.close(), this.frames.set(t, e), this.selectFrame();
491
+ }
492
+ selectFrame() {
493
+ let e;
494
+ for (const i of this.frames.keys())
495
+ (this.presentationTime === void 0 || i <= this.presentationTime) && (e === void 0 || i > e) && (e = i);
496
+ if (e === void 0) return;
497
+ const t = this.frames.get(e);
498
+ this.frames.delete(e);
499
+ for (const [i, s] of this.frames)
500
+ i < e && (s.close(), this.frames.delete(i));
501
+ this.image?.close(), this.image = t, this.frameTime = e, !this.snapshot && e >= this.presentationFloor && (this.render(), this.onFrame?.(e));
502
+ }
503
+ render() {
504
+ this.requested === void 0 && (this.requested = requestAnimationFrame(() => {
505
+ this.requested = void 0;
506
+ const e = this.canvas.getContext("2d");
507
+ if (!this.image || !e || this.snapshot || this.frameTime < this.presentationFloor)
508
+ return;
509
+ const t = this.image.displayWidth, i = this.image.displayHeight;
510
+ (this.canvas.width !== t || this.canvas.height !== i) && (this.canvas.width = t, this.canvas.height = i, this.canvas.style.aspectRatio = `${t} / ${i}`), e.drawImage(this.image, 0, 0);
511
+ }));
512
+ }
513
+ resetSnapshot() {
514
+ this.generation++, this.video.reset();
515
+ for (const e of this.frames.values()) e.close();
516
+ this.frames.clear(), this.snapshot = !1, this.frameTime = 0n, this.latestInputTime = void 0, this.presentationFloor = 0n, this.imageTopic = this.options.imageTopic, this.image?.close(), this.image = void 0;
517
+ }
518
+ clearCanvas() {
519
+ this.canvas.getContext("2d")?.clearRect(0, 0, this.canvas.width, this.canvas.height);
520
+ }
521
+ reset() {
522
+ this.resetSnapshot(), this.presentationTime = void 0, this.clearCanvas();
523
+ }
524
+ destroy() {
525
+ this.reset(), this.requested !== void 0 && cancelAnimationFrame(this.requested), this.requested = void 0;
526
+ }
527
+ }
528
+ export {
529
+ M as BlobSource,
530
+ D as HttpSource,
531
+ V as ImageRenderer,
532
+ x as McapRecording,
533
+ q as ReplayPlayer
534
+ };
@@ -0,0 +1,53 @@
1
+ import { M as o } from "./recording-tVYbg6KM.js";
2
+ class h {
3
+ baseUrl;
4
+ headers;
5
+ constructor({ baseUrl: e, headers: r }) {
6
+ this.baseUrl = new URL(`${String(e).replace(/\/+$/, "")}/`), this.headers = new Headers(r);
7
+ }
8
+ async request(e, r, t) {
9
+ const a = new Headers(this.headers);
10
+ new Headers(r.headers).forEach(
11
+ (n, i) => a.set(i, n)
12
+ ), t !== void 0 && a.set("Content-Type", "application/json");
13
+ const s = await fetch(new URL(`v1/${e}`, this.baseUrl), {
14
+ method: t === void 0 ? "GET" : "POST",
15
+ headers: a,
16
+ signal: r.signal,
17
+ body: t === void 0 ? void 0 : JSON.stringify(t),
18
+ cache: "no-store"
19
+ });
20
+ if (!s.ok)
21
+ throw new Error(
22
+ `Replay request failed (${s.status}): ${await s.text()}`
23
+ );
24
+ return s.json();
25
+ }
26
+ /** List the service's supported canonical data types. */
27
+ capabilities(e = {}) {
28
+ return this.request("capabilities", e);
29
+ }
30
+ /** Discover a datasource's canonical schemas and actual wire encodings. */
31
+ discover(e, r = {}) {
32
+ return this.request(
33
+ `discover?${new URLSearchParams({ datasource: e })}`,
34
+ r
35
+ );
36
+ }
37
+ /** Resolve topic URLs for ordered spans; each span can succeed or fail independently. */
38
+ manifest(e, r = {}) {
39
+ return this.request("manifest", r, e);
40
+ }
41
+ /** Open the single MCAP shared by all topics in one successful manifest result. */
42
+ async openSpan(e, r = {}) {
43
+ if ("error" in e)
44
+ throw new Error(`${e.error.code}: ${e.error.message}`);
45
+ const t = await o.open(e.manifest.url, r);
46
+ if (r.bounds) return t;
47
+ const a = t.metadata.get("replay"), s = a?.get("start_ns"), n = a?.get("end_ns");
48
+ return s !== void 0 && n !== void 0 ? t.withBounds({ start: BigInt(s), end: BigInt(n) - 1n }) : t;
49
+ }
50
+ }
51
+ export {
52
+ h as ReplayDataLoader
53
+ };
@@ -0,0 +1,11 @@
1
+ import { B as a, H as o, M as p } from "./recording-tVYbg6KM.js";
2
+ import { ImageRenderer as c, ReplayPlayer as l } from "./core.js";
3
+ import { ReplayDataLoader as R } from "./data-loader.js";
4
+ export {
5
+ a as BlobSource,
6
+ o as HttpSource,
7
+ c as ImageRenderer,
8
+ p as McapRecording,
9
+ R as ReplayDataLoader,
10
+ l as ReplayPlayer
11
+ };