@linker-design-plus/timeline-track 2.0.14 → 2.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/dist/components/panel/ClipConfigPanel.d.ts +0 -2
- package/dist/components/panel/ClipConfigPanelRenderer.d.ts +1 -0
- package/dist/core/controllers/previewBackend.d.ts +3 -0
- package/dist/core/controllers/previewPendingOverlayRenderer.d.ts +1 -0
- package/dist/core/controllers/timelineClipEventController.d.ts +1 -0
- package/dist/core/controllers/timelinePreviewSession.d.ts +12 -0
- package/dist/core/facade/timelineManager.d.ts +16 -0
- package/dist/core/models/types.d.ts +16 -2
- package/dist/core/resources/previewMediaSourceResolver.d.ts +4 -0
- package/dist/core/resources/resourceCache/cacheKey.d.ts +5 -0
- package/dist/core/resources/resourceCache/http.d.ts +5 -0
- package/dist/core/resources/resourceCache/index.d.ts +7 -0
- package/dist/core/resources/resourceCache/metadataStore.d.ts +11 -0
- package/dist/core/resources/resourceCache/resourceCacheManager.d.ts +39 -0
- package/dist/core/resources/resourceCache/storage.d.ts +24 -0
- package/dist/core/resources/resourceCache/types.d.ts +85 -0
- package/dist/index.cjs.js +54 -57
- package/dist/index.es.js +4720 -3902
- package/dist/utils/mediaElement.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -66,6 +66,23 @@ timeline.on('history_change', (_event, data) => {
|
|
|
66
66
|
});
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
+
### 预览资源缓存
|
|
70
|
+
|
|
71
|
+
预览资源缓存默认关闭。开启后,可被前端 `fetch` 读取且不超过 100MB 的 `http:` / `https:` 音视频文件会被缓存到浏览器存储中,用于后续预览播放。默认策略为 30 天 TTL、10GB 应用级容量上限、优先 OPFS,并在 OPFS 不可用时降级到 IndexedDB Blob。缓存失败会自动回退原始媒体 URL。
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
const timeline = new TimelineManager({
|
|
75
|
+
container,
|
|
76
|
+
previewBackend: 'dom',
|
|
77
|
+
resourceCache: {
|
|
78
|
+
enabled: true,
|
|
79
|
+
resolveMode: 'prefer-fast-start'
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
第一版不会缓存 HLS manifest / 分片,也不会缓存超过 100MB 的媒体文件。
|
|
85
|
+
|
|
69
86
|
## 核心能力
|
|
70
87
|
|
|
71
88
|
- 多轨时间线编辑,支持视频轨和音频轨
|
|
@@ -89,6 +106,7 @@ timeline.on('history_change', (_event, data) => {
|
|
|
89
106
|
- `updateClip(clipId, updates)` / `removeClip(clipId)`
|
|
90
107
|
- `selectClip(clipId)` / `clearSelection()` / `getSelectedClip()`
|
|
91
108
|
- `splitCurrentClip()` / `removeClipGaps()`
|
|
109
|
+
- `getRenderedHeight()`
|
|
92
110
|
- `undo()` / `redo()` / `clearHistory()`
|
|
93
111
|
- `attachPreview(containerOrConfig)` / `detachPreview()`
|
|
94
112
|
- `exportTimeline()` / `loadDraft(data)`
|
|
@@ -94,8 +94,6 @@ export declare class ClipConfigPanel {
|
|
|
94
94
|
private syncVoiceStateForClip;
|
|
95
95
|
private syncActiveTab;
|
|
96
96
|
private supportsVoicePanel;
|
|
97
|
-
private resolveDefaultVoiceFilterTag;
|
|
98
|
-
private getVisibleVoiceOptions;
|
|
99
97
|
private ensureVoiceFilters;
|
|
100
98
|
private handleVoiceFilterChange;
|
|
101
99
|
private handleVoiceSelect;
|
|
@@ -79,6 +79,7 @@ export declare class ClipConfigPanelRenderer extends LitDomRenderer<ClipConfigPa
|
|
|
79
79
|
private renderVoiceLoadingOverlay;
|
|
80
80
|
private renderEmptyState;
|
|
81
81
|
private renderPanel;
|
|
82
|
+
private renderTabPanel;
|
|
82
83
|
private renderTabBar;
|
|
83
84
|
private renderActionBar;
|
|
84
85
|
private renderVoiceActionBar;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ActiveClipPlaybackInfo, Clip, ClipVisualTransform, PlayState, PreviewAspectRatio, PreviewMediaSource, PreviewSourceResolver, TextPreviewFontConfig, TimeMs } from '../models/types';
|
|
2
2
|
import type { SourceMediaRegistry } from '../resources/sourceMediaRegistry';
|
|
3
|
+
import type { ResourceCacheManager } from '../resources/resourceCache';
|
|
3
4
|
import type { DiagnosticsCenter, DiagnosticEmitInput } from '../../utils/diagnostics';
|
|
4
5
|
export interface TimelinePreviewSyncPayload {
|
|
5
6
|
activeClips: ActiveClipPlaybackInfo[];
|
|
@@ -19,6 +20,7 @@ export interface TimelinePreviewBackendCallbacks {
|
|
|
19
20
|
onSyncProcessed?: (syncRequestId?: number) => void;
|
|
20
21
|
onRuntimeStateChange?: (state: PreviewRuntimeState) => void;
|
|
21
22
|
onAspectRatioChange?: (aspectRatio: PreviewAspectRatio) => void;
|
|
23
|
+
onPreviewClipSelect?: (clipId: string) => void;
|
|
22
24
|
onVisualTransformCommit?: (clipId: string, visualTransform: ClipVisualTransform) => void;
|
|
23
25
|
onPendingPreviewRetry?: () => void;
|
|
24
26
|
onRuntimeError?: (error: unknown) => void;
|
|
@@ -71,6 +73,7 @@ export interface TimelinePreviewBackendOptions {
|
|
|
71
73
|
previewSourceResolver?: PreviewSourceResolver;
|
|
72
74
|
textPreviewFont?: TextPreviewFontConfig | null;
|
|
73
75
|
sourceMediaRegistry?: SourceMediaRegistry;
|
|
76
|
+
resourceCacheManager?: ResourceCacheManager | null;
|
|
74
77
|
diagnostics?: DiagnosticsCenter;
|
|
75
78
|
getDiagnosticsContext?: () => Partial<DiagnosticEmitInput>;
|
|
76
79
|
rootClassName?: string;
|
|
@@ -3,6 +3,7 @@ import type { DomRenderer } from '../renderers/domRenderer';
|
|
|
3
3
|
export interface PreviewPendingOverlayViewModel {
|
|
4
4
|
pendingState: PreviewPendingState | null;
|
|
5
5
|
runtimeState: PreviewRuntimeState;
|
|
6
|
+
isBuffering: boolean;
|
|
6
7
|
}
|
|
7
8
|
export declare class PreviewPendingOverlayRenderer implements DomRenderer<PreviewPendingOverlayViewModel> {
|
|
8
9
|
private container;
|
|
@@ -17,6 +17,7 @@ export interface ClipSelectPlan {
|
|
|
17
17
|
export declare function applyClipMutationEffects(handlers: ClipMutationEffectHandlers): void;
|
|
18
18
|
export declare function applyClipUpdateEffects(handlers: ClipUpdateMutationEffectHandlers): void;
|
|
19
19
|
export declare function shouldReloadClipThumbnails(clip: Clip, originalClip?: Clip, hasThumbnailProvider?: boolean): boolean;
|
|
20
|
+
export declare function calculatePlaybackEndTime(clips: Pick<Clip, 'endTime'>[]): number;
|
|
20
21
|
export declare function calculateCanPlayState(clips: Pick<Clip, 'endTime'>[], currentTime: number): boolean;
|
|
21
22
|
interface SyncCanPlayStateOptions {
|
|
22
23
|
currentCanPlay: boolean;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ActiveClipPlaybackInfo, ClipVisualTransform, PlayState, PreviewAspectRatio, PreviewSourceResolver, TextPreviewFontConfig, TimeMs, TrackType } from '../models/types';
|
|
2
2
|
import type { SourceMediaRegistry } from '../resources/sourceMediaRegistry';
|
|
3
|
+
import type { ResourceCacheManager } from '../resources/resourceCache';
|
|
3
4
|
import type { PreviewPendingState, PreviewRuntimeState } from './previewBackend';
|
|
4
5
|
import { type DiagnosticEmitInput, type DiagnosticsCenter } from '../../utils/diagnostics';
|
|
5
6
|
interface TimelinePreviewSessionCallbacks {
|
|
@@ -8,6 +9,7 @@ interface TimelinePreviewSessionCallbacks {
|
|
|
8
9
|
onSyncProcessed?: (syncRequestId?: number) => void;
|
|
9
10
|
onRuntimeStateChange?: (state: PreviewRuntimeState) => void;
|
|
10
11
|
onAspectRatioChange?: (aspectRatio: PreviewAspectRatio) => void;
|
|
12
|
+
onPreviewClipSelect?: (clipId: string) => void;
|
|
11
13
|
onVisualTransformCommit?: (clipId: string, visualTransform: ClipVisualTransform) => void;
|
|
12
14
|
onPendingPreviewRetry?: () => void;
|
|
13
15
|
}
|
|
@@ -23,6 +25,7 @@ interface TimelinePreviewSessionDependencies {
|
|
|
23
25
|
previewSourceResolver?: PreviewSourceResolver;
|
|
24
26
|
textPreviewFont?: TextPreviewFontConfig | null;
|
|
25
27
|
sourceMediaRegistry?: SourceMediaRegistry;
|
|
28
|
+
resourceCacheManager?: ResourceCacheManager | null;
|
|
26
29
|
}
|
|
27
30
|
export interface TimelinePreviewSyncPayload {
|
|
28
31
|
activeClips: ActiveClipPlaybackInfo[];
|
|
@@ -93,12 +96,19 @@ export declare class TimelinePreviewSession {
|
|
|
93
96
|
private createSlot;
|
|
94
97
|
private resetSlotRecoveryTracking;
|
|
95
98
|
private destroySlot;
|
|
99
|
+
private releaseSlotObjectUrl;
|
|
100
|
+
private clearPendingRuntimeSource;
|
|
101
|
+
private rememberSlotObjectUrl;
|
|
102
|
+
private revokeResolvedObjectUrl;
|
|
96
103
|
private getTrackSlots;
|
|
97
104
|
private swapTrackSlots;
|
|
98
105
|
private applyTrackPlan;
|
|
99
106
|
private applySlotTarget;
|
|
107
|
+
private settleResolvedSourceWithoutRecovery;
|
|
100
108
|
private resolveDesiredSource;
|
|
101
109
|
private decorateSlotSourceUrl;
|
|
110
|
+
private resolvePlayableSlotSource;
|
|
111
|
+
private getReusableResolvedSlotSource;
|
|
102
112
|
private slotNeedsRecovery;
|
|
103
113
|
private recoverSlot;
|
|
104
114
|
private finishSlotRecovery;
|
|
@@ -113,7 +123,9 @@ export declare class TimelinePreviewSession {
|
|
|
113
123
|
private scheduleDeferredPreloadFlush;
|
|
114
124
|
private flushDeferredPreloads;
|
|
115
125
|
private applyResolvedSlotState;
|
|
126
|
+
private buildCurrentTargetForSlot;
|
|
116
127
|
private isCurrentRequest;
|
|
128
|
+
private isCurrentSourceTarget;
|
|
117
129
|
private shouldIgnoreExpectedEmptied;
|
|
118
130
|
private shouldIgnoreExpectedAbort;
|
|
119
131
|
private shouldIgnoreClearedSlotRecoverableEvent;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type TimelinePreviewBackend } from '../controllers';
|
|
2
|
+
import { type TimelineResourceCacheStats } from '../resources/resourceCache';
|
|
2
3
|
import { TimelineConfig, Clip, ClipConfig, TimeMs, PlayState, Action, TimelineEvent, EventListener as TimelineEventListener, TimelineExportData, Track as TrackEntity, ThumbnailProvider, TrackInsertionPlacement, TrackType, ActiveClipPlaybackInfo, PreviewAspectRatio, PreviewMountConfig, PreviewBackendType, SelectedClipAudioAction, ClipConfigVoicePanelOptions } from '../models';
|
|
3
4
|
import type { ResolvedPlaybackPlan } from '../controllers/timelinePlaybackResolver';
|
|
4
5
|
import { TimelineClipConfigController } from '../controllers/timelineClipConfigController';
|
|
@@ -78,6 +79,7 @@ export declare class TimelineManager {
|
|
|
78
79
|
private playbackAttemptId;
|
|
79
80
|
private lastPreviewSyncedPlayState;
|
|
80
81
|
private previewSyncInteractionMode;
|
|
82
|
+
private readonly resourceCacheManager;
|
|
81
83
|
constructor(config?: Partial<TimelineConfig>);
|
|
82
84
|
private createPlaybackAttemptId;
|
|
83
85
|
private refreshPlaybackAttempt;
|
|
@@ -151,6 +153,7 @@ export declare class TimelineManager {
|
|
|
151
153
|
private getTracksSortedByOrder;
|
|
152
154
|
private getPlaybackTracksSnapshot;
|
|
153
155
|
private buildPlaybackPlan;
|
|
156
|
+
private hasTimelineVideoClip;
|
|
154
157
|
private getPreviewAutoAspectRatioClipOrderMap;
|
|
155
158
|
private getNextPreviewAutoAspectRatioOrder;
|
|
156
159
|
private getAutoAspectRatioClip;
|
|
@@ -160,6 +163,7 @@ export declare class TimelineManager {
|
|
|
160
163
|
private beginPendingPreview;
|
|
161
164
|
updatePendingPreviewState(): void;
|
|
162
165
|
private buildPreviewPendingState;
|
|
166
|
+
private buildPreviewIndicatorState;
|
|
163
167
|
private clearPendingPreviewState;
|
|
164
168
|
private resetPreviewRuntimeState;
|
|
165
169
|
private destroyPreviewSession;
|
|
@@ -375,6 +379,13 @@ export declare class TimelineManager {
|
|
|
375
379
|
getPlayState(): PlayState;
|
|
376
380
|
setDuration(duration: TimeMs): void;
|
|
377
381
|
getDuration(): TimeMs;
|
|
382
|
+
/**
|
|
383
|
+
* 获取当前时间轴内容完整渲染高度。
|
|
384
|
+
*
|
|
385
|
+
* 该高度包含顶部时间刻度、所有轨道内容和底部横向滚动条,可供外部容器
|
|
386
|
+
* 在需要贴合内容时作为高度参考。
|
|
387
|
+
*/
|
|
388
|
+
getRenderedHeight(): number;
|
|
378
389
|
/**
|
|
379
390
|
* 调整时间轴大小以适配容器
|
|
380
391
|
* @param width 新的宽度
|
|
@@ -479,6 +490,7 @@ export declare class TimelineManager {
|
|
|
479
490
|
removeSelectedClips(): boolean;
|
|
480
491
|
canSeparateClipAudio(clipId: string): boolean;
|
|
481
492
|
canRestoreClipAudio(clipId: string): boolean;
|
|
493
|
+
private pausePlaybackForAudioSeparation;
|
|
482
494
|
private resolvePreferredSeparatedAudioTrackId;
|
|
483
495
|
separateClipAudio(clipId: string): Promise<string | null>;
|
|
484
496
|
restoreClipAudio(clipId: string): boolean;
|
|
@@ -496,6 +508,9 @@ export declare class TimelineManager {
|
|
|
496
508
|
* @returns 从 0 到最后一个音视频 clip 终点的时长(毫秒)
|
|
497
509
|
*/
|
|
498
510
|
getTrackTotalDuration(): TimeMs;
|
|
511
|
+
getResourceCacheStats(): Promise<TimelineResourceCacheStats>;
|
|
512
|
+
cleanupResourceCache(): Promise<void>;
|
|
513
|
+
clearResourceCache(): Promise<void>;
|
|
499
514
|
destroy(): void;
|
|
500
515
|
private initKeyboardShortcuts;
|
|
501
516
|
/** 清除历史堆栈 */
|
|
@@ -543,6 +558,7 @@ export declare class TimelineManager {
|
|
|
543
558
|
private handleBoxSelectEnd;
|
|
544
559
|
private isPointOnClip;
|
|
545
560
|
private getClipsIntersectingBox;
|
|
561
|
+
private resolveTrackRenderHeight;
|
|
546
562
|
private addClipToTrack;
|
|
547
563
|
private cloneTrackSnapshot;
|
|
548
564
|
private ensureTrackFromHistorySnapshot;
|
|
@@ -22,7 +22,6 @@ export interface TextClipStyle {
|
|
|
22
22
|
rotation: number;
|
|
23
23
|
strokeColor: string;
|
|
24
24
|
strokeWidth: number;
|
|
25
|
-
lineHeight: number;
|
|
26
25
|
paddingX: number;
|
|
27
26
|
}
|
|
28
27
|
export declare const DEFAULT_TEXT_CLIP_STYLE: TextClipStyle;
|
|
@@ -38,7 +37,12 @@ export interface HlsFmp4PreviewMediaSource {
|
|
|
38
37
|
mimeType: string;
|
|
39
38
|
kind: 'hls-fmp4';
|
|
40
39
|
}
|
|
41
|
-
export
|
|
40
|
+
export interface AudioPreviewMediaSource {
|
|
41
|
+
url: string;
|
|
42
|
+
mimeType: string;
|
|
43
|
+
kind: 'audio';
|
|
44
|
+
}
|
|
45
|
+
export type PreviewMediaSource = Mp4PreviewMediaSource | HlsFmp4PreviewMediaSource | AudioPreviewMediaSource;
|
|
42
46
|
export type PreviewSourceResolver = (clip: Clip) => PreviewMediaSource | null | Promise<PreviewMediaSource | null>;
|
|
43
47
|
export interface TextPreviewFontConfig {
|
|
44
48
|
fontName: string;
|
|
@@ -191,6 +195,15 @@ export interface TimelineKeyboardShortcutsConfig {
|
|
|
191
195
|
}
|
|
192
196
|
export declare const defaultDarkTheme: Theme;
|
|
193
197
|
export declare function resolveTheme(theme?: ThemeConfig): Theme;
|
|
198
|
+
export interface TimelineResourceCacheConfig {
|
|
199
|
+
enabled?: boolean;
|
|
200
|
+
maxEntryBytes?: number;
|
|
201
|
+
maxTotalBytes?: number;
|
|
202
|
+
ttlMs?: number;
|
|
203
|
+
preferStorage?: 'opfs' | 'indexeddb';
|
|
204
|
+
resolveMode?: 'prefer-fast-start' | 'prefer-cache-ready';
|
|
205
|
+
allowedMimeTypes?: string[];
|
|
206
|
+
}
|
|
194
207
|
export interface TimelineConfig {
|
|
195
208
|
duration: TimeMs;
|
|
196
209
|
zoom: number;
|
|
@@ -207,6 +220,7 @@ export interface TimelineConfig {
|
|
|
207
220
|
thumbnailProvider?: ThumbnailProvider;
|
|
208
221
|
previewBackend?: PreviewBackendType;
|
|
209
222
|
previewSourceResolver?: PreviewSourceResolver;
|
|
223
|
+
resourceCache?: boolean | TimelineResourceCacheConfig;
|
|
210
224
|
textPreviewFont?: TextPreviewFontConfig | null;
|
|
211
225
|
draftData?: TimelineExportData;
|
|
212
226
|
keyboardShortcuts?: false | TimelineKeyboardShortcutsConfig;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ResolveResourceInput, ResourceCacheConfig, ResourceCacheOptions } from './types';
|
|
2
|
+
export declare function normalizeResourceCacheOptions(config: ResourceCacheConfig | undefined): ResourceCacheOptions;
|
|
3
|
+
export declare function normalizeResourceUrl(url: string): string;
|
|
4
|
+
export declare function buildResourceCacheKey(input: Pick<ResolveResourceInput, 'sourceKey' | 'url'>): Promise<string>;
|
|
5
|
+
export declare function shouldBypassResourceCache(input: ResolveResourceInput, allowedMimeTypes?: string[]): boolean;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from './types';
|
|
2
|
+
export { IndexedDbResourceMetadataStore, createMemoryMetadataStore } from './metadataStore';
|
|
3
|
+
export { IndexedDbResourceStorage, OpfsResourceStorage, createMemoryResourceStorage, createResourceCacheStorage } from './storage';
|
|
4
|
+
export { buildResourceCacheKey, normalizeResourceCacheOptions, normalizeResourceUrl, shouldBypassResourceCache } from './cacheKey';
|
|
5
|
+
export { FetchResourceCacheHttpClient } from './http';
|
|
6
|
+
export { ResourceCacheManager } from './resourceCacheManager';
|
|
7
|
+
export type { ResourceCacheManagerDependencies } from './resourceCacheManager';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CachedResourceMetadata, ResourceCacheMetadataStore } from './types';
|
|
2
|
+
export declare class IndexedDbResourceMetadataStore implements ResourceCacheMetadataStore {
|
|
3
|
+
private dbPromise;
|
|
4
|
+
private getDb;
|
|
5
|
+
get(cacheKey: string): Promise<CachedResourceMetadata | null>;
|
|
6
|
+
put(metadata: CachedResourceMetadata): Promise<void>;
|
|
7
|
+
delete(cacheKey: string): Promise<void>;
|
|
8
|
+
clear(): Promise<void>;
|
|
9
|
+
list(): Promise<CachedResourceMetadata[]>;
|
|
10
|
+
}
|
|
11
|
+
export declare function createMemoryMetadataStore(initial?: CachedResourceMetadata[]): ResourceCacheMetadataStore;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ObjectUrlAdapter, ResolveResourceInput, ResolvedCachedResource, ResourceCacheConfig, ResourceCacheHttpClient, ResourceCacheMetadataStore, ResourceCacheStats, ResourceCacheStorage } from './types';
|
|
2
|
+
export interface ResourceCacheManagerDependencies {
|
|
3
|
+
options?: ResourceCacheConfig;
|
|
4
|
+
metadataStore?: ResourceCacheMetadataStore;
|
|
5
|
+
storage?: ResourceCacheStorage;
|
|
6
|
+
http?: ResourceCacheHttpClient;
|
|
7
|
+
objectUrl?: ObjectUrlAdapter;
|
|
8
|
+
now?: () => number;
|
|
9
|
+
cacheKeyBuilder?: (input: Pick<ResolveResourceInput, 'sourceKey' | 'url'>) => Promise<string>;
|
|
10
|
+
onEvent?: (eventName: string, data: Record<string, unknown>) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare class ResourceCacheManager {
|
|
13
|
+
private readonly options;
|
|
14
|
+
private readonly metadataStore;
|
|
15
|
+
private readonly storagePromise;
|
|
16
|
+
private readonly http;
|
|
17
|
+
private readonly objectUrl;
|
|
18
|
+
private readonly now;
|
|
19
|
+
private readonly cacheKeyBuilder;
|
|
20
|
+
private readonly onEvent?;
|
|
21
|
+
private readonly objectUrls;
|
|
22
|
+
private readonly inflightDownloads;
|
|
23
|
+
constructor(dependencies?: ResourceCacheManagerDependencies);
|
|
24
|
+
resolve(input: ResolveResourceInput): Promise<ResolvedCachedResource>;
|
|
25
|
+
resolvePlayableUrl(input: ResolveResourceInput): Promise<ResolvedCachedResource>;
|
|
26
|
+
revokeObjectUrl(url: string): void;
|
|
27
|
+
cleanupExpired(): Promise<void>;
|
|
28
|
+
clear(): Promise<void>;
|
|
29
|
+
getStats(): Promise<ResourceCacheStats>;
|
|
30
|
+
private resolveExpired;
|
|
31
|
+
private probeCacheable;
|
|
32
|
+
private probeAndDownload;
|
|
33
|
+
private getOrCreateDownload;
|
|
34
|
+
private downloadAndStore;
|
|
35
|
+
private evictForWrite;
|
|
36
|
+
private deleteEntry;
|
|
37
|
+
private blobResult;
|
|
38
|
+
private emitEvent;
|
|
39
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ResourceCacheStorage, ResourceCacheStorageKind } from './types';
|
|
2
|
+
export declare class IndexedDbResourceStorage implements ResourceCacheStorage {
|
|
3
|
+
readonly kind: "indexeddb";
|
|
4
|
+
private dbPromise;
|
|
5
|
+
private getDb;
|
|
6
|
+
read(cacheKey: string): Promise<Blob | null>;
|
|
7
|
+
write(cacheKey: string, blob: Blob): Promise<void>;
|
|
8
|
+
delete(cacheKey: string): Promise<void>;
|
|
9
|
+
clear(): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
export declare class OpfsResourceStorage implements ResourceCacheStorage {
|
|
12
|
+
readonly kind: "opfs";
|
|
13
|
+
private directoryPromise;
|
|
14
|
+
private getDirectory;
|
|
15
|
+
ensureReady(): Promise<boolean>;
|
|
16
|
+
read(cacheKey: string): Promise<Blob | null>;
|
|
17
|
+
write(cacheKey: string, blob: Blob): Promise<void>;
|
|
18
|
+
delete(cacheKey: string): Promise<void>;
|
|
19
|
+
clear(): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export declare function createMemoryResourceStorage(kind?: ResourceCacheStorageKind): ResourceCacheStorage;
|
|
22
|
+
export declare function createResourceCacheStorage(options: {
|
|
23
|
+
preferStorage: ResourceCacheStorageKind;
|
|
24
|
+
}): Promise<ResourceCacheStorage>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export type ResourceCacheStorageKind = 'opfs' | 'indexeddb';
|
|
2
|
+
export type ResourceCacheResolveMode = 'prefer-fast-start' | 'prefer-cache-ready';
|
|
3
|
+
export type ResourceCacheStatus = 'hit' | 'miss' | 'bypass' | 'stale-revalidated' | 'fallback';
|
|
4
|
+
export interface ResourceCacheOptions {
|
|
5
|
+
enabled: boolean;
|
|
6
|
+
maxEntryBytes: number;
|
|
7
|
+
maxTotalBytes: number;
|
|
8
|
+
ttlMs: number;
|
|
9
|
+
preferStorage: ResourceCacheStorageKind;
|
|
10
|
+
resolveMode: ResourceCacheResolveMode;
|
|
11
|
+
allowedMimeTypes: string[];
|
|
12
|
+
}
|
|
13
|
+
export type ResourceCacheConfig = boolean | Partial<ResourceCacheOptions>;
|
|
14
|
+
export interface ResolveResourceInput {
|
|
15
|
+
url: string;
|
|
16
|
+
mimeType?: string | null;
|
|
17
|
+
kind?: string | null;
|
|
18
|
+
sourceKey?: string | null;
|
|
19
|
+
}
|
|
20
|
+
export interface ResolvedCachedResource {
|
|
21
|
+
url: string;
|
|
22
|
+
cacheStatus: ResourceCacheStatus;
|
|
23
|
+
sourceUrl: string;
|
|
24
|
+
sizeBytes?: number;
|
|
25
|
+
objectUrl?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface ResourceProbeResult {
|
|
28
|
+
url: string;
|
|
29
|
+
ok: boolean;
|
|
30
|
+
status: number;
|
|
31
|
+
mimeType: string | null;
|
|
32
|
+
sizeBytes: number | null;
|
|
33
|
+
etag: string | null;
|
|
34
|
+
lastModified: string | null;
|
|
35
|
+
acceptRanges: string | null;
|
|
36
|
+
}
|
|
37
|
+
export interface CachedResourceMetadata {
|
|
38
|
+
cacheKey: string;
|
|
39
|
+
sourceUrl: string;
|
|
40
|
+
mimeType: string | null;
|
|
41
|
+
sizeBytes: number;
|
|
42
|
+
etag: string | null;
|
|
43
|
+
lastModified: string | null;
|
|
44
|
+
contentLength: number | null;
|
|
45
|
+
storageKind: ResourceCacheStorageKind;
|
|
46
|
+
createdAt: number;
|
|
47
|
+
updatedAt: number;
|
|
48
|
+
lastAccessedAt: number;
|
|
49
|
+
expiresAt: number;
|
|
50
|
+
}
|
|
51
|
+
export interface ResourceCacheStats {
|
|
52
|
+
entryCount: number;
|
|
53
|
+
totalBytes: number;
|
|
54
|
+
maxTotalBytes: number;
|
|
55
|
+
}
|
|
56
|
+
export interface TimelineResourceCacheStats extends ResourceCacheStats {
|
|
57
|
+
enabled: boolean;
|
|
58
|
+
}
|
|
59
|
+
export interface ResourceCacheStorage {
|
|
60
|
+
readonly kind: ResourceCacheStorageKind;
|
|
61
|
+
read(cacheKey: string): Promise<Blob | null>;
|
|
62
|
+
write(cacheKey: string, blob: Blob): Promise<void>;
|
|
63
|
+
delete(cacheKey: string): Promise<void>;
|
|
64
|
+
clear(): Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
export interface ResourceCacheMetadataStore {
|
|
67
|
+
get(cacheKey: string): Promise<CachedResourceMetadata | null>;
|
|
68
|
+
put(metadata: CachedResourceMetadata): Promise<void>;
|
|
69
|
+
delete(cacheKey: string): Promise<void>;
|
|
70
|
+
clear(): Promise<void>;
|
|
71
|
+
list(): Promise<CachedResourceMetadata[]>;
|
|
72
|
+
}
|
|
73
|
+
export interface ResourceCacheHttpClient {
|
|
74
|
+
probe(url: string): Promise<ResourceProbeResult>;
|
|
75
|
+
download(url: string): Promise<Blob>;
|
|
76
|
+
}
|
|
77
|
+
export interface ObjectUrlAdapter {
|
|
78
|
+
createObjectURL(blob: Blob): string;
|
|
79
|
+
revokeObjectURL(url: string): void;
|
|
80
|
+
}
|
|
81
|
+
export declare const RESOURCE_CACHE_DEFAULT_MAX_ENTRY_BYTES: number;
|
|
82
|
+
export declare const RESOURCE_CACHE_DEFAULT_MAX_TOTAL_BYTES: number;
|
|
83
|
+
export declare const RESOURCE_CACHE_DEFAULT_TTL_MS: number;
|
|
84
|
+
export declare const RESOURCE_CACHE_DEFAULT_ALLOWED_MIME_TYPES: string[];
|
|
85
|
+
export declare const RESOURCE_CACHE_DEFAULT_OPTIONS: ResourceCacheOptions;
|