@glivion/square-screen-js-sdk 0.1.0 → 1.0.1
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/index.cjs +874 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +522 -0
- package/dist/index.d.mts +522 -0
- package/dist/index.mjs +870 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +8 -1
- package/.github/workflows/build-js-sdk.yml +0 -70
- package/eslint.config.js +0 -3
- package/examples/react-app/README.md +0 -73
- package/examples/react-app/eslint.config.js +0 -22
- package/examples/react-app/index.html +0 -13
- package/examples/react-app/package-lock.json +0 -2239
- package/examples/react-app/package.json +0 -31
- package/examples/react-app/public/favicon.svg +0 -1
- package/examples/react-app/public/icons.svg +0 -24
- package/examples/react-app/src/App.css +0 -184
- package/examples/react-app/src/App.tsx +0 -157
- package/examples/react-app/src/EmergencyTicker.tsx +0 -25
- package/examples/react-app/src/HeadlessExample.tsx +0 -66
- package/examples/react-app/src/RendererExample.tsx +0 -70
- package/examples/react-app/src/assets/hero.png +0 -0
- package/examples/react-app/src/assets/react.svg +0 -1
- package/examples/react-app/src/assets/vite.svg +0 -1
- package/examples/react-app/src/index.css +0 -183
- package/examples/react-app/src/main.tsx +0 -10
- package/examples/react-app/src/mockNetworkDataSource.ts +0 -116
- package/examples/react-app/src/usePlayer.ts +0 -71
- package/examples/react-app/tsconfig.app.json +0 -25
- package/examples/react-app/tsconfig.json +0 -7
- package/examples/react-app/tsconfig.node.json +0 -24
- package/examples/react-app/vite.config.ts +0 -7
- package/examples/react-app/yarn.lock +0 -1089
- package/src/__tests__/cache/SquareScreenCache.test.ts +0 -375
- package/src/__tests__/network/NetworkClient.test.ts +0 -217
- package/src/__tests__/network/mappers.test.ts +0 -163
- package/src/__tests__/player/SquareScreenPlayer.test.ts +0 -840
- package/src/cache/SquareScreenCache.ts +0 -154
- package/src/constants.ts +0 -9
- package/src/core/types.ts +0 -251
- package/src/env.d.ts +0 -4
- package/src/index.ts +0 -34
- package/src/network/NetworkClient.ts +0 -234
- package/src/network/apiTypes.ts +0 -89
- package/src/network/mappers.ts +0 -106
- package/src/player/SquareScreenPlayer.ts +0 -414
- package/src/renderer/SquareScreenRenderer.ts +0 -282
- package/tsconfig.json +0 -12
- package/tsdown.config.ts +0 -23
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
//#region src/constants.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Production root URL for the SquareScreen REST API.
|
|
4
|
+
*
|
|
5
|
+
* {@link SquareScreenPlayer} uses this for all network requests. Integrators cannot
|
|
6
|
+
* override it via player configuration; supply a custom {@link NetworkDataSource}
|
|
7
|
+
* only if you must talk to a different host (e.g. tests or a private gateway).
|
|
8
|
+
*/
|
|
9
|
+
declare const SQUARESCREEN_API_BASE_URL = "https://square-screen-api-development-f7zuxa.laravel.cloud/api/v1";
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/core/types.d.ts
|
|
12
|
+
/** The type of media content in a playlist item. Matches the string values returned by the API. */
|
|
13
|
+
type MediaType = "image" | "video";
|
|
14
|
+
/** The transition animation to apply when moving between playlist items. */
|
|
15
|
+
type TransitionType = "fade" | "slide" | "none";
|
|
16
|
+
/** The current connectivity and sync state of the device. */
|
|
17
|
+
type DeviceStatus = "connecting" | "online" | "offline" | "syncing";
|
|
18
|
+
/** Playback strategy metadata returned alongside a playlist. */
|
|
19
|
+
interface PlaybackStrategy {
|
|
20
|
+
loop: boolean;
|
|
21
|
+
shuffle: boolean;
|
|
22
|
+
/** Number of upcoming items to pre-download. 0 means no preloading. */
|
|
23
|
+
preloadCount?: number;
|
|
24
|
+
}
|
|
25
|
+
/** Schedule metadata associated with a playlist. */
|
|
26
|
+
interface Schedule {
|
|
27
|
+
uuid: string;
|
|
28
|
+
name: string;
|
|
29
|
+
/** Higher value means higher priority when multiple schedules overlap. */
|
|
30
|
+
priority: number;
|
|
31
|
+
}
|
|
32
|
+
/** Metadata about the playlist container returned by the API. */
|
|
33
|
+
interface PlaylistMeta {
|
|
34
|
+
uuid: string;
|
|
35
|
+
name: string;
|
|
36
|
+
}
|
|
37
|
+
/** A playlist returned from the API, representing everything the device should display. */
|
|
38
|
+
interface Playlist {
|
|
39
|
+
uuid: string;
|
|
40
|
+
items: PlaylistItem[];
|
|
41
|
+
/** Present when the backend includes scheduling/playback hints. Not always populated. */
|
|
42
|
+
strategy?: PlaybackStrategy;
|
|
43
|
+
/** Metadata about the active schedule driving this playlist. */
|
|
44
|
+
schedule?: Schedule;
|
|
45
|
+
/** Metadata about the playlist container itself. */
|
|
46
|
+
playlistMeta?: PlaylistMeta;
|
|
47
|
+
/** Unix timestamp (ms) recording when this playlist was stored in the local cache. */
|
|
48
|
+
cachedAt: number;
|
|
49
|
+
}
|
|
50
|
+
/** A single piece of content within a playlist. */
|
|
51
|
+
interface PlaylistItem {
|
|
52
|
+
uuid: string;
|
|
53
|
+
name: string;
|
|
54
|
+
type: MediaType;
|
|
55
|
+
/** URL of the media file to display. */
|
|
56
|
+
url: string;
|
|
57
|
+
/** How long to display this item, in seconds. */
|
|
58
|
+
duration: number;
|
|
59
|
+
/** Animation to use when transitioning away from this item. Defaults to none if absent. */
|
|
60
|
+
transition?: TransitionType;
|
|
61
|
+
/** Native width of the media in pixels. */
|
|
62
|
+
width?: number;
|
|
63
|
+
/** Native height of the media in pixels. */
|
|
64
|
+
height?: number;
|
|
65
|
+
/** Human-readable title. Present on some item types (e.g. video). */
|
|
66
|
+
title?: string;
|
|
67
|
+
/** Thumbnail URL for preloading previews. */
|
|
68
|
+
thumbnail?: string;
|
|
69
|
+
}
|
|
70
|
+
/** An active emergency broadcast targeting this device. */
|
|
71
|
+
interface EmergencyAlert {
|
|
72
|
+
/** Server-assigned integer ID. */
|
|
73
|
+
id: number;
|
|
74
|
+
uuid: string;
|
|
75
|
+
/** ID of the company that issued the broadcast. */
|
|
76
|
+
companyId: number;
|
|
77
|
+
title: string;
|
|
78
|
+
message: string;
|
|
79
|
+
/** Hex color string for the alert background, e.g. "#FF0000". */
|
|
80
|
+
backgroundColor: string;
|
|
81
|
+
/** Hex color string for the alert text, e.g. "#FFFFFF". */
|
|
82
|
+
textColor: string;
|
|
83
|
+
/** The scope this broadcast targets, e.g. "all", "workspace", "group", or "device". */
|
|
84
|
+
targetScope: string;
|
|
85
|
+
/** Whether this broadcast is currently active. */
|
|
86
|
+
isActive: boolean;
|
|
87
|
+
/** ISO 8601 timestamp when the broadcast started. */
|
|
88
|
+
startedAt: string;
|
|
89
|
+
/** ISO 8601 timestamp when the broadcast ended, or undefined if still active. */
|
|
90
|
+
endedAt?: string;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Device health metrics sent to the server on each heartbeat.
|
|
94
|
+
* All hardware metrics are optional — not all browsers expose them.
|
|
95
|
+
*/
|
|
96
|
+
interface HeartbeatPayload {
|
|
97
|
+
cpuUsage?: number;
|
|
98
|
+
memoryUsage?: number;
|
|
99
|
+
diskUsage?: number;
|
|
100
|
+
temperature?: number;
|
|
101
|
+
osVersion?: string;
|
|
102
|
+
/** The version string of this SDK, included on every heartbeat. */
|
|
103
|
+
playerVersion: string;
|
|
104
|
+
}
|
|
105
|
+
/** Acknowledgement returned by the server after a successful heartbeat POST. */
|
|
106
|
+
interface HeartbeatAck {
|
|
107
|
+
received: boolean;
|
|
108
|
+
}
|
|
109
|
+
/** Query parameters for filtering a playlist to video items only. */
|
|
110
|
+
interface VideoPlaylistParams {
|
|
111
|
+
category?: string;
|
|
112
|
+
tags?: string[];
|
|
113
|
+
quality?: string;
|
|
114
|
+
limit?: number;
|
|
115
|
+
}
|
|
116
|
+
/** Query parameters for filtering a playlist to image items only. */
|
|
117
|
+
interface ImagePlaylistParams {
|
|
118
|
+
category?: string;
|
|
119
|
+
tags?: string[];
|
|
120
|
+
limit?: number;
|
|
121
|
+
}
|
|
122
|
+
/** Playback event data sent to the server. */
|
|
123
|
+
interface PlaybackEvent {
|
|
124
|
+
media_uuid: string;
|
|
125
|
+
playlist_uuid: string;
|
|
126
|
+
schedule_uuid: string;
|
|
127
|
+
started_at: string;
|
|
128
|
+
ended_at: string;
|
|
129
|
+
/** Actual number of seconds the item was displayed. */
|
|
130
|
+
duration_seconds: number;
|
|
131
|
+
/** Whether the item played to its full duration without interruption. */
|
|
132
|
+
completed: boolean;
|
|
133
|
+
}
|
|
134
|
+
/** An HTTP-level failure — the request reached the server but returned an error status. */
|
|
135
|
+
interface NetworkError {
|
|
136
|
+
kind: "network";
|
|
137
|
+
code: number;
|
|
138
|
+
message: string;
|
|
139
|
+
}
|
|
140
|
+
/** The device credentials (ID or token) were rejected by the server. */
|
|
141
|
+
interface AuthError {
|
|
142
|
+
kind: "auth";
|
|
143
|
+
message: string;
|
|
144
|
+
}
|
|
145
|
+
/** Reading from or writing to the local cache failed. */
|
|
146
|
+
interface CacheError {
|
|
147
|
+
kind: "cache";
|
|
148
|
+
message: string;
|
|
149
|
+
}
|
|
150
|
+
/** The server response could not be parsed into the expected shape. */
|
|
151
|
+
interface ParseError {
|
|
152
|
+
kind: "parse";
|
|
153
|
+
message: string;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Signals that an emergency broadcast is active.
|
|
157
|
+
* The caller should switch to displaying the EmergencyAlert instead of normal content.
|
|
158
|
+
*/
|
|
159
|
+
interface EmergencyOverrideActive {
|
|
160
|
+
kind: "emergency_override";
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Every error the SDK can produce.
|
|
164
|
+
* Check the `kind` field to identify and handle each case.
|
|
165
|
+
*/
|
|
166
|
+
type SquareScreenError = NetworkError | AuthError | CacheError | ParseError | EmergencyOverrideActive;
|
|
167
|
+
/**
|
|
168
|
+
* The return type for all SDK operations that can fail.
|
|
169
|
+
*
|
|
170
|
+
* Check `result.success` first — TypeScript will then narrow the type
|
|
171
|
+
* so that `result.data` is only accessible on success and `result.error`
|
|
172
|
+
* is only accessible on failure.
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* if (result.success) {
|
|
176
|
+
* console.log(result.data);
|
|
177
|
+
* } else {
|
|
178
|
+
* console.error(result.error.kind);
|
|
179
|
+
* }
|
|
180
|
+
*/
|
|
181
|
+
type SquareScreenResult<T> = {
|
|
182
|
+
success: true;
|
|
183
|
+
data: T;
|
|
184
|
+
} | {
|
|
185
|
+
success: false;
|
|
186
|
+
error: SquareScreenError;
|
|
187
|
+
};
|
|
188
|
+
interface NetworkDataSource {
|
|
189
|
+
fetchPlaylist: () => Promise<SquareScreenResult<Playlist>>;
|
|
190
|
+
fetchVideoPlaylist: (params: VideoPlaylistParams) => Promise<SquareScreenResult<Playlist>>;
|
|
191
|
+
fetchImagePlaylist: (params: ImagePlaylistParams) => Promise<SquareScreenResult<Playlist>>;
|
|
192
|
+
/** Resolves to null when no emergency is active. */
|
|
193
|
+
checkForEmergencyAlert: () => Promise<SquareScreenResult<EmergencyAlert | null>>;
|
|
194
|
+
healthCheck: (payload: HeartbeatPayload) => Promise<SquareScreenResult<HeartbeatAck>>;
|
|
195
|
+
reportPlaybackEvent: (event: PlaybackEvent) => Promise<SquareScreenResult<{
|
|
196
|
+
recorded: boolean;
|
|
197
|
+
}>>;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Abstraction over local storage. The default implementation is `SquareScreenCache`
|
|
201
|
+
* (IndexedDB for playlist metadata + Cache API for media blobs). Pass a custom
|
|
202
|
+
* implementation via `SquareScreenPlayerConfig.cacheProvider` to integrate with
|
|
203
|
+
* an existing storage layer.
|
|
204
|
+
*/
|
|
205
|
+
interface SquareScreenCacheProvider {
|
|
206
|
+
/** Returns the cached playlist, or null if not found / TTL expired. Pass `allowStale` to bypass TTL for offline fallback. */
|
|
207
|
+
getPlaylist(uuid: string, allowStale?: boolean): Promise<Playlist | null>;
|
|
208
|
+
/** Persists a playlist. `ttlMs` controls how long it is considered fresh. */
|
|
209
|
+
savePlaylist(playlist: Playlist, ttlMs: number): Promise<void>;
|
|
210
|
+
/** Returns a blob URL for the cached media, or null if not yet downloaded. */
|
|
211
|
+
getMediaUrl(url: string): Promise<string | null>;
|
|
212
|
+
/** Downloads and stores the media blob, returns a blob URL for immediate use. */
|
|
213
|
+
saveMedia(url: string, blob: Blob): Promise<string>;
|
|
214
|
+
/** Wipes all cached data (playlist metadata and media blobs). */
|
|
215
|
+
clear(): Promise<void>;
|
|
216
|
+
}
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region src/player/SquareScreenPlayer.d.ts
|
|
219
|
+
interface SquareScreenPlayerConfig {
|
|
220
|
+
/** Unique identifier for this device. */
|
|
221
|
+
deviceId: string;
|
|
222
|
+
/** Secret token used to authenticate this device. Never log or expose this value. */
|
|
223
|
+
deviceToken: string;
|
|
224
|
+
/** SDK version string sent on every heartbeat. */
|
|
225
|
+
version: string;
|
|
226
|
+
/** How long a cached playlist is considered fresh, in ms. Defaults to 5 minutes. */
|
|
227
|
+
ttl?: number;
|
|
228
|
+
/** How often to poll the API for playlist updates, in ms. Defaults to 30 seconds. */
|
|
229
|
+
pollInterval?: number;
|
|
230
|
+
/** How often to poll the API for emergency alerts, in ms. Defaults to 15 seconds. */
|
|
231
|
+
emergencyPollInterval?: number;
|
|
232
|
+
/** How often to send a heartbeat to the API, in ms. Defaults to 60 seconds. */
|
|
233
|
+
heartbeatInterval?: number;
|
|
234
|
+
/**
|
|
235
|
+
* Override the network layer with a custom implementation — useful for testing
|
|
236
|
+
* or mocking without a real API. When provided, `deviceId` and `deviceToken`
|
|
237
|
+
* are ignored for network calls. Otherwise requests go to the production API
|
|
238
|
+
* URL defined by {@link SQUARESCREEN_API_BASE_URL}.
|
|
239
|
+
*/
|
|
240
|
+
networkDataSource?: NetworkDataSource;
|
|
241
|
+
/**
|
|
242
|
+
* Override the cache layer with a custom implementation. When omitted the default
|
|
243
|
+
* `SquareScreenCache` (IndexedDB + Cache API) is used. Pass your own implementation
|
|
244
|
+
* to integrate with an existing media storage layer.
|
|
245
|
+
*/
|
|
246
|
+
cacheProvider?: SquareScreenCacheProvider;
|
|
247
|
+
}
|
|
248
|
+
/** Typed detail payloads for each player event. */
|
|
249
|
+
type PlayerEventMap = {
|
|
250
|
+
/** Fires when the current playlist item changes. */itemchange: CustomEvent<{
|
|
251
|
+
item: PlaylistItem;
|
|
252
|
+
index: number;
|
|
253
|
+
total: number;
|
|
254
|
+
}>; /** Fires when the device connectivity/sync status changes. */
|
|
255
|
+
statuschange: CustomEvent<{
|
|
256
|
+
status: DeviceStatus;
|
|
257
|
+
}>; /** Fires when an emergency alert becomes active or is cleared. */
|
|
258
|
+
emergencyalert: CustomEvent<{
|
|
259
|
+
alert: EmergencyAlert | null;
|
|
260
|
+
}>; /** Fires whenever the playlist is refreshed from the network or cache. */
|
|
261
|
+
playlistupdate: CustomEvent<{
|
|
262
|
+
playlist: Playlist;
|
|
263
|
+
}>;
|
|
264
|
+
};
|
|
265
|
+
/**
|
|
266
|
+
* Headless, framework-agnostic player that manages playlist fetching, caching,
|
|
267
|
+
* item advancement, preloading, polling, and emergency alerts.
|
|
268
|
+
*
|
|
269
|
+
* Extends `EventTarget` — use `addEventListener` / `removeEventListener` to
|
|
270
|
+
* react to player events. No DOM or rendering logic lives here.
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* const player = new SquareScreenPlayer({ deviceId, deviceToken, version: "1.0.0" });
|
|
274
|
+
* player.addEventListener("itemchange", ({ detail }) => render(detail.item));
|
|
275
|
+
* player.addEventListener("emergencyalert", ({ detail }) => showAlert(detail.alert));
|
|
276
|
+
* await player.start();
|
|
277
|
+
*/
|
|
278
|
+
declare class SquareScreenPlayer extends EventTarget {
|
|
279
|
+
private readonly network;
|
|
280
|
+
private readonly cache;
|
|
281
|
+
private readonly config;
|
|
282
|
+
private playlist;
|
|
283
|
+
private stopped;
|
|
284
|
+
private currentIndex;
|
|
285
|
+
private status;
|
|
286
|
+
private activeAlert;
|
|
287
|
+
private currentItemStartTime;
|
|
288
|
+
private itemTimer;
|
|
289
|
+
private playlistPollTimer;
|
|
290
|
+
private emergencyPollTimer;
|
|
291
|
+
private heartbeatTimer;
|
|
292
|
+
constructor(config: SquareScreenPlayerConfig);
|
|
293
|
+
/** The playlist item currently being displayed, or null if no playlist is loaded. */
|
|
294
|
+
get currentItem(): PlaylistItem | null;
|
|
295
|
+
/**
|
|
296
|
+
* Starts the player: fetches the playlist, begins playback, and starts polling
|
|
297
|
+
* and heartbeat intervals. Safe to await — resolves once the first playlist load
|
|
298
|
+
* attempt completes (whether from network or cache fallback).
|
|
299
|
+
*/
|
|
300
|
+
start(): Promise<void>;
|
|
301
|
+
/** Stops all timers and clears internal state. Call this when tearing down the player. */
|
|
302
|
+
stop(): void;
|
|
303
|
+
/**
|
|
304
|
+
* Network-first playlist load. On success the playlist is saved to cache and
|
|
305
|
+
* applied if the UUID changed. On failure the player falls back to the last
|
|
306
|
+
* known playlist UUID stored in `localStorage`, loading it from cache with
|
|
307
|
+
* `allowStale = true` so it is served even after its TTL has expired.
|
|
308
|
+
*/
|
|
309
|
+
private loadPlaylist;
|
|
310
|
+
/**
|
|
311
|
+
* Activates a playlist: optionally shuffles the items, resets the index to 0,
|
|
312
|
+
* emits `playlistupdate`, and kicks off the first `scheduleItem` call.
|
|
313
|
+
* Bails out immediately if `stop()` has been called.
|
|
314
|
+
*/
|
|
315
|
+
private applyPlaylist;
|
|
316
|
+
refreshPlaylist(): void;
|
|
317
|
+
/**
|
|
318
|
+
* Emits `itemchange` immediately with either the cached blob URL or the raw
|
|
319
|
+
* HTTPS URL, then arms the advancement timer. Never blocks on a network fetch —
|
|
320
|
+
* if the media isn't cached yet the browser loads it directly while
|
|
321
|
+
* `preloadNext` / `downloadInBackground` cache it for the next cycle.
|
|
322
|
+
*
|
|
323
|
+
* Guards against `stop()` being called while awaiting the cache lookup.
|
|
324
|
+
*/
|
|
325
|
+
private scheduleItem;
|
|
326
|
+
/**
|
|
327
|
+
* Schedules background downloads for upcoming items while the current one
|
|
328
|
+
* is playing, so subsequent transitions can serve blob URLs immediately.
|
|
329
|
+
*
|
|
330
|
+
* - `preloadCount: 0` — disabled; nothing is downloaded.
|
|
331
|
+
* - `preloadCount: N` — downloads the next N items ahead (wraps at end).
|
|
332
|
+
* - `preloadCount` absent — downloads all items in the playlist up front.
|
|
333
|
+
*/
|
|
334
|
+
private preloadNext;
|
|
335
|
+
/**
|
|
336
|
+
* Fire-and-forget download. Checks the cache first; if the media is already
|
|
337
|
+
* present the call is a no-op. Errors are silently swallowed — a failed
|
|
338
|
+
* download is not fatal; the raw URL will be used until the next successful download.
|
|
339
|
+
*/
|
|
340
|
+
private downloadInBackground;
|
|
341
|
+
/**
|
|
342
|
+
* Moves to the next item. Reports the completed playback event, then either
|
|
343
|
+
* wraps back to index 0 (when `loop` is true or absent) or halts when
|
|
344
|
+
* `loop: false` and the last item has finished.
|
|
345
|
+
*/
|
|
346
|
+
private advance;
|
|
347
|
+
/** Sends a proof-of-play event to the server. Fire-and-forget; failures are not surfaced. */
|
|
348
|
+
private reportPlaybackEvent;
|
|
349
|
+
/** Arms the playlist-refresh and emergency-alert polling intervals. */
|
|
350
|
+
private startPolling;
|
|
351
|
+
/** Arms the periodic heartbeat that keeps the device registration alive. */
|
|
352
|
+
private startHeartbeat;
|
|
353
|
+
/**
|
|
354
|
+
* Polls the server for an active emergency alert. Emits `emergencyalert` only
|
|
355
|
+
* when the state actually changes (alert activated, cleared, or replaced by a
|
|
356
|
+
* different UUID) to avoid redundant re-renders on the consumer side.
|
|
357
|
+
*/
|
|
358
|
+
private checkEmergencyAlert;
|
|
359
|
+
private setStatus;
|
|
360
|
+
private dispatch;
|
|
361
|
+
addEventListener<K extends keyof PlayerEventMap>(type: K, listener: (event: PlayerEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void;
|
|
362
|
+
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
|
363
|
+
removeEventListener<K extends keyof PlayerEventMap>(type: K, listener: (event: PlayerEventMap[K]) => void, options?: boolean | EventListenerOptions): void;
|
|
364
|
+
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
|
365
|
+
}
|
|
366
|
+
//#endregion
|
|
367
|
+
//#region src/renderer/SquareScreenRenderer.d.ts
|
|
368
|
+
interface SquareScreenRendererConfig {
|
|
369
|
+
/** Transition to use when an item doesn't specify one. Defaults to `"none"`. */
|
|
370
|
+
defaultTransition?: TransitionType;
|
|
371
|
+
/** Duration of transition animations in ms. Defaults to `500`. */
|
|
372
|
+
transitionDuration?: number;
|
|
373
|
+
/**
|
|
374
|
+
* Maximum ms to wait for a video to reach `canplay` before transitioning anyway.
|
|
375
|
+
* Keeps transitions on-time when media loads from a slow network.
|
|
376
|
+
* Defaults to `3000`. Set to `0` to transition immediately without waiting.
|
|
377
|
+
*/
|
|
378
|
+
canPlayTimeout?: number;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Optional vanilla JS renderer that wires a {@link SquareScreenPlayer} to a DOM container.
|
|
382
|
+
* Handles `<img>` / `<video>` element lifecycle, autoplay, transitions, and emergency alerts.
|
|
383
|
+
*
|
|
384
|
+
* When an emergency alert is active it renders a full-screen overlay on top of all content.
|
|
385
|
+
* Normal playback resumes automatically once the alert is cleared.
|
|
386
|
+
*
|
|
387
|
+
* @example
|
|
388
|
+
* const player = new SquareScreenPlayer({ ... });
|
|
389
|
+
* const renderer = new SquareScreenRenderer(document.getElementById("screen"), player);
|
|
390
|
+
* renderer.mount();
|
|
391
|
+
* await player.start();
|
|
392
|
+
*
|
|
393
|
+
* // Tear down
|
|
394
|
+
* player.stop();
|
|
395
|
+
* renderer.unmount();
|
|
396
|
+
*/
|
|
397
|
+
declare class SquareScreenRenderer {
|
|
398
|
+
private readonly container;
|
|
399
|
+
private readonly player;
|
|
400
|
+
private readonly config;
|
|
401
|
+
private wrapper;
|
|
402
|
+
/** Two slots that alternate as current/next during transitions. */
|
|
403
|
+
private slots;
|
|
404
|
+
private activeSlot;
|
|
405
|
+
private alertOverlay;
|
|
406
|
+
private readonly onItemChange;
|
|
407
|
+
private readonly onEmergencyAlert;
|
|
408
|
+
constructor(container: HTMLElement, player: SquareScreenPlayer, config?: SquareScreenRendererConfig);
|
|
409
|
+
/** Injects the renderer DOM into the container and begins listening to the player. */
|
|
410
|
+
mount(): void;
|
|
411
|
+
/** Removes the renderer DOM and stops listening to the player. */
|
|
412
|
+
unmount(): void;
|
|
413
|
+
private buildDOM;
|
|
414
|
+
private createSlot;
|
|
415
|
+
private handleItemChange;
|
|
416
|
+
private handleEmergencyAlert;
|
|
417
|
+
private createImage;
|
|
418
|
+
private createVideo;
|
|
419
|
+
private waitForCanPlay;
|
|
420
|
+
private applyTransition;
|
|
421
|
+
private wait;
|
|
422
|
+
}
|
|
423
|
+
//#endregion
|
|
424
|
+
//#region src/cache/SquareScreenCache.d.ts
|
|
425
|
+
/**
|
|
426
|
+
* Default {@link SquareScreenCacheProvider} backed by IndexedDB (playlist metadata)
|
|
427
|
+
* and the Cache API (media blobs).
|
|
428
|
+
*
|
|
429
|
+
* **IndexedDB** — a single `playlists` object store holds one document per
|
|
430
|
+
* playlist UUID. A private `_ttl` field (milliseconds) is stored alongside the
|
|
431
|
+
* record and stripped before returning data to callers.
|
|
432
|
+
*
|
|
433
|
+
* **Cache API** — media files are stored under their original URL as the cache
|
|
434
|
+
* key, matching the same URL-keyed approach used by the Android SDK's
|
|
435
|
+
* `MediaFileCache`. Once a blob is retrieved from the Cache API it is wrapped
|
|
436
|
+
* in a `URL.createObjectURL` handle that is kept in an in-memory map and reused
|
|
437
|
+
* on subsequent calls to avoid redundant allocations. All handles are revoked
|
|
438
|
+
* when {@link clear} is called.
|
|
439
|
+
*
|
|
440
|
+
* Integrators who need different storage behaviour (a service-worker cache,
|
|
441
|
+
* an in-memory store for tests, a custom database) should implement
|
|
442
|
+
* {@link SquareScreenCacheProvider} and pass it via
|
|
443
|
+
* `SquareScreenPlayerConfig.cacheProvider`.
|
|
444
|
+
*/
|
|
445
|
+
declare class SquareScreenCache implements SquareScreenCacheProvider {
|
|
446
|
+
private readonly dbName;
|
|
447
|
+
private readonly cacheName;
|
|
448
|
+
/** Tracks the blob URL created for each media URL so it is reused across calls. */
|
|
449
|
+
private readonly objectUrls;
|
|
450
|
+
/**
|
|
451
|
+
* @param dbName Name of the IndexedDB database. Override in tests to isolate state.
|
|
452
|
+
* @param cacheName Name of the Cache API bucket. Override in tests to isolate state.
|
|
453
|
+
*/
|
|
454
|
+
constructor({
|
|
455
|
+
dbName,
|
|
456
|
+
cacheName
|
|
457
|
+
}?: {
|
|
458
|
+
dbName?: string;
|
|
459
|
+
cacheName?: string;
|
|
460
|
+
});
|
|
461
|
+
/** Opens (or lazily creates) the IndexedDB database with the `playlists` object store. */
|
|
462
|
+
private openDB;
|
|
463
|
+
/**
|
|
464
|
+
* Returns the cached playlist for the given UUID, or `null` if:
|
|
465
|
+
* - nothing has been stored for that UUID, or
|
|
466
|
+
* - the record's age exceeds its TTL and `allowStale` is `false`.
|
|
467
|
+
*
|
|
468
|
+
* @param uuid The playlist UUID to look up.
|
|
469
|
+
* @param allowStale When `true`, expired records are returned as-is (useful
|
|
470
|
+
* for serving a fallback when the network is unreachable).
|
|
471
|
+
*/
|
|
472
|
+
getPlaylist(uuid: string, allowStale?: boolean): Promise<Playlist | null>;
|
|
473
|
+
/**
|
|
474
|
+
* Persists a playlist to IndexedDB, overwriting any previous record with the
|
|
475
|
+
* same UUID. `cachedAt` is set to the current wall-clock time so that TTL
|
|
476
|
+
* checks in {@link getPlaylist} have an accurate baseline.
|
|
477
|
+
*
|
|
478
|
+
* @param playlist The playlist to store. Items are persisted inline as part
|
|
479
|
+
* of the same document — no separate per-item records.
|
|
480
|
+
* @param ttlMs How long (in milliseconds) the record is considered fresh.
|
|
481
|
+
* Passed through `SquareScreenPlayerConfig.ttl` by the player.
|
|
482
|
+
*/
|
|
483
|
+
savePlaylist(playlist: Playlist, ttlMs: number): Promise<void>;
|
|
484
|
+
/**
|
|
485
|
+
* Returns a blob URL for the locally cached copy of `url`, or `null` if the
|
|
486
|
+
* media has not been downloaded yet.
|
|
487
|
+
*
|
|
488
|
+
* The blob URL is created once and stored in an in-memory map. Subsequent
|
|
489
|
+
* calls for the same `url` return the same handle without re-reading the
|
|
490
|
+
* Cache API, which avoids both I/O and unnecessary `URL.createObjectURL`
|
|
491
|
+
* allocations on long-running signage devices.
|
|
492
|
+
*
|
|
493
|
+
* @param url The original remote URL used as the Cache API key.
|
|
494
|
+
*/
|
|
495
|
+
getMediaUrl(url: string): Promise<string | null>;
|
|
496
|
+
/**
|
|
497
|
+
* Stores `blob` in the Cache API under `url` and returns a blob URL for
|
|
498
|
+
* immediate use by the renderer.
|
|
499
|
+
*
|
|
500
|
+
* Called by the player after a successful `fetch()` so that subsequent
|
|
501
|
+
* {@link getMediaUrl} calls for the same URL skip the network entirely.
|
|
502
|
+
*
|
|
503
|
+
* @param url The original remote URL — used as the Cache API key so that
|
|
504
|
+
* {@link getMediaUrl} can retrieve the entry with a simple `match`.
|
|
505
|
+
* @param blob The downloaded media blob to persist.
|
|
506
|
+
* @returns A blob URL that the renderer can set as `src` on an
|
|
507
|
+
* `<img>` or `<video>` element.
|
|
508
|
+
*/
|
|
509
|
+
saveMedia(url: string, blob: Blob): Promise<string>;
|
|
510
|
+
/**
|
|
511
|
+
* Wipes all cached data:
|
|
512
|
+
* - Revokes every outstanding blob URL to release the underlying Blob references.
|
|
513
|
+
* - Deletes the IndexedDB database entirely (recreated on next access).
|
|
514
|
+
* - Removes all entries from the Cache API bucket.
|
|
515
|
+
*
|
|
516
|
+
* Useful for a "factory reset" flow or in tests to guarantee a clean slate.
|
|
517
|
+
*/
|
|
518
|
+
clear(): Promise<void>;
|
|
519
|
+
}
|
|
520
|
+
//#endregion
|
|
521
|
+
export { type AuthError, type CacheError, type DeviceStatus, type EmergencyAlert, type EmergencyOverrideActive, type HeartbeatAck, type HeartbeatPayload, type ImagePlaylistParams, type MediaType, type NetworkDataSource, type NetworkError, type ParseError, type PlaybackEvent, type PlaybackStrategy, type PlayerEventMap, type Playlist, type PlaylistItem, type PlaylistMeta, SQUARESCREEN_API_BASE_URL, type Schedule, SquareScreenCache, type SquareScreenCacheProvider, type SquareScreenError, SquareScreenPlayer, type SquareScreenPlayerConfig, SquareScreenRenderer, type SquareScreenRendererConfig, type SquareScreenResult, type TransitionType, type VideoPlaylistParams };
|
|
522
|
+
//# sourceMappingURL=index.d.mts.map
|