@editframe/elements 0.20.4-beta.0 → 0.23.6-beta.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/DelayedLoadingState.js +0 -27
- package/dist/EF_FRAMEGEN.d.ts +5 -3
- package/dist/EF_FRAMEGEN.js +49 -11
- package/dist/_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js +7 -0
- package/dist/attachContextRoot.d.ts +1 -0
- package/dist/attachContextRoot.js +9 -0
- package/dist/elements/ContextProxiesController.d.ts +1 -2
- package/dist/elements/EFAudio.js +5 -9
- package/dist/elements/EFCaptions.d.ts +1 -3
- package/dist/elements/EFCaptions.js +112 -129
- package/dist/elements/EFImage.js +6 -7
- package/dist/elements/EFMedia/AssetIdMediaEngine.js +2 -5
- package/dist/elements/EFMedia/AssetMediaEngine.js +36 -33
- package/dist/elements/EFMedia/BaseMediaEngine.js +57 -73
- package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +1 -1
- package/dist/elements/EFMedia/BufferedSeekingInput.js +134 -78
- package/dist/elements/EFMedia/JitMediaEngine.js +9 -19
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +7 -13
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +2 -3
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +6 -5
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +1 -3
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +1 -1
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js +9 -25
- package/dist/elements/EFMedia/shared/BufferUtils.js +2 -17
- package/dist/elements/EFMedia/shared/GlobalInputCache.js +0 -24
- package/dist/elements/EFMedia/shared/PrecisionUtils.js +0 -21
- package/dist/elements/EFMedia/shared/ThumbnailExtractor.js +0 -17
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +1 -10
- package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.d.ts +29 -0
- package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js +32 -0
- package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +1 -15
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js +1 -7
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js +8 -5
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js +12 -13
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js +1 -1
- package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js +134 -70
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +11 -18
- package/dist/elements/EFMedia.d.ts +19 -0
- package/dist/elements/EFMedia.js +44 -25
- package/dist/elements/EFSourceMixin.js +5 -7
- package/dist/elements/EFSurface.js +6 -9
- package/dist/elements/EFTemporal.browsertest.d.ts +11 -0
- package/dist/elements/EFTemporal.d.ts +10 -0
- package/dist/elements/EFTemporal.js +100 -41
- package/dist/elements/EFThumbnailStrip.js +23 -73
- package/dist/elements/EFTimegroup.browsertest.d.ts +3 -3
- package/dist/elements/EFTimegroup.d.ts +35 -14
- package/dist/elements/EFTimegroup.js +138 -181
- package/dist/elements/EFVideo.d.ts +16 -2
- package/dist/elements/EFVideo.js +156 -108
- package/dist/elements/EFWaveform.js +23 -40
- package/dist/elements/SampleBuffer.js +3 -7
- package/dist/elements/TargetController.js +5 -5
- package/dist/elements/durationConverter.js +4 -4
- package/dist/elements/renderTemporalAudio.d.ts +10 -0
- package/dist/elements/renderTemporalAudio.js +35 -0
- package/dist/elements/updateAnimations.js +19 -43
- package/dist/gui/ContextMixin.d.ts +5 -5
- package/dist/gui/ContextMixin.js +167 -162
- package/dist/gui/Controllable.browsertest.d.ts +0 -0
- package/dist/gui/Controllable.d.ts +15 -0
- package/dist/gui/Controllable.js +9 -0
- package/dist/gui/EFConfiguration.js +7 -7
- package/dist/gui/EFControls.browsertest.d.ts +11 -0
- package/dist/gui/EFControls.d.ts +18 -4
- package/dist/gui/EFControls.js +70 -28
- package/dist/gui/EFDial.browsertest.d.ts +0 -0
- package/dist/gui/EFDial.d.ts +18 -0
- package/dist/gui/EFDial.js +141 -0
- package/dist/gui/EFFilmstrip.browsertest.d.ts +11 -0
- package/dist/gui/EFFilmstrip.d.ts +12 -2
- package/dist/gui/EFFilmstrip.js +214 -129
- package/dist/gui/EFFitScale.js +5 -8
- package/dist/gui/EFFocusOverlay.js +4 -4
- package/dist/gui/EFPause.browsertest.d.ts +0 -0
- package/dist/gui/EFPause.d.ts +23 -0
- package/dist/gui/EFPause.js +59 -0
- package/dist/gui/EFPlay.browsertest.d.ts +0 -0
- package/dist/gui/EFPlay.d.ts +23 -0
- package/dist/gui/EFPlay.js +59 -0
- package/dist/gui/EFPreview.d.ts +4 -0
- package/dist/gui/EFPreview.js +18 -9
- package/dist/gui/EFResizableBox.browsertest.d.ts +0 -0
- package/dist/gui/EFResizableBox.d.ts +34 -0
- package/dist/gui/EFResizableBox.js +547 -0
- package/dist/gui/EFScrubber.d.ts +9 -3
- package/dist/gui/EFScrubber.js +13 -13
- package/dist/gui/EFTimeDisplay.d.ts +7 -1
- package/dist/gui/EFTimeDisplay.js +8 -8
- package/dist/gui/EFToggleLoop.d.ts +9 -3
- package/dist/gui/EFToggleLoop.js +7 -5
- package/dist/gui/EFTogglePlay.d.ts +12 -4
- package/dist/gui/EFTogglePlay.js +26 -21
- package/dist/gui/EFWorkbench.js +5 -5
- package/dist/gui/PlaybackController.d.ts +67 -0
- package/dist/gui/PlaybackController.js +310 -0
- package/dist/gui/TWMixin.js +1 -1
- package/dist/gui/TWMixin2.js +1 -1
- package/dist/gui/TargetOrContextMixin.d.ts +10 -0
- package/dist/gui/TargetOrContextMixin.js +98 -0
- package/dist/gui/efContext.d.ts +2 -2
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -1
- package/dist/otel/BridgeSpanExporter.d.ts +13 -0
- package/dist/otel/BridgeSpanExporter.js +87 -0
- package/dist/otel/setupBrowserTracing.d.ts +12 -0
- package/dist/otel/setupBrowserTracing.js +32 -0
- package/dist/otel/tracingHelpers.d.ts +34 -0
- package/dist/otel/tracingHelpers.js +112 -0
- package/dist/style.css +1 -1
- package/dist/transcoding/cache/RequestDeduplicator.js +0 -21
- package/dist/transcoding/cache/URLTokenDeduplicator.js +1 -21
- package/dist/transcoding/utils/UrlGenerator.js +2 -19
- package/dist/utils/LRUCache.js +6 -53
- package/package.json +13 -5
- package/src/elements/ContextProxiesController.ts +10 -10
- package/src/elements/EFAudio.ts +1 -0
- package/src/elements/EFCaptions.browsertest.ts +128 -56
- package/src/elements/EFCaptions.ts +60 -34
- package/src/elements/EFImage.browsertest.ts +1 -2
- package/src/elements/EFMedia/AssetMediaEngine.ts +65 -37
- package/src/elements/EFMedia/BaseMediaEngine.ts +110 -52
- package/src/elements/EFMedia/BufferedSeekingInput.ts +218 -101
- package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +3 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +7 -3
- package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.ts +1 -1
- package/src/elements/EFMedia/videoTasks/MainVideoInputCache.ts +76 -0
- package/src/elements/EFMedia/videoTasks/makeScrubVideoInputTask.ts +16 -10
- package/src/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.ts +7 -1
- package/src/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.ts +222 -116
- package/src/elements/EFMedia.browsertest.ts +8 -15
- package/src/elements/EFMedia.ts +54 -8
- package/src/elements/EFSurface.browsertest.ts +2 -6
- package/src/elements/EFSurface.ts +1 -0
- package/src/elements/EFTemporal.browsertest.ts +58 -1
- package/src/elements/EFTemporal.ts +140 -4
- package/src/elements/EFThumbnailStrip.browsertest.ts +2 -8
- package/src/elements/EFThumbnailStrip.ts +1 -0
- package/src/elements/EFTimegroup.browsertest.ts +16 -15
- package/src/elements/EFTimegroup.ts +281 -275
- package/src/elements/EFVideo.browsertest.ts +162 -74
- package/src/elements/EFVideo.ts +229 -101
- package/src/elements/FetchContext.browsertest.ts +7 -2
- package/src/elements/TargetController.browsertest.ts +1 -0
- package/src/elements/TargetController.ts +1 -0
- package/src/elements/renderTemporalAudio.ts +108 -0
- package/src/elements/updateAnimations.browsertest.ts +181 -6
- package/src/elements/updateAnimations.ts +6 -6
- package/src/gui/ContextMixin.browsertest.ts +274 -27
- package/src/gui/ContextMixin.ts +230 -175
- package/src/gui/Controllable.browsertest.ts +258 -0
- package/src/gui/Controllable.ts +41 -0
- package/src/gui/EFControls.browsertest.ts +294 -80
- package/src/gui/EFControls.ts +139 -28
- package/src/gui/EFDial.browsertest.ts +84 -0
- package/src/gui/EFDial.ts +172 -0
- package/src/gui/EFFilmstrip.browsertest.ts +712 -0
- package/src/gui/EFFilmstrip.ts +213 -23
- package/src/gui/EFPause.browsertest.ts +202 -0
- package/src/gui/EFPause.ts +73 -0
- package/src/gui/EFPlay.browsertest.ts +202 -0
- package/src/gui/EFPlay.ts +73 -0
- package/src/gui/EFPreview.ts +20 -5
- package/src/gui/EFResizableBox.browsertest.ts +79 -0
- package/src/gui/EFResizableBox.ts +898 -0
- package/src/gui/EFScrubber.ts +7 -5
- package/src/gui/EFTimeDisplay.browsertest.ts +19 -19
- package/src/gui/EFTimeDisplay.ts +3 -1
- package/src/gui/EFToggleLoop.ts +6 -5
- package/src/gui/EFTogglePlay.ts +30 -23
- package/src/gui/PlaybackController.ts +522 -0
- package/src/gui/TWMixin.css +3 -0
- package/src/gui/TargetOrContextMixin.ts +185 -0
- package/src/gui/efContext.ts +2 -2
- package/src/otel/BridgeSpanExporter.ts +150 -0
- package/src/otel/setupBrowserTracing.ts +73 -0
- package/src/otel/tracingHelpers.ts +251 -0
- package/test/cache-integration-verification.browsertest.ts +1 -1
- package/types.json +1 -1
- package/dist/elements/ContextProxiesController.js +0 -69
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { currentTimeContext } from "./currentTimeContext.js";
|
|
2
|
+
import { durationContext } from "./durationContext.js";
|
|
3
|
+
import { loopContext, playingContext } from "./playingContext.js";
|
|
4
|
+
import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
|
|
5
|
+
import { isEFTemporal } from "../elements/EFTemporal.js";
|
|
6
|
+
import { TargetController } from "../elements/TargetController.js";
|
|
7
|
+
import { isControllable } from "./Controllable.js";
|
|
8
|
+
import { consume } from "@lit/context";
|
|
9
|
+
import { property, state } from "lit/decorators.js";
|
|
10
|
+
var ContextRequestEvent = class extends Event {
|
|
11
|
+
constructor(context, contextTarget, callback, subscribe) {
|
|
12
|
+
super("context-request", {
|
|
13
|
+
bubbles: true,
|
|
14
|
+
composed: true
|
|
15
|
+
});
|
|
16
|
+
this.context = context;
|
|
17
|
+
this.contextTarget = contextTarget;
|
|
18
|
+
this.callback = callback;
|
|
19
|
+
this.subscribe = subscribe ?? false;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
function TargetOrContextMixin(superClass, contextToProxy) {
|
|
23
|
+
class TargetOrContextClass extends superClass {
|
|
24
|
+
constructor(..._args) {
|
|
25
|
+
super(..._args);
|
|
26
|
+
this.target = "";
|
|
27
|
+
this.targetElement = null;
|
|
28
|
+
this.contextFromParent = null;
|
|
29
|
+
}
|
|
30
|
+
#targetController;
|
|
31
|
+
#contextUnsubscribe;
|
|
32
|
+
#contextRequestHandler;
|
|
33
|
+
#additionalContextUnsubscribes = /* @__PURE__ */ new Map();
|
|
34
|
+
get effectiveContext() {
|
|
35
|
+
return this.targetElement ?? this.contextFromParent;
|
|
36
|
+
}
|
|
37
|
+
connectedCallback() {
|
|
38
|
+
super.connectedCallback();
|
|
39
|
+
if (this.target) this.#targetController = new TargetController(this);
|
|
40
|
+
this.#contextRequestHandler = (event) => {
|
|
41
|
+
if (this.targetElement && event.type === "context-request") {
|
|
42
|
+
event.stopPropagation();
|
|
43
|
+
this.targetElement.dispatchEvent(new event.constructor(event.type, event));
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
this.addEventListener("context-request", this.#contextRequestHandler, true);
|
|
47
|
+
}
|
|
48
|
+
#subscribeToTargetContext() {
|
|
49
|
+
if (!this.targetElement) return;
|
|
50
|
+
this.#contextUnsubscribe?.();
|
|
51
|
+
for (const unsubscribe of this.#additionalContextUnsubscribes.values()) unsubscribe();
|
|
52
|
+
this.#additionalContextUnsubscribes.clear();
|
|
53
|
+
const event = new ContextRequestEvent(contextToProxy, this, (value, unsubscribe) => {
|
|
54
|
+
this.contextFromParent = value;
|
|
55
|
+
this.#contextUnsubscribe = unsubscribe;
|
|
56
|
+
}, true);
|
|
57
|
+
this.targetElement.dispatchEvent(event);
|
|
58
|
+
const additionalContexts = [
|
|
59
|
+
[playingContext, "playing"],
|
|
60
|
+
[loopContext, "loop"],
|
|
61
|
+
[currentTimeContext, "currentTimeMs"],
|
|
62
|
+
[durationContext, "durationMs"]
|
|
63
|
+
];
|
|
64
|
+
for (const [context, propertyName] of additionalContexts) {
|
|
65
|
+
const contextEvent = new ContextRequestEvent(context, this, (value, unsubscribe) => {
|
|
66
|
+
if (propertyName in this) this[propertyName] = value;
|
|
67
|
+
this.#additionalContextUnsubscribes.set(context, unsubscribe);
|
|
68
|
+
}, true);
|
|
69
|
+
this.targetElement.dispatchEvent(contextEvent);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
updated(changedProperties) {
|
|
73
|
+
super.updated?.(changedProperties);
|
|
74
|
+
if (changedProperties.has("targetElement") && this.targetElement) {
|
|
75
|
+
if (isEFTemporal(this.targetElement) && !isControllable(this.targetElement)) console.warn("Control element is targeting a non-root temporal element without playbackController. Controls can only target root temporal elements (not nested within a timegroup). Target element:", this.targetElement);
|
|
76
|
+
this.#subscribeToTargetContext();
|
|
77
|
+
}
|
|
78
|
+
if (changedProperties.has("target")) {
|
|
79
|
+
if (this.target && !this.#targetController) this.#targetController = new TargetController(this);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
disconnectedCallback() {
|
|
83
|
+
super.disconnectedCallback();
|
|
84
|
+
this.#contextUnsubscribe?.();
|
|
85
|
+
for (const unsubscribe of this.#additionalContextUnsubscribes.values()) unsubscribe();
|
|
86
|
+
this.#additionalContextUnsubscribes.clear();
|
|
87
|
+
if (this.#contextRequestHandler) this.removeEventListener("context-request", this.#contextRequestHandler, true);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
__decorate([property({ type: String })], TargetOrContextClass.prototype, "target", void 0);
|
|
91
|
+
__decorate([state()], TargetOrContextClass.prototype, "targetElement", void 0);
|
|
92
|
+
__decorate([consume({
|
|
93
|
+
context: contextToProxy,
|
|
94
|
+
subscribe: true
|
|
95
|
+
})], TargetOrContextClass.prototype, "contextFromParent", void 0);
|
|
96
|
+
return TargetOrContextClass;
|
|
97
|
+
}
|
|
98
|
+
export { TargetOrContextMixin };
|
package/dist/gui/efContext.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -10,12 +10,17 @@ export { EFWorkbench } from './gui/EFWorkbench.js';
|
|
|
10
10
|
export { EFPreview } from './gui/EFPreview.js';
|
|
11
11
|
export { EFFilmstrip } from './gui/EFFilmstrip.js';
|
|
12
12
|
export { EFTogglePlay } from './gui/EFTogglePlay.js';
|
|
13
|
+
export { EFPlay } from './gui/EFPlay.js';
|
|
14
|
+
export { EFPause } from './gui/EFPause.js';
|
|
13
15
|
export { EFToggleLoop } from './gui/EFToggleLoop.js';
|
|
14
16
|
export { EFScrubber } from './gui/EFScrubber.js';
|
|
15
17
|
export { EFTimeDisplay } from './gui/EFTimeDisplay.js';
|
|
18
|
+
export { type DialChangeDetail, EFDial } from './gui/EFDial.js';
|
|
16
19
|
export { EFControls } from './gui/EFControls.js';
|
|
17
20
|
export { EFFocusOverlay } from './gui/EFFocusOverlay.js';
|
|
21
|
+
export { type BoxBounds, EFResizableBox } from './gui/EFResizableBox.ts';
|
|
18
22
|
export { EFFitScale } from './gui/EFFitScale.js';
|
|
19
23
|
export { EFSurface } from './elements/EFSurface.ts';
|
|
20
24
|
export { EFThumbnailStrip } from './elements/EFThumbnailStrip.ts';
|
|
21
25
|
export { getRenderInfo, RenderInfo } from './getRenderInfo.js';
|
|
26
|
+
export type { TraceContext } from './otel/tracingHelpers.js';
|
package/dist/index.js
CHANGED
|
@@ -11,15 +11,19 @@ import { EFWorkbench } from "./gui/EFWorkbench.js";
|
|
|
11
11
|
import { EFPreview } from "./gui/EFPreview.js";
|
|
12
12
|
import { EFFilmstrip } from "./gui/EFFilmstrip.js";
|
|
13
13
|
import { EFTogglePlay } from "./gui/EFTogglePlay.js";
|
|
14
|
+
import { EFPlay } from "./gui/EFPlay.js";
|
|
15
|
+
import { EFPause } from "./gui/EFPause.js";
|
|
14
16
|
import { EFToggleLoop } from "./gui/EFToggleLoop.js";
|
|
15
17
|
import { EFScrubber } from "./gui/EFScrubber.js";
|
|
16
18
|
import { EFTimeDisplay } from "./gui/EFTimeDisplay.js";
|
|
19
|
+
import { EFDial } from "./gui/EFDial.js";
|
|
17
20
|
import { EFControls } from "./gui/EFControls.js";
|
|
18
21
|
import { EFFocusOverlay } from "./gui/EFFocusOverlay.js";
|
|
22
|
+
import { EFResizableBox } from "./gui/EFResizableBox.js";
|
|
19
23
|
import { EFFitScale } from "./gui/EFFitScale.js";
|
|
20
24
|
import { EFSurface } from "./elements/EFSurface.js";
|
|
21
25
|
import { EFThumbnailStrip } from "./elements/EFThumbnailStrip.js";
|
|
22
26
|
import "./EF_FRAMEGEN.js";
|
|
23
27
|
import { RenderInfo, getRenderInfo } from "./getRenderInfo.js";
|
|
24
28
|
if (typeof window !== "undefined") window.EF_REGISTERED = true;
|
|
25
|
-
export { EFAudio, EFCaptions, EFCaptionsActiveWord, EFCaptionsAfterActiveWord, EFCaptionsBeforeActiveWord, EFCaptionsSegment, EFConfiguration, EFControls, EFFilmstrip, EFFitScale, EFFocusOverlay, EFImage, EFPreview, EFScrubber, EFSurface, EFThumbnailStrip, EFTimeDisplay, EFTimegroup, EFToggleLoop, EFTogglePlay, EFVideo, EFWaveform, EFWorkbench, RenderInfo, getRenderInfo };
|
|
29
|
+
export { EFAudio, EFCaptions, EFCaptionsActiveWord, EFCaptionsAfterActiveWord, EFCaptionsBeforeActiveWord, EFCaptionsSegment, EFConfiguration, EFControls, EFDial, EFFilmstrip, EFFitScale, EFFocusOverlay, EFImage, EFPause, EFPlay, EFPreview, EFResizableBox, EFScrubber, EFSurface, EFThumbnailStrip, EFTimeDisplay, EFTimegroup, EFToggleLoop, EFTogglePlay, EFVideo, EFWaveform, EFWorkbench, RenderInfo, getRenderInfo };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ExportResult } from '@opentelemetry/core';
|
|
2
|
+
import { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base';
|
|
3
|
+
interface BridgeWithSpanExport {
|
|
4
|
+
exportSpans?: (endpoint: string, payload: string) => void;
|
|
5
|
+
}
|
|
6
|
+
export declare class BridgeSpanExporter implements SpanExporter {
|
|
7
|
+
private bridge;
|
|
8
|
+
private endpoint;
|
|
9
|
+
constructor(bridge: BridgeWithSpanExport, endpoint: string);
|
|
10
|
+
export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void;
|
|
11
|
+
shutdown(): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { ExportResultCode } from "@opentelemetry/core";
|
|
2
|
+
function toHex(value) {
|
|
3
|
+
if (typeof value === "string") return value;
|
|
4
|
+
if (Array.isArray(value)) return value.map((b) => {
|
|
5
|
+
return (typeof b === "number" ? b : 0).toString(16).padStart(2, "0");
|
|
6
|
+
}).join("");
|
|
7
|
+
if (ArrayBuffer.isView(value)) return Array.from(value).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
8
|
+
return String(value);
|
|
9
|
+
}
|
|
10
|
+
function convertAttribute(value) {
|
|
11
|
+
if (typeof value === "string") return { stringValue: value };
|
|
12
|
+
if (typeof value === "number") return Number.isInteger(value) ? { intValue: value } : { doubleValue: value };
|
|
13
|
+
if (typeof value === "boolean") return { boolValue: value };
|
|
14
|
+
if (Array.isArray(value)) return { arrayValue: { values: value.map(convertAttribute) } };
|
|
15
|
+
return { stringValue: String(value) };
|
|
16
|
+
}
|
|
17
|
+
var BridgeSpanExporter = class {
|
|
18
|
+
constructor(bridge, endpoint) {
|
|
19
|
+
this.bridge = bridge;
|
|
20
|
+
this.endpoint = endpoint;
|
|
21
|
+
}
|
|
22
|
+
export(spans, resultCallback) {
|
|
23
|
+
if (!this.bridge?.exportSpans) {
|
|
24
|
+
resultCallback({ code: ExportResultCode.FAILED });
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const otlpPayload = { resourceSpans: [{
|
|
29
|
+
resource: { attributes: Object.entries(spans[0]?.resource?.attributes || {}).map(([key, value]) => ({
|
|
30
|
+
key,
|
|
31
|
+
value: convertAttribute(value)
|
|
32
|
+
})) },
|
|
33
|
+
scopeSpans: [{
|
|
34
|
+
scope: {
|
|
35
|
+
name: "telecine-browser",
|
|
36
|
+
version: "1.0.0"
|
|
37
|
+
},
|
|
38
|
+
spans: spans.map((span) => {
|
|
39
|
+
const ctx = span.spanContext();
|
|
40
|
+
return {
|
|
41
|
+
traceId: toHex(ctx.traceId),
|
|
42
|
+
spanId: toHex(ctx.spanId),
|
|
43
|
+
parentSpanId: span.parentSpanId ? toHex(span.parentSpanId) : void 0,
|
|
44
|
+
name: span.name,
|
|
45
|
+
kind: span.kind,
|
|
46
|
+
startTimeUnixNano: String(span.startTime[0] * 1e9 + span.startTime[1]),
|
|
47
|
+
endTimeUnixNano: String(span.endTime[0] * 1e9 + span.endTime[1]),
|
|
48
|
+
attributes: Object.entries(span.attributes).map(([key, value]) => ({
|
|
49
|
+
key,
|
|
50
|
+
value: convertAttribute(value)
|
|
51
|
+
})),
|
|
52
|
+
status: span.status,
|
|
53
|
+
events: span.events.map((event) => ({
|
|
54
|
+
timeUnixNano: String(event.time[0] * 1e9 + event.time[1]),
|
|
55
|
+
name: event.name,
|
|
56
|
+
attributes: Object.entries(event.attributes || {}).map(([key, value]) => ({
|
|
57
|
+
key,
|
|
58
|
+
value: convertAttribute(value)
|
|
59
|
+
}))
|
|
60
|
+
})),
|
|
61
|
+
links: span.links.map((link) => ({
|
|
62
|
+
traceId: toHex(link.context.traceId),
|
|
63
|
+
spanId: toHex(link.context.spanId),
|
|
64
|
+
attributes: Object.entries(link.attributes || {}).map(([key, value]) => ({
|
|
65
|
+
key,
|
|
66
|
+
value: convertAttribute(value)
|
|
67
|
+
}))
|
|
68
|
+
}))
|
|
69
|
+
};
|
|
70
|
+
})
|
|
71
|
+
}]
|
|
72
|
+
}] };
|
|
73
|
+
const serializedPayload = JSON.stringify(otlpPayload);
|
|
74
|
+
this.bridge.exportSpans(this.endpoint, serializedPayload);
|
|
75
|
+
resultCallback({ code: ExportResultCode.SUCCESS });
|
|
76
|
+
} catch (error) {
|
|
77
|
+
resultCallback({
|
|
78
|
+
code: ExportResultCode.FAILED,
|
|
79
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
shutdown() {
|
|
84
|
+
return Promise.resolve();
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
export { BridgeSpanExporter };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface BridgeWithSpanExport {
|
|
2
|
+
exportSpans?: (endpoint: string, payload: string) => void;
|
|
3
|
+
}
|
|
4
|
+
export interface BrowserTracingConfig {
|
|
5
|
+
otelEndpoint: string;
|
|
6
|
+
serviceName?: string;
|
|
7
|
+
bridge?: BridgeWithSpanExport;
|
|
8
|
+
useBatching?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function setupBrowserTracing(config: BrowserTracingConfig): Promise<void>;
|
|
11
|
+
export declare function isBrowserTracingInitialized(): boolean;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { BridgeSpanExporter } from "./BridgeSpanExporter.js";
|
|
2
|
+
import { Resource } from "@opentelemetry/resources";
|
|
3
|
+
import { BatchSpanProcessor, SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
4
|
+
import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
|
|
5
|
+
import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
|
|
6
|
+
var isInitialized = false;
|
|
7
|
+
var provider = null;
|
|
8
|
+
async function setupBrowserTracing(config) {
|
|
9
|
+
if (isInitialized) return;
|
|
10
|
+
try {
|
|
11
|
+
if (!config.bridge) throw new Error("Bridge is required for browser tracing");
|
|
12
|
+
const exporter = new BridgeSpanExporter(config.bridge, config.otelEndpoint);
|
|
13
|
+
let spanProcessor;
|
|
14
|
+
if (config.useBatching) spanProcessor = new BatchSpanProcessor(exporter, {
|
|
15
|
+
maxQueueSize: 100,
|
|
16
|
+
maxExportBatchSize: 10,
|
|
17
|
+
scheduledDelayMillis: 500
|
|
18
|
+
});
|
|
19
|
+
else spanProcessor = new SimpleSpanProcessor(exporter);
|
|
20
|
+
provider = new WebTracerProvider({
|
|
21
|
+
resource: new Resource({ [ATTR_SERVICE_NAME]: config.serviceName || "telecine-browser" }),
|
|
22
|
+
spanProcessors: [spanProcessor]
|
|
23
|
+
});
|
|
24
|
+
const { ZoneContextManager } = await import("@opentelemetry/context-zone");
|
|
25
|
+
provider.register({ contextManager: new ZoneContextManager() });
|
|
26
|
+
isInitialized = true;
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error("Failed to initialize browser tracing:", error);
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export { setupBrowserTracing };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Context, Span } from '@opentelemetry/api';
|
|
2
|
+
export type TraceContext = Record<string, string>;
|
|
3
|
+
/**
|
|
4
|
+
* Enable tracing globally. Call this during initialization if tracing is requested.
|
|
5
|
+
*/
|
|
6
|
+
export declare function enableTracing(): void;
|
|
7
|
+
/**
|
|
8
|
+
* Check if tracing is currently enabled.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isTracingEnabled(): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Set the current frame's span. Call this when starting a frame render.
|
|
13
|
+
* All spans created during this frame will use this as parent if
|
|
14
|
+
* Zone.js doesn't provide one via context.active()
|
|
15
|
+
*/
|
|
16
|
+
export declare function setCurrentFrameSpan(span: Span): void;
|
|
17
|
+
/**
|
|
18
|
+
* Clear the current frame span. Call this when a frame completes.
|
|
19
|
+
*/
|
|
20
|
+
export declare function clearCurrentFrameSpan(): void;
|
|
21
|
+
export declare function extractParentContext(traceContext?: TraceContext): Context;
|
|
22
|
+
/**
|
|
23
|
+
* Get the active span's context to pass to child operations
|
|
24
|
+
* Use this when calling functions that create child spans
|
|
25
|
+
*/
|
|
26
|
+
export declare function getActiveContext(): Context;
|
|
27
|
+
/**
|
|
28
|
+
* Wrapper that passes span context explicitly to the function
|
|
29
|
+
* Use this for operations that need to store or propagate context across boundaries
|
|
30
|
+
*/
|
|
31
|
+
export declare function withSpanAndContext<T>(name: string, attributes: Record<string, string | number | boolean> | undefined, parentContext: Context | undefined, fn: (span: Span, activeContext: Context) => Promise<T>): Promise<T>;
|
|
32
|
+
export declare function createSpan(name: string, attributes?: Record<string, string | number | boolean>, parentContext?: Context): Span;
|
|
33
|
+
export declare function withSpan<T>(name: string, attributes: Record<string, string | number | boolean> | undefined, parentContext: Context | undefined, fn: (span: Span) => Promise<T>): Promise<T>;
|
|
34
|
+
export declare function withSpanSync<T>(name: string, attributes: Record<string, string | number | boolean> | undefined, parentContext: Context | undefined, fn: (span: Span) => T): T;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { context, propagation, trace } from "@opentelemetry/api";
|
|
2
|
+
var tracingEnabled = false;
|
|
3
|
+
function enableTracing() {
|
|
4
|
+
tracingEnabled = true;
|
|
5
|
+
}
|
|
6
|
+
function isTracingEnabled() {
|
|
7
|
+
return tracingEnabled;
|
|
8
|
+
}
|
|
9
|
+
var currentFrameSpan;
|
|
10
|
+
function setCurrentFrameSpan(span) {
|
|
11
|
+
currentFrameSpan = span;
|
|
12
|
+
}
|
|
13
|
+
function clearCurrentFrameSpan() {
|
|
14
|
+
currentFrameSpan = void 0;
|
|
15
|
+
}
|
|
16
|
+
function extractParentContext(traceContext) {
|
|
17
|
+
if (!traceContext) return context.active();
|
|
18
|
+
try {
|
|
19
|
+
return propagation.extract(context.active(), traceContext);
|
|
20
|
+
} catch (_error) {
|
|
21
|
+
return context.active();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function withSpanAndContext(name, attributes, parentContext, fn) {
|
|
25
|
+
if (!tracingEnabled) {
|
|
26
|
+
const noopSpan = trace.getTracer("telecine-browser").startSpan(name);
|
|
27
|
+
const result = await fn(noopSpan, parentContext || context.active());
|
|
28
|
+
noopSpan.end();
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
const tracer = trace.getTracer("telecine-browser");
|
|
32
|
+
let ctx;
|
|
33
|
+
if (parentContext) ctx = parentContext;
|
|
34
|
+
else {
|
|
35
|
+
const activeContext = context.active();
|
|
36
|
+
if (trace.getSpan(activeContext)?.isRecording?.()) ctx = activeContext;
|
|
37
|
+
else if (currentFrameSpan) ctx = trace.setSpan(context.active(), currentFrameSpan);
|
|
38
|
+
else ctx = activeContext;
|
|
39
|
+
}
|
|
40
|
+
const span = tracer.startSpan(name, { attributes }, ctx);
|
|
41
|
+
const spanContext = trace.setSpan(ctx, span);
|
|
42
|
+
try {
|
|
43
|
+
const result = await context.with(spanContext, async () => {
|
|
44
|
+
return fn(span, spanContext);
|
|
45
|
+
});
|
|
46
|
+
span.end();
|
|
47
|
+
return result;
|
|
48
|
+
} catch (error) {
|
|
49
|
+
span.recordException(error);
|
|
50
|
+
span.end();
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function createSpan(name, attributes, parentContext) {
|
|
55
|
+
const tracer = trace.getTracer("telecine-browser");
|
|
56
|
+
const ctx = parentContext || context.active();
|
|
57
|
+
return context.with(ctx, () => {
|
|
58
|
+
const span = tracer.startSpan(name);
|
|
59
|
+
if (attributes) span.setAttributes(attributes);
|
|
60
|
+
return span;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
async function withSpan(name, attributes, parentContext, fn) {
|
|
64
|
+
if (!tracingEnabled) {
|
|
65
|
+
const noopSpan = trace.getTracer("telecine-browser").startSpan(name);
|
|
66
|
+
const result = await fn(noopSpan);
|
|
67
|
+
noopSpan.end();
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
const tracer = trace.getTracer("telecine-browser");
|
|
71
|
+
let ctx;
|
|
72
|
+
if (parentContext) ctx = parentContext;
|
|
73
|
+
else {
|
|
74
|
+
const activeContext = context.active();
|
|
75
|
+
if (trace.getSpan(activeContext)?.isRecording?.()) ctx = activeContext;
|
|
76
|
+
else if (currentFrameSpan) ctx = trace.setSpan(context.active(), currentFrameSpan);
|
|
77
|
+
else ctx = activeContext;
|
|
78
|
+
}
|
|
79
|
+
const span = tracer.startSpan(name, { attributes }, ctx);
|
|
80
|
+
const spanContext = trace.setSpan(ctx, span);
|
|
81
|
+
try {
|
|
82
|
+
const result = await context.with(spanContext, async () => {
|
|
83
|
+
return fn(span);
|
|
84
|
+
});
|
|
85
|
+
span.end();
|
|
86
|
+
return result;
|
|
87
|
+
} catch (error) {
|
|
88
|
+
span.recordException(error);
|
|
89
|
+
span.end();
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function withSpanSync(name, attributes, parentContext, fn) {
|
|
94
|
+
if (!tracingEnabled) {
|
|
95
|
+
const noopSpan = trace.getTracer("telecine-browser").startSpan(name);
|
|
96
|
+
const result = fn(noopSpan);
|
|
97
|
+
noopSpan.end();
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
const span = createSpan(name, attributes, parentContext);
|
|
101
|
+
const ctx = parentContext || context.active();
|
|
102
|
+
try {
|
|
103
|
+
const result = context.with(trace.setSpan(ctx, span), () => fn(span));
|
|
104
|
+
span.end();
|
|
105
|
+
return result;
|
|
106
|
+
} catch (error) {
|
|
107
|
+
span.recordException(error);
|
|
108
|
+
span.end();
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
export { clearCurrentFrameSpan, enableTracing, extractParentContext, isTracingEnabled, setCurrentFrameSpan, withSpan, withSpanAndContext, withSpanSync };
|
package/dist/style.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:""}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.left-0{left:0}.top-0{top:0}.isolate{isolation:isolate}.z-10{z-index:10}.z-20,.z-\[20\]{z-index:20}.z-\[5\]{z-index:5}.col-span-2{grid-column:span 2/span 2}.mx-2{margin-left:.5rem;margin-right:.5rem}.mb-\[1px\]{margin-bottom:1px}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.grid{display:grid}.contents{display:contents}.hidden{display:none}.size-full{width:100%;height:100%}.h-\[1\.1rem\]{height:1.1rem}.h-\[200px\]{height:200px}.h-\[270px\]{height:270px}.h-\[300px\]{height:300px}.h-\[360px\]{height:360px}.h-\[500px\]{height:500px}.h-\[5px\]{height:5px}.h-full{height:100%}.w-1{width:.25rem}.w-\[1000px\]{width:1000px}.w-\[2px\]{width:2px}.w-\[480px\]{width:480px}.w-\[600px\]{width:600px}.w-\[640px\]{width:640px}.w-full{width:100%}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y))rotate(var(--tw-rotate))skewX(var(--tw-skew-x))skewY(var(--tw-skew-y))scaleX(var(--tw-scale-x))scaleY(var(--tw-scale-y))}.cursor-crosshair{cursor:crosshair}.resize{resize:both}.place-content-center{place-content:center}.items-center{align-items:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.whitespace-nowrap{white-space:nowrap}.text-nowrap{text-wrap:nowrap}.rounded{border-radius:.25rem}.border{border-width:1px}.border-r-2{border-right-width:2px}.border-blue-200{--tw-border-opacity:1;border-color:rgb(191 219 254/var(--tw-border-opacity))}.border-blue-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity))}.border-green-200{--tw-border-opacity:1;border-color:rgb(187 247 208/var(--tw-border-opacity))}.border-green-500{--tw-border-opacity:1;border-color:rgb(34 197 94/var(--tw-border-opacity))}.border-purple-200{--tw-border-opacity:1;border-color:rgb(233 213 255/var(--tw-border-opacity))}.border-red-700{--tw-border-opacity:1;border-color:rgb(185 28 28/var(--tw-border-opacity))}.border-slate-500{--tw-border-opacity:1;border-color:rgb(100 116 139/var(--tw-border-opacity))}.border-slate-600{--tw-border-opacity:1;border-color:rgb(71 85 105/var(--tw-border-opacity))}.border-yellow-500{--tw-border-opacity:1;border-color:rgb(234 179 8/var(--tw-border-opacity))}.border-b-slate-600{--tw-border-opacity:1;border-bottom-color:rgb(71 85 105/var(--tw-border-opacity))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(191 219 254/var(--tw-bg-opacity))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity))}.bg-green-200{--tw-bg-opacity:1;background-color:rgb(187 247 208/var(--tw-bg-opacity))}.bg-green-50{--tw-bg-opacity:1;background-color:rgb(240 253 244/var(--tw-bg-opacity))}.bg-lime-400{--tw-bg-opacity:1;background-color:rgb(163 230 53/var(--tw-bg-opacity))}.bg-purple-50{--tw-bg-opacity:1;background-color:rgb(250 245 255/var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity))}.bg-slate-200{--tw-bg-opacity:1;background-color:rgb(226 232 240/var(--tw-bg-opacity))}.bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}.bg-slate-500{--tw-bg-opacity:1;background-color:rgb(100 116 139/var(--tw-bg-opacity))}.bg-slate-800{--tw-bg-opacity:1;background-color:rgb(30 41 59/var(--tw-bg-opacity))}.bg-yellow-200{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity))}.bg-yellow-400{--tw-bg-opacity:1;background-color:rgb(250 204 21/var(--tw-bg-opacity))}.bg-opacity-20{--tw-bg-opacity:.2}.object-contain{-o-object-fit:contain;object-fit:contain}.p-4{padding:1rem}.p-\[1px\]{padding:1px}.px-0{padding-left:0;padding-right:0}.px-0\.5{padding-left:.125rem;padding-right:.125rem}.pb-0{padding-bottom:0}.pl-1{padding-left:.25rem}.pl-2{padding-left:.5rem}.pr-0{padding-right:0}.pr-1{padding-right:.25rem}.pt-\[8px\]{padding-top:8px}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-\[8px\]{font-size:8px}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.ordinal{--tw-ordinal:ordinal;font-variant-numeric:var(--tw-ordinal)var(--tw-slashed-zero)var(--tw-numeric-figure)var(--tw-numeric-spacing)var(--tw-numeric-fraction)}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.text-green-200{--tw-text-opacity:1;color:rgb(187 247 208/var(--tw-text-opacity))}.text-green-900{--tw-text-opacity:1;color:rgb(20 83 45/var(--tw-text-opacity))}.line-through{text-decoration-line:line-through}.opacity-50{opacity:.5}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-slate-300{--tw-shadow-color:#cbd5e1;--tw-shadow:var(--tw-shadow-colored)}.shadow-slate-600{--tw-shadow-color:#475569;--tw-shadow:var(--tw-shadow-colored)}.outline{outline-style:solid}.blur{--tw-blur:blur(8px);filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}.filter{filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur)var(--tw-backdrop-brightness)var(--tw-backdrop-contrast)var(--tw-backdrop-grayscale)var(--tw-backdrop-hue-rotate)var(--tw-backdrop-invert)var(--tw-backdrop-opacity)var(--tw-backdrop-saturate)var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur)var(--tw-backdrop-brightness)var(--tw-backdrop-contrast)var(--tw-backdrop-grayscale)var(--tw-backdrop-hue-rotate)var(--tw-backdrop-invert)var(--tw-backdrop-opacity)var(--tw-backdrop-saturate)var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter,backdrop-filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.hover\:bg-slate-400:hover{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity))}.peer:hover~.peer-hover\:border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184/var(--tw-border-opacity))}.peer:hover~.peer-hover\:bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}.data-\[focused\]\:bg-slate-400[data-focused]{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity))}.peer[data-focused]~.peer-data-\[focused\]\:border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184/var(--tw-border-opacity))}.peer[data-focused]~.peer-data-\[focused\]\:bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}
|
|
1
|
+
*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:""}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.left-0{left:0}.top-0{top:0}.isolate{isolation:isolate}.z-10{z-index:10}.z-20,.z-\[20\]{z-index:20}.z-\[5\]{z-index:5}.col-span-2{grid-column:span 2/span 2}.mx-2{margin-left:.5rem;margin-right:.5rem}.mb-\[1px\]{margin-bottom:1px}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.grid{display:grid}.contents{display:contents}.hidden{display:none}.size-full{width:100%;height:100%}.h-\[1\.1rem\]{height:1.1rem}.h-\[200px\]{height:200px}.h-\[270px\]{height:270px}.h-\[300px\]{height:300px}.h-\[360px\]{height:360px}.h-\[500px\]{height:500px}.h-\[5px\]{height:5px}.h-full{height:100%}.w-1{width:.25rem}.w-\[1000px\]{width:1000px}.w-\[2px\]{width:2px}.w-\[480px\]{width:480px}.w-\[600px\]{width:600px}.w-\[640px\]{width:640px}.w-full{width:100%}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y))rotate(var(--tw-rotate))skewX(var(--tw-skew-x))skewY(var(--tw-skew-y))scaleX(var(--tw-scale-x))scaleY(var(--tw-scale-y))}.cursor-crosshair{cursor:crosshair}.resize{resize:both}.place-content-center{place-content:center}.items-center{align-items:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.whitespace-nowrap{white-space:nowrap}.text-nowrap{text-wrap:nowrap}.rounded{border-radius:.25rem}.border{border-width:1px}.border-r-2{border-right-width:2px}.border-blue-200{--tw-border-opacity:1;border-color:rgb(191 219 254/var(--tw-border-opacity,1))}.border-blue-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.border-green-200{--tw-border-opacity:1;border-color:rgb(187 247 208/var(--tw-border-opacity,1))}.border-green-500{--tw-border-opacity:1;border-color:rgb(34 197 94/var(--tw-border-opacity,1))}.border-purple-200{--tw-border-opacity:1;border-color:rgb(233 213 255/var(--tw-border-opacity,1))}.border-red-700{--tw-border-opacity:1;border-color:rgb(185 28 28/var(--tw-border-opacity,1))}.border-slate-500{--tw-border-opacity:1;border-color:rgb(100 116 139/var(--tw-border-opacity,1))}.border-slate-600{--tw-border-opacity:1;border-color:rgb(71 85 105/var(--tw-border-opacity,1))}.border-yellow-500{--tw-border-opacity:1;border-color:rgb(234 179 8/var(--tw-border-opacity,1))}.border-b-slate-600{--tw-border-opacity:1;border-bottom-color:rgb(71 85 105/var(--tw-border-opacity,1))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(191 219 254/var(--tw-bg-opacity,1))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.bg-green-200{--tw-bg-opacity:1;background-color:rgb(187 247 208/var(--tw-bg-opacity,1))}.bg-green-50{--tw-bg-opacity:1;background-color:rgb(240 253 244/var(--tw-bg-opacity,1))}.bg-lime-400{--tw-bg-opacity:1;background-color:rgb(163 230 53/var(--tw-bg-opacity,1))}.bg-purple-50{--tw-bg-opacity:1;background-color:rgb(250 245 255/var(--tw-bg-opacity,1))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity,1))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.bg-slate-200{--tw-bg-opacity:1;background-color:rgb(226 232 240/var(--tw-bg-opacity,1))}.bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity,1))}.bg-slate-500{--tw-bg-opacity:1;background-color:rgb(100 116 139/var(--tw-bg-opacity,1))}.bg-slate-800{--tw-bg-opacity:1;background-color:rgb(30 41 59/var(--tw-bg-opacity,1))}.bg-yellow-200{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity,1))}.bg-yellow-400{--tw-bg-opacity:1;background-color:rgb(250 204 21/var(--tw-bg-opacity,1))}.bg-opacity-20{--tw-bg-opacity:.2}.object-contain{-o-object-fit:contain;object-fit:contain}.p-4{padding:1rem}.p-\[1px\]{padding:1px}.px-0\.5{padding-left:.125rem;padding-right:.125rem}.pb-0{padding-bottom:0}.pl-1{padding-left:.25rem}.pl-2{padding-left:.5rem}.pr-0{padding-right:0}.pr-1{padding-right:.25rem}.pt-\[8px\]{padding-top:8px}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-\[8px\]{font-size:8px}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.ordinal{--tw-ordinal:ordinal;font-variant-numeric:var(--tw-ordinal)var(--tw-slashed-zero)var(--tw-numeric-figure)var(--tw-numeric-spacing)var(--tw-numeric-fraction)}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity,1))}.text-green-200{--tw-text-opacity:1;color:rgb(187 247 208/var(--tw-text-opacity,1))}.text-green-900{--tw-text-opacity:1;color:rgb(20 83 45/var(--tw-text-opacity,1))}.line-through{text-decoration-line:line-through}.opacity-50{opacity:.5}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-slate-300{--tw-shadow-color:#cbd5e1;--tw-shadow:var(--tw-shadow-colored)}.shadow-slate-600{--tw-shadow-color:#475569;--tw-shadow:var(--tw-shadow-colored)}.outline{outline-style:solid}.blur{--tw-blur:blur(8px);filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}.filter{filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur)var(--tw-backdrop-brightness)var(--tw-backdrop-contrast)var(--tw-backdrop-grayscale)var(--tw-backdrop-hue-rotate)var(--tw-backdrop-invert)var(--tw-backdrop-opacity)var(--tw-backdrop-saturate)var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur)var(--tw-backdrop-brightness)var(--tw-backdrop-contrast)var(--tw-backdrop-grayscale)var(--tw-backdrop-hue-rotate)var(--tw-backdrop-invert)var(--tw-backdrop-opacity)var(--tw-backdrop-saturate)var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter,backdrop-filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.hover\:bg-slate-400:hover{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity,1))}.peer:hover~.peer-hover\:border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184/var(--tw-border-opacity,1))}.peer:hover~.peer-hover\:bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity,1))}.data-\[focused\]\:bg-slate-400[data-focused]{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity,1))}.peer[data-focused]~.peer-data-\[focused\]\:border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184/var(--tw-border-opacity,1))}.peer[data-focused]~.peer-data-\[focused\]\:bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity,1))}
|
|
2
2
|
/*$vite$:1*/
|
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Request deduplication utility
|
|
3
|
-
* Manages pending requests to prevent concurrent duplicate requests
|
|
4
|
-
*/
|
|
5
1
|
var RequestDeduplicator = class {
|
|
6
2
|
constructor() {
|
|
7
3
|
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
8
4
|
}
|
|
9
|
-
/**
|
|
10
|
-
* Execute a request with deduplication
|
|
11
|
-
* If a request with the same key is already pending, return the existing promise
|
|
12
|
-
* Otherwise, execute the request factory and track the promise
|
|
13
|
-
*/
|
|
14
5
|
async executeRequest(key, requestFactory) {
|
|
15
6
|
const existingRequest = this.pendingRequests.get(key);
|
|
16
7
|
if (existingRequest) return existingRequest;
|
|
@@ -25,27 +16,15 @@ var RequestDeduplicator = class {
|
|
|
25
16
|
throw error;
|
|
26
17
|
}
|
|
27
18
|
}
|
|
28
|
-
/**
|
|
29
|
-
* Clear all pending requests (used in cache clearing)
|
|
30
|
-
*/
|
|
31
19
|
clear() {
|
|
32
20
|
this.pendingRequests.clear();
|
|
33
21
|
}
|
|
34
|
-
/**
|
|
35
|
-
* Get number of pending requests
|
|
36
|
-
*/
|
|
37
22
|
getPendingCount() {
|
|
38
23
|
return this.pendingRequests.size;
|
|
39
24
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Check if a request is pending
|
|
42
|
-
*/
|
|
43
25
|
isPending(key) {
|
|
44
26
|
return this.pendingRequests.has(key);
|
|
45
27
|
}
|
|
46
|
-
/**
|
|
47
|
-
* Get all pending request keys
|
|
48
|
-
*/
|
|
49
28
|
getPendingKeys() {
|
|
50
29
|
return Array.from(this.pendingRequests.keys());
|
|
51
30
|
}
|
|
@@ -2,10 +2,6 @@ var URLTokenDeduplicator = class {
|
|
|
2
2
|
constructor() {
|
|
3
3
|
this.tokenCache = /* @__PURE__ */ new Map();
|
|
4
4
|
}
|
|
5
|
-
/**
|
|
6
|
-
* Get or create a URL token with global deduplication
|
|
7
|
-
* Multiple requests for the same cache key will share the same token promise
|
|
8
|
-
*/
|
|
9
5
|
async getToken(cacheKey, tokenFactory, parseExpiration) {
|
|
10
6
|
const now = Date.now();
|
|
11
7
|
const cached = this.tokenCache.get(cacheKey);
|
|
@@ -27,36 +23,20 @@ var URLTokenDeduplicator = class {
|
|
|
27
23
|
});
|
|
28
24
|
return tokenPromise;
|
|
29
25
|
}
|
|
30
|
-
/**
|
|
31
|
-
* Clear all cached tokens (used in testing)
|
|
32
|
-
*/
|
|
33
26
|
clear() {
|
|
34
27
|
this.tokenCache.clear();
|
|
35
28
|
}
|
|
36
|
-
/**
|
|
37
|
-
* Get number of cached tokens
|
|
38
|
-
*/
|
|
39
29
|
getCachedCount() {
|
|
40
30
|
return this.tokenCache.size;
|
|
41
31
|
}
|
|
42
|
-
/**
|
|
43
|
-
* Check if a token is cached and valid
|
|
44
|
-
*/
|
|
45
32
|
hasValidToken(cacheKey) {
|
|
46
33
|
const cached = this.tokenCache.get(cacheKey);
|
|
47
34
|
if (!cached) return false;
|
|
48
|
-
|
|
49
|
-
return now < cached.expiration;
|
|
35
|
+
return Date.now() < cached.expiration;
|
|
50
36
|
}
|
|
51
|
-
/**
|
|
52
|
-
* Get all cached token keys
|
|
53
|
-
*/
|
|
54
37
|
getCachedKeys() {
|
|
55
38
|
return Array.from(this.tokenCache.keys());
|
|
56
39
|
}
|
|
57
|
-
/**
|
|
58
|
-
* Remove expired tokens from cache
|
|
59
|
-
*/
|
|
60
40
|
cleanup() {
|
|
61
41
|
const now = Date.now();
|
|
62
42
|
for (const [key, entry] of this.tokenCache.entries()) if (now >= entry.expiration) this.tokenCache.delete(key);
|
|
@@ -2,9 +2,6 @@ var UrlGenerator = class {
|
|
|
2
2
|
constructor(baseUrl) {
|
|
3
3
|
this.baseUrl = baseUrl;
|
|
4
4
|
}
|
|
5
|
-
/**
|
|
6
|
-
* Generate video segment URL
|
|
7
|
-
*/
|
|
8
5
|
generateSegmentUrl(segmentId, renditionId, metadata) {
|
|
9
6
|
const audioRendition = metadata.audioRendition;
|
|
10
7
|
const videoRendition = metadata.videoRendition;
|
|
@@ -13,31 +10,17 @@ var UrlGenerator = class {
|
|
|
13
10
|
console.error("Rendition not found", metadata);
|
|
14
11
|
throw new Error(`Rendition ${renditionId} not found`);
|
|
15
12
|
}
|
|
16
|
-
|
|
17
|
-
return template.replace("{rendition}", renditionId).replace("{segmentId}", segmentId.toString()).replace("{src}", metadata.src).replace("{trackId}", rendition.trackId?.toString() ?? "");
|
|
13
|
+
return (segmentId === "init" ? metadata.templates.initSegment : metadata.templates.mediaSegment).replace("{rendition}", renditionId).replace("{segmentId}", segmentId.toString()).replace("{src}", metadata.src).replace("{trackId}", rendition.trackId?.toString() ?? "");
|
|
18
14
|
}
|
|
19
|
-
/**
|
|
20
|
-
* Generate init segment URL
|
|
21
|
-
*/
|
|
22
15
|
generateInitSegmentUrl(mediaUrl, rendition) {
|
|
23
16
|
return `${this.baseUrl()}/api/v1/transcode/${rendition}/init.m4s?url=${encodeURIComponent(mediaUrl)}`;
|
|
24
17
|
}
|
|
25
|
-
/**
|
|
26
|
-
* Generate manifest URL
|
|
27
|
-
*/
|
|
28
18
|
generateManifestUrl(mediaUrl) {
|
|
29
19
|
return `${this.baseUrl()}/api/v1/transcode/manifest.json?url=${encodeURIComponent(mediaUrl)}`;
|
|
30
20
|
}
|
|
31
|
-
/**
|
|
32
|
-
* Generate track fragment index URL
|
|
33
|
-
*/
|
|
34
21
|
generateTrackFragmentIndexUrl(mediaUrl) {
|
|
35
|
-
|
|
36
|
-
return `/@ef-track-fragment-index/${normalizedSrc}`;
|
|
22
|
+
return `/@ef-track-fragment-index/${mediaUrl.startsWith("/") ? mediaUrl.slice(1) : mediaUrl}`;
|
|
37
23
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Generate quality presets URL
|
|
40
|
-
*/
|
|
41
24
|
generatePresetsUrl() {
|
|
42
25
|
return `${this.baseUrl()}/api/v1/transcode/presets`;
|
|
43
26
|
}
|