@meframe/core 0.0.40 → 0.0.41

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.
Files changed (47) hide show
  1. package/dist/cache/CacheManager.d.ts +1 -0
  2. package/dist/cache/CacheManager.d.ts.map +1 -1
  3. package/dist/cache/CacheManager.js +2 -1
  4. package/dist/cache/CacheManager.js.map +1 -1
  5. package/dist/cache/resource/MP4IndexCache.d.ts +4 -0
  6. package/dist/cache/resource/MP4IndexCache.d.ts.map +1 -1
  7. package/dist/cache/resource/MP4IndexCache.js +6 -0
  8. package/dist/cache/resource/MP4IndexCache.js.map +1 -1
  9. package/dist/cache/resource/ResourceCache.d.ts +3 -8
  10. package/dist/cache/resource/ResourceCache.d.ts.map +1 -1
  11. package/dist/cache/resource/ResourceCache.js +26 -11
  12. package/dist/cache/resource/ResourceCache.js.map +1 -1
  13. package/dist/cache/storage/opfs/OPFSManager.d.ts +28 -4
  14. package/dist/cache/storage/opfs/OPFSManager.d.ts.map +1 -1
  15. package/dist/cache/storage/opfs/OPFSManager.js +110 -4
  16. package/dist/cache/storage/opfs/OPFSManager.js.map +1 -1
  17. package/dist/cache/storage/opfs/types.d.ts +5 -0
  18. package/dist/cache/storage/opfs/types.d.ts.map +1 -1
  19. package/dist/config/defaults.js +1 -1
  20. package/dist/config/defaults.js.map +1 -1
  21. package/dist/orchestrator/GlobalAudioSession.d.ts +5 -0
  22. package/dist/orchestrator/GlobalAudioSession.d.ts.map +1 -1
  23. package/dist/orchestrator/GlobalAudioSession.js +45 -57
  24. package/dist/orchestrator/GlobalAudioSession.js.map +1 -1
  25. package/dist/orchestrator/Orchestrator.d.ts.map +1 -1
  26. package/dist/orchestrator/Orchestrator.js +2 -1
  27. package/dist/orchestrator/Orchestrator.js.map +1 -1
  28. package/dist/stages/compose/OfflineAudioMixer.d.ts.map +1 -1
  29. package/dist/stages/compose/OfflineAudioMixer.js +3 -1
  30. package/dist/stages/compose/OfflineAudioMixer.js.map +1 -1
  31. package/dist/stages/demux/MP4IndexParser.d.ts +1 -0
  32. package/dist/stages/demux/MP4IndexParser.d.ts.map +1 -1
  33. package/dist/stages/demux/MP4IndexParser.js +20 -10
  34. package/dist/stages/demux/MP4IndexParser.js.map +1 -1
  35. package/dist/stages/load/ResourceLoader.d.ts +3 -1
  36. package/dist/stages/load/ResourceLoader.d.ts.map +1 -1
  37. package/dist/stages/load/ResourceLoader.js +45 -4
  38. package/dist/stages/load/ResourceLoader.js.map +1 -1
  39. package/dist/stages/load/TaskManager.d.ts +7 -1
  40. package/dist/stages/load/TaskManager.d.ts.map +1 -1
  41. package/dist/stages/load/TaskManager.js +40 -2
  42. package/dist/stages/load/TaskManager.js.map +1 -1
  43. package/dist/utils/errors.d.ts +27 -0
  44. package/dist/utils/errors.d.ts.map +1 -1
  45. package/dist/utils/errors.js +32 -0
  46. package/dist/utils/errors.js.map +1 -1
  47. package/package.json +1 -1
@@ -7,6 +7,7 @@ import { Resource } from '../../model';
7
7
  export declare class TaskManager {
8
8
  activeTasks: Map<string, LoadTask>;
9
9
  taskQueue: LoadTask[];
10
+ private pausedPreloadTasks;
10
11
  private concurrentCount;
11
12
  private maxConcurrent;
12
13
  constructor(maxConcurrent?: number);
@@ -52,9 +53,14 @@ export declare class TaskManager {
52
53
  get canProcess(): boolean;
53
54
  /**
54
55
  * Pause all preload tasks (when active load starts)
55
- * Removes preload tasks from queue to let active loads proceed
56
+ * Moves preload tasks to paused queue instead of discarding them
56
57
  */
57
58
  pausePreloadTasks(): void;
59
+ /**
60
+ * Resume preload tasks when no active normal tasks
61
+ * Called automatically after task completion
62
+ */
63
+ resumePreloadTasks(): void;
58
64
  /**
59
65
  * Clear all tasks
60
66
  */
@@ -1 +1 @@
1
- {"version":3,"file":"TaskManager.d.ts","sourceRoot":"","sources":["../../../src/stages/load/TaskManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;GAEG;AACH,qBAAa,WAAW;IACtB,WAAW,wBAA+B;IAC1C,SAAS,EAAE,QAAQ,EAAE,CAAM;IAC3B,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,aAAa,CAAS;gBAElB,aAAa,GAAE,MAAU;IAIrC;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAI1C;;OAEG;IACH,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO;IAYxE;;OAEG;IACH,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS;IAM7D;;OAEG;IACH,OAAO,CACL,QAAQ,EAAE,QAAQ,EAClB,SAAS,GAAE,OAAe,EAC1B,SAAS,CAAC,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf,QAAQ;IA8BX;;OAEG;IACH,WAAW,IAAI,QAAQ,GAAG,IAAI;IAQ9B;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI;IAKlC;;OAEG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI;IAerD;;OAEG;IACH,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAkBvC;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIvD;;OAEG;IACH,IAAI,UAAU,IAAI,OAAO,CAExB;IAED;;;OAGG;IACH,iBAAiB,IAAI,IAAI;IAQzB;;OAEG;IACH,KAAK,IAAI,IAAI;CAUd"}
1
+ {"version":3,"file":"TaskManager.d.ts","sourceRoot":"","sources":["../../../src/stages/load/TaskManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;GAEG;AACH,qBAAa,WAAW;IACtB,WAAW,wBAA+B;IAC1C,SAAS,EAAE,QAAQ,EAAE,CAAM;IAC3B,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,aAAa,CAAS;gBAElB,aAAa,GAAE,MAAU;IAIrC;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAI1C;;OAEG;IACH,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO;IAYxE;;OAEG;IACH,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS;IAM7D;;OAEG;IACH,OAAO,CACL,QAAQ,EAAE,QAAQ,EAClB,SAAS,GAAE,OAAe,EAC1B,SAAS,CAAC,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf,QAAQ;IA8BX;;OAEG;IACH,WAAW,IAAI,QAAQ,GAAG,IAAI;IAQ9B;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI;IAKlC;;OAEG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI;IAkBrD;;OAEG;IACH,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAkBvC;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIvD;;OAEG;IACH,IAAI,UAAU,IAAI,OAAO,CAExB;IAED;;;OAGG;IACH,iBAAiB,IAAI,IAAI;IAmBzB;;;OAGG;IACH,kBAAkB,IAAI,IAAI;IA2B1B;;OAEG;IACH,KAAK,IAAI,IAAI;CAWd"}
@@ -1,6 +1,7 @@
1
1
  class TaskManager {
2
2
  activeTasks = /* @__PURE__ */ new Map();
3
3
  taskQueue = [];
4
+ pausedPreloadTasks = [];
4
5
  concurrentCount = 0;
5
6
  maxConcurrent;
6
7
  constructor(maxConcurrent = 3) {
@@ -87,6 +88,7 @@ class TaskManager {
87
88
  this.activeTasks.delete(resourceId);
88
89
  this.concurrentCount--;
89
90
  }
91
+ this.resumePreloadTasks();
90
92
  }
91
93
  /**
92
94
  * Cancel a task
@@ -119,10 +121,45 @@ class TaskManager {
119
121
  }
120
122
  /**
121
123
  * Pause all preload tasks (when active load starts)
122
- * Removes preload tasks from queue to let active loads proceed
124
+ * Moves preload tasks to paused queue instead of discarding them
123
125
  */
124
126
  pausePreloadTasks() {
125
- this.taskQueue = this.taskQueue.filter((t) => !t.isPreload);
127
+ const normalTasks = [];
128
+ const pausedIds = new Set(this.pausedPreloadTasks.map((t) => t.resourceId));
129
+ for (const task of this.taskQueue) {
130
+ if (task.isPreload) {
131
+ if (!pausedIds.has(task.resourceId)) {
132
+ this.pausedPreloadTasks.push(task);
133
+ pausedIds.add(task.resourceId);
134
+ }
135
+ } else {
136
+ normalTasks.push(task);
137
+ }
138
+ }
139
+ this.taskQueue = normalTasks;
140
+ }
141
+ /**
142
+ * Resume preload tasks when no active normal tasks
143
+ * Called automatically after task completion
144
+ */
145
+ resumePreloadTasks() {
146
+ if (this.pausedPreloadTasks.length === 0) return;
147
+ for (const task of this.activeTasks.values()) {
148
+ if (!task.isPreload) return;
149
+ }
150
+ const skipIds = /* @__PURE__ */ new Set();
151
+ for (const task of this.taskQueue) {
152
+ skipIds.add(task.resourceId);
153
+ }
154
+ for (const id of this.activeTasks.keys()) {
155
+ skipIds.add(id);
156
+ }
157
+ for (const task of this.pausedPreloadTasks) {
158
+ if (!skipIds.has(task.resourceId)) {
159
+ this.taskQueue.push(task);
160
+ }
161
+ }
162
+ this.pausedPreloadTasks = [];
126
163
  }
127
164
  /**
128
165
  * Clear all tasks
@@ -133,6 +170,7 @@ class TaskManager {
133
170
  }
134
171
  this.activeTasks.clear();
135
172
  this.taskQueue = [];
173
+ this.pausedPreloadTasks = [];
136
174
  this.concurrentCount = 0;
137
175
  }
138
176
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TaskManager.js","sources":["../../../src/stages/load/TaskManager.ts"],"sourcesContent":["import type { LoadTask } from './types';\nimport type { Resource } from '../../model';\n\n/**\n * Manages resource loading tasks and queue\n */\nexport class TaskManager {\n activeTasks = new Map<string, LoadTask>();\n taskQueue: LoadTask[] = [];\n private concurrentCount = 0;\n private maxConcurrent: number;\n\n constructor(maxConcurrent: number = 3) {\n this.maxConcurrent = maxConcurrent;\n }\n\n /**\n * Check if a resource is already being loaded\n */\n hasActiveTask(resourceId: string): boolean {\n return this.activeTasks.has(resourceId);\n }\n\n /**\n * Check if a resource is being loaded for a specific session\n */\n hasActiveTaskForSession(resourceId: string, sessionId?: string): boolean {\n const task = this.activeTasks.get(resourceId);\n if (!task) return false;\n\n // If sessionId is provided, check if it matches\n if (sessionId !== undefined) {\n return task.sessionId === sessionId;\n }\n\n return true;\n }\n\n /**\n * Get task promise (task must already exist)\n */\n getTaskPromise(resourceId: string): Promise<void> | undefined {\n const task =\n this.activeTasks.get(resourceId) || this.taskQueue.find((t) => t.resourceId === resourceId);\n return task?.promise;\n }\n\n /**\n * Create and enqueue a new task\n */\n enqueue(\n resource: Resource,\n isPreload: boolean = false,\n sessionId?: string,\n clipId?: string,\n trackId?: string\n ): LoadTask {\n // Create promise for this task\n let resolve: (() => void) | undefined;\n let reject: ((error: Error) => void) | undefined;\n const promise = new Promise<void>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n\n const task: LoadTask = {\n resourceId: resource.id,\n resource,\n bytesLoaded: 0,\n totalBytes: 0,\n startTime: Date.now(),\n isPreload,\n sessionId,\n clipId,\n trackId,\n promise,\n resolve,\n reject,\n };\n\n // Add to end of queue (no priority-based ordering)\n this.taskQueue.push(task);\n\n return task;\n }\n\n /**\n * Get next task from queue if under concurrent limit\n */\n getNextTask(): LoadTask | null {\n if (this.taskQueue.length === 0 || this.concurrentCount >= this.maxConcurrent) {\n return null;\n }\n\n return this.taskQueue.shift() || null;\n }\n\n /**\n * Mark task as active\n */\n activateTask(task: LoadTask): void {\n this.activeTasks.set(task.resourceId, task);\n this.concurrentCount++;\n }\n\n /**\n * Mark task as completed\n */\n completeTask(resourceId: string, error?: Error): void {\n const task = this.activeTasks.get(resourceId);\n if (task) {\n // Resolve or reject task's promise\n if (error) {\n task.reject?.(error);\n } else {\n task.resolve?.();\n }\n\n this.activeTasks.delete(resourceId);\n this.concurrentCount--;\n }\n }\n\n /**\n * Cancel a task\n */\n cancelTask(resourceId: string): boolean {\n const task = this.activeTasks.get(resourceId);\n if (task) {\n task.controller?.abort();\n this.completeTask(resourceId);\n return true;\n }\n\n // Also remove from queue\n const index = this.taskQueue.findIndex((t) => t.resourceId === resourceId);\n if (index >= 0) {\n this.taskQueue.splice(index, 1);\n return true;\n }\n\n return false;\n }\n\n /**\n * Find an active task\n */\n getActiveTask(resourceId: string): LoadTask | undefined {\n return this.activeTasks.get(resourceId);\n }\n\n /**\n * Check if can process more tasks\n */\n get canProcess(): boolean {\n return this.concurrentCount < this.maxConcurrent;\n }\n\n /**\n * Pause all preload tasks (when active load starts)\n * Removes preload tasks from queue to let active loads proceed\n */\n pausePreloadTasks(): void {\n // Remove preload tasks from queue\n this.taskQueue = this.taskQueue.filter((t) => !t.isPreload);\n\n // Note: We don't abort active preload tasks to avoid wasting downloaded data\n // They will complete naturally but new preload tasks won't be started\n }\n\n /**\n * Clear all tasks\n */\n clear(): void {\n // Cancel all active tasks\n for (const task of this.activeTasks.values()) {\n task.controller?.abort();\n }\n\n this.activeTasks.clear();\n this.taskQueue = [];\n this.concurrentCount = 0;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TaskManager.js","sources":["../../../src/stages/load/TaskManager.ts"],"sourcesContent":["import type { LoadTask } from './types';\nimport type { Resource } from '../../model';\n\n/**\n * Manages resource loading tasks and queue\n */\nexport class TaskManager {\n activeTasks = new Map<string, LoadTask>();\n taskQueue: LoadTask[] = [];\n private pausedPreloadTasks: LoadTask[] = [];\n private concurrentCount = 0;\n private maxConcurrent: number;\n\n constructor(maxConcurrent: number = 3) {\n this.maxConcurrent = maxConcurrent;\n }\n\n /**\n * Check if a resource is already being loaded\n */\n hasActiveTask(resourceId: string): boolean {\n return this.activeTasks.has(resourceId);\n }\n\n /**\n * Check if a resource is being loaded for a specific session\n */\n hasActiveTaskForSession(resourceId: string, sessionId?: string): boolean {\n const task = this.activeTasks.get(resourceId);\n if (!task) return false;\n\n // If sessionId is provided, check if it matches\n if (sessionId !== undefined) {\n return task.sessionId === sessionId;\n }\n\n return true;\n }\n\n /**\n * Get task promise (task must already exist)\n */\n getTaskPromise(resourceId: string): Promise<void> | undefined {\n const task =\n this.activeTasks.get(resourceId) || this.taskQueue.find((t) => t.resourceId === resourceId);\n return task?.promise;\n }\n\n /**\n * Create and enqueue a new task\n */\n enqueue(\n resource: Resource,\n isPreload: boolean = false,\n sessionId?: string,\n clipId?: string,\n trackId?: string\n ): LoadTask {\n // Create promise for this task\n let resolve: (() => void) | undefined;\n let reject: ((error: Error) => void) | undefined;\n const promise = new Promise<void>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n\n const task: LoadTask = {\n resourceId: resource.id,\n resource,\n bytesLoaded: 0,\n totalBytes: 0,\n startTime: Date.now(),\n isPreload,\n sessionId,\n clipId,\n trackId,\n promise,\n resolve,\n reject,\n };\n\n // Add to end of queue (no priority-based ordering)\n this.taskQueue.push(task);\n\n return task;\n }\n\n /**\n * Get next task from queue if under concurrent limit\n */\n getNextTask(): LoadTask | null {\n if (this.taskQueue.length === 0 || this.concurrentCount >= this.maxConcurrent) {\n return null;\n }\n\n return this.taskQueue.shift() || null;\n }\n\n /**\n * Mark task as active\n */\n activateTask(task: LoadTask): void {\n this.activeTasks.set(task.resourceId, task);\n this.concurrentCount++;\n }\n\n /**\n * Mark task as completed\n */\n completeTask(resourceId: string, error?: Error): void {\n const task = this.activeTasks.get(resourceId);\n if (task) {\n // Resolve or reject task's promise\n if (error) {\n task.reject?.(error);\n } else {\n task.resolve?.();\n }\n\n this.activeTasks.delete(resourceId);\n this.concurrentCount--;\n }\n\n // Try to resume preload tasks after completion\n this.resumePreloadTasks();\n }\n\n /**\n * Cancel a task\n */\n cancelTask(resourceId: string): boolean {\n const task = this.activeTasks.get(resourceId);\n if (task) {\n task.controller?.abort();\n this.completeTask(resourceId);\n return true;\n }\n\n // Also remove from queue\n const index = this.taskQueue.findIndex((t) => t.resourceId === resourceId);\n if (index >= 0) {\n this.taskQueue.splice(index, 1);\n return true;\n }\n\n return false;\n }\n\n /**\n * Find an active task\n */\n getActiveTask(resourceId: string): LoadTask | undefined {\n return this.activeTasks.get(resourceId);\n }\n\n /**\n * Check if can process more tasks\n */\n get canProcess(): boolean {\n return this.concurrentCount < this.maxConcurrent;\n }\n\n /**\n * Pause all preload tasks (when active load starts)\n * Moves preload tasks to paused queue instead of discarding them\n */\n pausePreloadTasks(): void {\n // Single-pass: split queue and deduplicate\n const normalTasks: LoadTask[] = [];\n const pausedIds = new Set(this.pausedPreloadTasks.map((t) => t.resourceId));\n\n for (const task of this.taskQueue) {\n if (task.isPreload) {\n if (!pausedIds.has(task.resourceId)) {\n this.pausedPreloadTasks.push(task);\n pausedIds.add(task.resourceId);\n }\n } else {\n normalTasks.push(task);\n }\n }\n\n this.taskQueue = normalTasks;\n }\n\n /**\n * Resume preload tasks when no active normal tasks\n * Called automatically after task completion\n */\n resumePreloadTasks(): void {\n if (this.pausedPreloadTasks.length === 0) return;\n\n // Check if any active normal tasks exist\n for (const task of this.activeTasks.values()) {\n if (!task.isPreload) return;\n }\n\n // Build skip set (already in queue or active)\n const skipIds = new Set<string>();\n for (const task of this.taskQueue) {\n skipIds.add(task.resourceId);\n }\n for (const id of this.activeTasks.keys()) {\n skipIds.add(id);\n }\n\n // Restore valid tasks\n for (const task of this.pausedPreloadTasks) {\n if (!skipIds.has(task.resourceId)) {\n this.taskQueue.push(task);\n }\n }\n\n this.pausedPreloadTasks = [];\n }\n\n /**\n * Clear all tasks\n */\n clear(): void {\n // Cancel all active tasks\n for (const task of this.activeTasks.values()) {\n task.controller?.abort();\n }\n\n this.activeTasks.clear();\n this.taskQueue = [];\n this.pausedPreloadTasks = [];\n this.concurrentCount = 0;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -9,4 +9,31 @@ export declare class WaiterReplacedError extends Error {
9
9
  readonly clipId: string;
10
10
  constructor(clipId: string);
11
11
  }
12
+ /**
13
+ * Error thrown when reading an empty or incomplete OPFS file
14
+ * Usually indicates a race condition between write and read operations
15
+ */
16
+ export declare class EmptyStreamError extends Error {
17
+ readonly resourceId: string;
18
+ readonly fileOffset: number;
19
+ constructor(resourceId: string, fileOffset: number);
20
+ }
21
+ /**
22
+ * Error thrown when a cached resource file is corrupted or incomplete
23
+ */
24
+ export declare class ResourceCorruptedError extends Error {
25
+ readonly resourceId: string;
26
+ readonly reason: string;
27
+ constructor(resourceId: string, reason: string);
28
+ }
29
+ /**
30
+ * Error thrown when OPFS quota is exceeded
31
+ * Used for project-level LRU eviction coordination
32
+ */
33
+ export declare class OPFSQuotaExceededError extends Error {
34
+ readonly projectId: string;
35
+ readonly prefix: string;
36
+ readonly retryable: boolean;
37
+ constructor(projectId: string, prefix: string, retryable: boolean);
38
+ }
12
39
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;aAChB,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM;CAI3C"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;aAChB,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM;CAI3C;AAED;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;aAEvB,UAAU,EAAE,MAAM;aAClB,UAAU,EAAE,MAAM;gBADlB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM;CAQrC;AAED;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;aAE7B,UAAU,EAAE,MAAM;aAClB,MAAM,EAAE,MAAM;gBADd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM;CAKjC;AAED;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;aAE7B,SAAS,EAAE,MAAM;aACjB,MAAM,EAAE,MAAM;aACd,SAAS,EAAE,OAAO;gBAFlB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,OAAO;CAQrC"}
@@ -5,7 +5,39 @@ class WaiterReplacedError extends Error {
5
5
  this.name = "WaiterReplacedError";
6
6
  }
7
7
  }
8
+ class EmptyStreamError extends Error {
9
+ constructor(resourceId, fileOffset) {
10
+ super(
11
+ `Empty stream received for resource ${resourceId}. File offset: ${fileOffset}. This indicates the file is being written or is corrupted.`
12
+ );
13
+ this.resourceId = resourceId;
14
+ this.fileOffset = fileOffset;
15
+ this.name = "EmptyStreamError";
16
+ }
17
+ }
18
+ class ResourceCorruptedError extends Error {
19
+ constructor(resourceId, reason) {
20
+ super(`Resource ${resourceId} is corrupted: ${reason}`);
21
+ this.resourceId = resourceId;
22
+ this.reason = reason;
23
+ this.name = "ResourceCorruptedError";
24
+ }
25
+ }
26
+ class OPFSQuotaExceededError extends Error {
27
+ constructor(projectId, prefix, retryable) {
28
+ super(
29
+ `OPFS quota exceeded for ${prefix}-${projectId}. ` + (retryable ? "Old projects evicted, please retry." : "No space available.")
30
+ );
31
+ this.projectId = projectId;
32
+ this.prefix = prefix;
33
+ this.retryable = retryable;
34
+ this.name = "OPFSQuotaExceededError";
35
+ }
36
+ }
8
37
  export {
38
+ EmptyStreamError,
39
+ OPFSQuotaExceededError,
40
+ ResourceCorruptedError,
9
41
  WaiterReplacedError
10
42
  };
11
43
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sources":["../../src/utils/errors.ts"],"sourcesContent":["/**\n * Custom error types for Meframe\n */\n\n/**\n * Error thrown when a clip ready waiter is replaced by a newer one\n * This happens during rapid seeks and should be ignored by callers\n */\nexport class WaiterReplacedError extends Error {\n constructor(public readonly clipId: string) {\n super(`Waiter for clip ${clipId} was replaced by a newer waiter`);\n this.name = 'WaiterReplacedError';\n }\n}\n"],"names":[],"mappings":"AAQO,MAAM,4BAA4B,MAAM;AAAA,EAC7C,YAA4B,QAAgB;AAC1C,UAAM,mBAAmB,MAAM,iCAAiC;AADtC,SAAA,SAAA;AAE1B,SAAK,OAAO;AAAA,EACd;AACF;"}
1
+ {"version":3,"file":"errors.js","sources":["../../src/utils/errors.ts"],"sourcesContent":["/**\n * Custom error types for Meframe\n */\n\n/**\n * Error thrown when a clip ready waiter is replaced by a newer one\n * This happens during rapid seeks and should be ignored by callers\n */\nexport class WaiterReplacedError extends Error {\n constructor(public readonly clipId: string) {\n super(`Waiter for clip ${clipId} was replaced by a newer waiter`);\n this.name = 'WaiterReplacedError';\n }\n}\n\n/**\n * Error thrown when reading an empty or incomplete OPFS file\n * Usually indicates a race condition between write and read operations\n */\nexport class EmptyStreamError extends Error {\n constructor(\n public readonly resourceId: string,\n public readonly fileOffset: number\n ) {\n super(\n `Empty stream received for resource ${resourceId}. ` +\n `File offset: ${fileOffset}. This indicates the file is being written or is corrupted.`\n );\n this.name = 'EmptyStreamError';\n }\n}\n\n/**\n * Error thrown when a cached resource file is corrupted or incomplete\n */\nexport class ResourceCorruptedError extends Error {\n constructor(\n public readonly resourceId: string,\n public readonly reason: string\n ) {\n super(`Resource ${resourceId} is corrupted: ${reason}`);\n this.name = 'ResourceCorruptedError';\n }\n}\n\n/**\n * Error thrown when OPFS quota is exceeded\n * Used for project-level LRU eviction coordination\n */\nexport class OPFSQuotaExceededError extends Error {\n constructor(\n public readonly projectId: string,\n public readonly prefix: string,\n public readonly retryable: boolean\n ) {\n super(\n `OPFS quota exceeded for ${prefix}-${projectId}. ` +\n (retryable ? 'Old projects evicted, please retry.' : 'No space available.')\n );\n this.name = 'OPFSQuotaExceededError';\n }\n}\n"],"names":[],"mappings":"AAQO,MAAM,4BAA4B,MAAM;AAAA,EAC7C,YAA4B,QAAgB;AAC1C,UAAM,mBAAmB,MAAM,iCAAiC;AADtC,SAAA,SAAA;AAE1B,SAAK,OAAO;AAAA,EACd;AACF;AAMO,MAAM,yBAAyB,MAAM;AAAA,EAC1C,YACkB,YACA,YAChB;AACA;AAAA,MACE,sCAAsC,UAAU,kBAC9B,UAAU;AAAA,IAAA;AALd,SAAA,aAAA;AACA,SAAA,aAAA;AAMhB,SAAK,OAAO;AAAA,EACd;AACF;AAKO,MAAM,+BAA+B,MAAM;AAAA,EAChD,YACkB,YACA,QAChB;AACA,UAAM,YAAY,UAAU,kBAAkB,MAAM,EAAE;AAHtC,SAAA,aAAA;AACA,SAAA,SAAA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;AAMO,MAAM,+BAA+B,MAAM;AAAA,EAChD,YACkB,WACA,QACA,WAChB;AACA;AAAA,MACE,2BAA2B,MAAM,IAAI,SAAS,QAC3C,YAAY,wCAAwC;AAAA,IAAA;AANzC,SAAA,YAAA;AACA,SAAA,SAAA;AACA,SAAA,YAAA;AAMhB,SAAK,OAAO;AAAA,EACd;AACF;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meframe/core",
3
- "version": "0.0.40",
3
+ "version": "0.0.41",
4
4
  "description": "Next generation media processing framework based on WebCodecs",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",