@xiboplayer/cache 0.1.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/src/index.js ADDED
@@ -0,0 +1,4 @@
1
+ // @xiboplayer/cache - Offline caching and downloads
2
+ export { CacheManager, cacheManager } from './cache.js';
3
+ export { CacheProxy } from './cache-proxy.js';
4
+ export { DownloadManager } from './download-manager.js';
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Test Utilities for Xibo Player Cache package
3
+ * Re-exports common test helpers.
4
+ */
5
+
6
+ import { vi } from 'vitest';
7
+
8
+ /**
9
+ * Mock fetch with controllable responses
10
+ */
11
+ export function mockFetch(responses = {}) {
12
+ global.fetch = vi.fn((url, options) => {
13
+ const method = options?.method || 'GET';
14
+ const key = `${method} ${url}`;
15
+ const response = responses[key] || responses[url];
16
+
17
+ if (!response) {
18
+ return Promise.resolve({
19
+ ok: false,
20
+ status: 404,
21
+ statusText: 'Not Found',
22
+ headers: {
23
+ get: () => null
24
+ }
25
+ });
26
+ }
27
+
28
+ return Promise.resolve({
29
+ ok: response.ok !== false,
30
+ status: response.status || 200,
31
+ statusText: response.statusText || 'OK',
32
+ headers: {
33
+ get: (name) => response.headers?.[name] || null
34
+ },
35
+ blob: () => Promise.resolve(response.blob || new Blob()),
36
+ text: () => Promise.resolve(response.text || ''),
37
+ json: () => Promise.resolve(response.json || {}),
38
+ arrayBuffer: () => Promise.resolve(response.arrayBuffer || new ArrayBuffer(0))
39
+ });
40
+ });
41
+
42
+ return global.fetch;
43
+ }
44
+
45
+ /**
46
+ * Mock fetch that supports Range request handling (for chunk download tests)
47
+ * Returns the correct portion of a source blob based on the Range header.
48
+ */
49
+ export function mockChunkedFetch(sourceBlob) {
50
+ global.fetch = vi.fn(async (url, options) => {
51
+ const method = options?.method || 'GET';
52
+
53
+ if (method === 'HEAD') {
54
+ return {
55
+ ok: true,
56
+ status: 200,
57
+ headers: {
58
+ get: (name) => {
59
+ if (name === 'Content-Length') return String(sourceBlob.size);
60
+ if (name === 'Content-Type') return sourceBlob.type || 'application/octet-stream';
61
+ return null;
62
+ }
63
+ }
64
+ };
65
+ }
66
+
67
+ // Handle Range requests
68
+ const rangeHeader = options?.headers?.Range;
69
+ if (rangeHeader) {
70
+ const match = rangeHeader.match(/bytes=(\d+)-(\d+)/);
71
+ if (match) {
72
+ const start = parseInt(match[1]);
73
+ const end = parseInt(match[2]);
74
+ const chunk = sourceBlob.slice(start, end + 1);
75
+ return {
76
+ ok: true,
77
+ status: 206,
78
+ headers: {
79
+ get: (name) => {
80
+ if (name === 'Content-Length') return String(chunk.size);
81
+ if (name === 'Content-Range') return `bytes ${start}-${end}/${sourceBlob.size}`;
82
+ return null;
83
+ }
84
+ },
85
+ blob: () => Promise.resolve(chunk)
86
+ };
87
+ }
88
+ }
89
+
90
+ // Full file download
91
+ return {
92
+ ok: true,
93
+ status: 200,
94
+ headers: { get: () => null },
95
+ blob: () => Promise.resolve(sourceBlob)
96
+ };
97
+ });
98
+
99
+ return global.fetch;
100
+ }
101
+
102
+ /**
103
+ * Create test blob of specified size
104
+ */
105
+ export function createTestBlob(size = 1024, type = 'application/octet-stream') {
106
+ const buffer = new ArrayBuffer(size);
107
+ // Fill with non-zero data so chunks are distinguishable
108
+ const view = new Uint8Array(buffer);
109
+ for (let i = 0; i < size; i++) {
110
+ view[i] = i % 256;
111
+ }
112
+ return new Blob([buffer], { type });
113
+ }
114
+
115
+ /**
116
+ * Wait for condition to be true
117
+ */
118
+ export async function waitFor(condition, timeout = 5000) {
119
+ const start = Date.now();
120
+ while (!condition()) {
121
+ if (Date.now() - start > timeout) {
122
+ throw new Error('waitFor timeout');
123
+ }
124
+ await new Promise(resolve => setTimeout(resolve, 50));
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Create a spy
130
+ */
131
+ export function createSpy() {
132
+ return vi.fn();
133
+ }