@tomorrowos/sdk 1.1.4 → 1.1.6

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 (36) hide show
  1. package/PLAYER_INSTALL.md +32 -4
  2. package/README.md +1 -1
  3. package/dist/index.d.ts +3 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +1 -0
  6. package/dist/playlist-catalog.d.ts +5 -0
  7. package/dist/playlist-catalog.d.ts.map +1 -1
  8. package/dist/playlist-catalog.js +22 -1
  9. package/dist/screen-tags.d.ts +95 -0
  10. package/dist/screen-tags.d.ts.map +1 -0
  11. package/dist/screen-tags.js +835 -0
  12. package/dist/store/memory-store.d.ts +2 -0
  13. package/dist/store/memory-store.d.ts.map +1 -1
  14. package/dist/store/memory-store.js +11 -0
  15. package/dist/store/postgres-store.d.ts +2 -0
  16. package/dist/store/postgres-store.d.ts.map +1 -1
  17. package/dist/store/postgres-store.js +9 -0
  18. package/dist/store/sqlite-store.d.ts +2 -0
  19. package/dist/store/sqlite-store.d.ts.map +1 -1
  20. package/dist/store/sqlite-store.js +12 -0
  21. package/dist/store/types.d.ts +20 -0
  22. package/dist/store/types.d.ts.map +1 -1
  23. package/dist/tomorrowos.d.ts +6 -0
  24. package/dist/tomorrowos.d.ts.map +1 -1
  25. package/dist/tomorrowos.js +44 -1
  26. package/package.json +1 -1
  27. package/templates/cms-starter/package-lock.json +3 -3
  28. package/templates/cms-starter/package.json +2 -2
  29. package/templates/cms-starter/public/index.html +86 -1
  30. package/templates/cms-starter/public/methods.js +782 -11
  31. package/templates/cms-starter/public/panel.css +356 -0
  32. package/templates/cms-starter-v0/cms-panel/index.html +86 -1
  33. package/templates/cms-starter-v0/cms-panel/methods.js +782 -11
  34. package/templates/cms-starter-v0/cms-panel/panel.css +356 -0
  35. package/templates/cms-starter-v0/package-lock.json +3 -3
  36. package/templates/cms-starter-v0/package.json +2 -2
package/PLAYER_INSTALL.md CHANGED
@@ -18,7 +18,7 @@ This guide covers the full path from a verified player package to a paired scree
18
18
 
19
19
  - A running TomorrowOS CMS (Replit, Vercel, Railway, or self-hosted)
20
20
  - A CMS URL the **panel** can reach (public HTTPS in production, or a tunnel / LAN IP for lab tests)
21
- - A supported panel: **Samsung Tizen 6.5 and 7.0** or **BrightSign Series 3-6**
21
+ - A supported panel: **Samsung Tizen 6.5 and 7.0**, **BrightSign Series 3-6**, or **Windows 11 Pro x64** (Windows Player V1)
22
22
 
23
23
  ---
24
24
 
@@ -28,6 +28,7 @@ This guide covers the full path from a verified player package to a paired scree
28
28
  | --- | --- |
29
29
  | **Samsung** | Install on a Samsung Tizen player via **Custom App** (`https://tmr.sh/tizen`), or download the player from the CMS and install it via USB. |
30
30
  | **BrightSign** | Download the ZIP package from the CMS with `config.js` configured so that `cmsEndpoint` points to your CMS origin and install it via SD card. |
31
+ | **Windows** | Download **Windows Player V1** (`TomorrowOS-Windows-Setup.exe`) and run the installer on **Windows 11 Pro x64**. |
31
32
 
32
33
  ### Samsung (recommended path)
33
34
 
@@ -54,7 +55,21 @@ After install, enter your CMS URL on the on-device setup screen.
54
55
  1. Control Panel → **Download Players → BrightSign** (`GET /players/brightsign.zip`).
55
56
  2. That zip already has `cmsEndpoint` pointed at **this** CMS origin — usually you only confirm `orientation`.
56
57
 
57
- Caption in the Control Panel today: **Tizen 6.5 and 7.0**, **BrightSign Series 3-6**.
58
+ ### Windows
59
+
60
+ **Windows 11 Pro x64** — Windows Player V1. Download the installer from either:
61
+
62
+ - `https://tmr.sh/app/windows/TomorrowOS-Windows-Setup.exe`, **or**
63
+ - Control Panel → **Download Players → Windows**
64
+
65
+ Then install:
66
+
67
+ 1. Run `TomorrowOS-Windows-Setup.exe`.
68
+ 2. In the wizard, set the CMS endpoint, orientation, display, and maintenance passcode.
69
+ 3. Finish the wizard and launch the player.
70
+ 4. The screen shows a six-character pairing code. Enter it in the Control Panel to pair.
71
+
72
+ Caption in the Control Panel today: **Tizen 6.5 and 7.0**, **BrightSign Series 3-6**, **Windows 11 Pro x64**.
58
73
 
59
74
  ---
60
75
 
@@ -144,6 +159,18 @@ When you download via the CMS, `cmsEndpoint` is **filled automatically** with th
144
159
  9. Wait through the initial black window (~10 seconds before `Show()` is normal).
145
160
  10. Confirm the pairing / brand UI appears.
146
161
 
162
+ ### Windows
163
+
164
+ **Windows 11 Pro x64** — Windows Player V1.
165
+
166
+ 1. Download the installer from either:
167
+ - `https://tmr.sh/app/windows/TomorrowOS-Windows-Setup.exe`, **or**
168
+ - Control Panel → **Download Players → Windows**
169
+ 2. Run `TomorrowOS-Windows-Setup.exe`.
170
+ 3. In the wizard, set the CMS endpoint, orientation, display, and maintenance passcode.
171
+ 4. Finish the wizard and launch the player.
172
+ 5. The screen shows a six-character pairing code. Enter it in the Control Panel to pair.
173
+
147
174
  ---
148
175
 
149
176
  ## 4. Six-character pairing
@@ -191,7 +218,7 @@ Always record **model + firmware** from `device.info.get` before calling a fleet
191
218
 
192
219
  ### Not shipping yet
193
220
 
194
- LG webOS, Android, and Windows players are not in this SDK release.
221
+ LG webOS and Android players are not in this SDK release.
195
222
 
196
223
  ---
197
224
 
@@ -225,6 +252,7 @@ await tomorrowos.pairing.unpair(deviceId);
225
252
  2. Point the player at the **new** CMS endpoint:
226
253
  - Tizen: re-enter CMS URL on the setup screen (clear / change stored URL if needed, then reboot).
227
254
  - BrightSign: download a new zip from the **new** CMS (or edit `config.js` `cmsEndpoint`), copy to SD, power-cycle.
255
+ - Windows: re-run `TomorrowOS-Windows-Setup.exe` and set the new CMS endpoint, then launch the player.
228
256
  3. Pair on the new CMS with the on-screen code.
229
257
 
230
258
  ---
@@ -245,7 +273,7 @@ await tomorrowos.pairing.unpair(deviceId);
245
273
 
246
274
  ## Coming soon
247
275
 
248
- LG webOS, Android, and Windows apps.
276
+ LG webOS and Android players.
249
277
 
250
278
  ---
251
279
 
package/README.md CHANGED
@@ -106,9 +106,9 @@ Player install and pairing: `PLAYER_INSTALL.md`. Deep hosting and agent protocol
106
106
  | Samsung Tizen 6.5 and 7.0 | Supported | Certified models and firmware only |
107
107
  | BrightSign Series 3-6 | Supported | Series 3 requires firmware **9.1.140+** |
108
108
  | BrightSign Series 3 4K H.264 | Not supported | Use certified **1080p H.264** media |
109
+ | Windows 11 Pro x64 | Supported | None |
109
110
  | Android | Planned | Not available for production |
110
111
  | LG webOS | Planned | Not available for production |
111
- | Windows | Planned | Not available for production |
112
112
 
113
113
  Treat a combination as production-ready only after you validate it on your panels.
114
114
 
package/dist/index.d.ts CHANGED
@@ -3,8 +3,10 @@ export type { DeviceListItem, DeviceScreenshotInfo, ListenOptions, TomorrowOSBra
3
3
  export type { ConnectorState, ConnectorStatus, ServerStatusReport, StatusBlocker } from "./server-status.js";
4
4
  export { buildServerStatus } from "./server-status.js";
5
5
  export { getSdkPackageVersion } from "./sdk-version.js";
6
- export type { DeviceOnOffTimer, DevicePlaylistAssignment, DeviceRegistryRecord, PairedDeviceRecord, PendingCodeEntry, PendingCodeRecord, DeviceRegistryEntry, PlaylistItemRecord, PlaylistSchedule, PublishedPlaylistSnapshot, StoredPlaylist, TomorrowOSDataSnapshot, TomorrowOSMigratableStore, TomorrowOSStore } from "./store/types.js";
6
+ export type { DeviceOnOffTimer, DevicePlaylistAssignment, DeviceRegistryRecord, PairedDeviceRecord, PendingCodeEntry, PendingCodeRecord, DeviceRegistryEntry, PlaylistItemRecord, PlaylistItemSchedule, PlaylistItemTagRule, PlaylistSchedule, PublishedPlaylistSnapshot, StoredPlaylist, TomorrowOSDataSnapshot, TomorrowOSMigratableStore, TomorrowOSStore } from "./store/types.js";
7
7
  export { PlaylistCatalog } from "./playlist-catalog.js";
8
+ export { filterPolicyForScreen, itemMatchesScreen, itemScheduleActive, parseItemSchedule, parseTagRule, ScreenTagStore } from "./screen-tags.js";
9
+ export type { ItemSchedule, ScreenTagHost, ScreenTagHttpDeps, TagRule, TagRuleOp } from "./screen-tags.js";
8
10
  export type { BuiltDevicePolicy, SavePlaylistInput } from "./playlist-catalog.js";
9
11
  export { DEFAULT_PAIRING_CODE_SECRET, generateDeterministicPairingCode, generateRandomPairingCode, isValidPairingCodeFormat, normalizePairingCode, PAIRING_CODE_ALPHABET, PAIRING_CODE_LENGTH, resolvePairingCodeSecret } from "./pairing-code.js";
10
12
  export { MemoryStore } from "./store/memory-store.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,eAAe,EACf,iBAAiB,EAClB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,aAAa,EACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,YAAY,EACV,gBAAgB,EAChB,wBAAwB,EACxB,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,yBAAyB,EACzB,cAAc,EACd,sBAAsB,EACtB,yBAAyB,EACzB,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EACL,2BAA2B,EAC3B,gCAAgC,EAChC,yBAAyB,EACzB,wBAAwB,EACxB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,wBAAwB,EACzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,YAAY,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,4BAA4B,EAC5B,qBAAqB,EACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,eAAe,EACf,iBAAiB,EAClB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,aAAa,EACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,YAAY,EACV,gBAAgB,EAChB,wBAAwB,EACxB,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,yBAAyB,EACzB,cAAc,EACd,sBAAsB,EACtB,yBAAyB,EACzB,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACf,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,OAAO,EACP,SAAS,EACV,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EACL,2BAA2B,EAC3B,gCAAgC,EAChC,yBAAyB,EACzB,wBAAwB,EACxB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,wBAAwB,EACzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,YAAY,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,4BAA4B,EAC5B,qBAAqB,EACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ export { TomorrowOS } from "./tomorrowos.js";
2
2
  export { buildServerStatus } from "./server-status.js";
3
3
  export { getSdkPackageVersion } from "./sdk-version.js";
4
4
  export { PlaylistCatalog } from "./playlist-catalog.js";
5
+ export { filterPolicyForScreen, itemMatchesScreen, itemScheduleActive, parseItemSchedule, parseTagRule, ScreenTagStore } from "./screen-tags.js";
5
6
  export { DEFAULT_PAIRING_CODE_SECRET, generateDeterministicPairingCode, generateRandomPairingCode, isValidPairingCodeFormat, normalizePairingCode, PAIRING_CODE_ALPHABET, PAIRING_CODE_LENGTH, resolvePairingCodeSecret } from "./pairing-code.js";
6
7
  export { MemoryStore } from "./store/memory-store.js";
7
8
  export { PostgresStore } from "./store/postgres-store.js";
@@ -29,6 +29,11 @@ export declare class PlaylistCatalog {
29
29
  removePlaylistFromDevice(deviceId: string, playlistId: string): Promise<BuiltDevicePolicy>;
30
30
  /** Remove every playlist assignment from a device (CMS catalog + empty policy). */
31
31
  clearAllAssignmentsFromDevice(deviceId: string): Promise<BuiltDevicePolicy>;
32
+ /**
33
+ * A retired playlist stays only while some device still has its published snapshot.
34
+ * Clear (or removing it from the last screen) drops that snapshot, so the row goes too.
35
+ */
36
+ private deleteRetiredPlaylistsWithoutAssignments;
32
37
  /**
33
38
  * If the device has this playlist assigned, refresh its snapshot to latest
34
39
  * and return a rebuilt snapshot policy for immediate push.
@@ -1 +1 @@
1
- {"version":3,"file":"playlist-catalog.d.ts","sourceRoot":"","sources":["../src/playlist-catalog.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,wBAAwB,EACxB,kBAAkB,EAClB,gBAAgB,EAChB,yBAAyB,EACzB,cAAc,EACd,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,kBAAkB,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE;QACN,SAAS,EAAE,yBAAyB,EAAE,CAAC;QACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;KAClC,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAyDD,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,eAAe;IAE7C,aAAa,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAK1C,6BAA6B,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAI1D,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAI5D,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC;IA8B/D,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAcnD,oBAAoB,CACxB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,wBAAwB,EAAE,CAAC;IAIhC,wBAAwB,CAC5B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EAAE,EACrB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC;IAiEvB,wBAAwB,CAC5B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,CAAC;IAO7B,mFAAmF;IAC7E,6BAA6B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAKjF;;;OAGG;IACG,+BAA+B,CACnC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,iBAAiB,CAAA;KAAE,CAAC;IA4BrD,oBAAoB,CACxB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC;YAKf,0BAA0B;IA+BxC,6BAA6B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAGpE"}
1
+ {"version":3,"file":"playlist-catalog.d.ts","sourceRoot":"","sources":["../src/playlist-catalog.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,wBAAwB,EACxB,kBAAkB,EAClB,gBAAgB,EAChB,yBAAyB,EACzB,cAAc,EACd,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,kBAAkB,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE;QACN,SAAS,EAAE,yBAAyB,EAAE,CAAC;QACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;KAClC,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAyDD,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,eAAe;IAE7C,aAAa,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAK1C,6BAA6B,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAI1D,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAI5D,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC;IA8B/D,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAkBnD,oBAAoB,CACxB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,wBAAwB,EAAE,CAAC;IAIhC,wBAAwB,CAC5B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EAAE,EACrB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC;IAiEvB,wBAAwB,CAC5B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,CAAC;IAQ7B,mFAAmF;IAC7E,6BAA6B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IASjF;;;OAGG;YACW,wCAAwC;IAStD;;;OAGG;IACG,+BAA+B,CACnC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,iBAAiB,CAAA;KAAE,CAAC;IA4BrD,oBAAoB,CACxB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC;YAKf,0BAA0B;IA+BxC,6BAA6B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAGpE"}
@@ -100,7 +100,11 @@ export class PlaylistCatalog {
100
100
  retired: true,
101
101
  retiredAt: new Date().toISOString()
102
102
  };
103
- await this.store.setPlaylist(record);
103
+ if (await this.store.isPlaylistAssigned(id)) {
104
+ await this.store.setPlaylist(record);
105
+ return record;
106
+ }
107
+ await this.store.deletePlaylist(id);
104
108
  return record;
105
109
  }
106
110
  async getDeviceAssignments(deviceId) {
@@ -161,13 +165,30 @@ export class PlaylistCatalog {
161
165
  const assignments = await this.store.getDeviceAssignments(deviceId);
162
166
  const next = assignments.filter((a) => a.playlistId !== playlistId);
163
167
  await this.store.setDeviceAssignments(deviceId, next);
168
+ await this.deleteRetiredPlaylistsWithoutAssignments([playlistId]);
164
169
  return this.buildPolicyFromAssignments(next, { useLatest: false });
165
170
  }
166
171
  /** Remove every playlist assignment from a device (CMS catalog + empty policy). */
167
172
  async clearAllAssignmentsFromDevice(deviceId) {
173
+ const removedIds = (await this.store.getDeviceAssignments(deviceId)).map((assignment) => assignment.playlistId);
168
174
  await this.store.setDeviceAssignments(deviceId, []);
175
+ await this.deleteRetiredPlaylistsWithoutAssignments(removedIds);
169
176
  return this.buildPolicyFromAssignments([], { useLatest: false });
170
177
  }
178
+ /**
179
+ * A retired playlist stays only while some device still has its published snapshot.
180
+ * Clear (or removing it from the last screen) drops that snapshot, so the row goes too.
181
+ */
182
+ async deleteRetiredPlaylistsWithoutAssignments(playlistIds) {
183
+ for (const playlistId of new Set(playlistIds)) {
184
+ const playlist = await this.store.getPlaylist(playlistId);
185
+ if (!playlist?.retired)
186
+ continue;
187
+ if (await this.store.isPlaylistAssigned(playlistId))
188
+ continue;
189
+ await this.store.deletePlaylist(playlistId);
190
+ }
191
+ }
171
192
  /**
172
193
  * If the device has this playlist assigned, refresh its snapshot to latest
173
194
  * and return a rebuilt snapshot policy for immediate push.
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Screen tags and per-item schedules.
3
+ *
4
+ * Screens store tags. Each playlist item may store a tagRule and a schedule.
5
+ * When a policy is pushed, items that do not match that screen right now are
6
+ * removed. Items with no rule play on every screen. Items with no schedule
7
+ * play all the time. tagRule and schedule are stripped before the player sees
8
+ * the policy.
9
+ *
10
+ * Screen tags live in screen-tags.json beside the SQLite database (or
11
+ * data/screen-tags.json). Playlist item rules ride along in items JSON.
12
+ */
13
+ import type { IncomingMessage, ServerResponse } from "http";
14
+ import type { TomorrowOSStore } from "./store/types.js";
15
+ export interface ScreenTagHost {
16
+ listDevices(): Promise<Array<{
17
+ deviceId: string;
18
+ deviceName?: string | null;
19
+ connected: boolean;
20
+ }>>;
21
+ pushLatestPolicyToDevice(deviceId: string): Promise<{
22
+ pushed: boolean;
23
+ }>;
24
+ playlists: {
25
+ buildPolicyForDevice(deviceId: string, options: {
26
+ useLatest?: boolean;
27
+ }): Promise<{
28
+ policy: unknown;
29
+ }>;
30
+ };
31
+ }
32
+ export type TagRuleOp = "any" | "all" | "notAny" | "notAll";
33
+ export interface TagRule {
34
+ op: TagRuleOp;
35
+ tags: string[];
36
+ }
37
+ export declare function normalizeTag(raw: unknown): string | null;
38
+ export declare function normalizeTagList(raw: unknown): string[];
39
+ /**
40
+ * Monday = 0 … Sunday = 6.
41
+ * [true, true, true, true, true, false, false] is Mon–Fri and does not play Sat or Sun.
42
+ * [false, false, false, false, false, true, true] is Sat and Sun.
43
+ */
44
+ export declare function weekdayIndexMondayFirst(date: Date): number;
45
+ export interface ItemSchedule {
46
+ startDate?: string;
47
+ endDate?: string;
48
+ startTime?: string;
49
+ endTime?: string;
50
+ days?: boolean[];
51
+ }
52
+ /** Missing or empty schedule means the item plays all the time. */
53
+ export declare function parseItemSchedule(raw: unknown): ItemSchedule | null;
54
+ /**
55
+ * `now` is interpreted in its local timezone. End times are exclusive.
56
+ * A window whose end is earlier than its start continues past midnight,
57
+ * and that tail still belongs to the day the window started.
58
+ */
59
+ export declare function itemScheduleActive(raw: unknown, now?: Date): boolean;
60
+ /** Missing, empty, or invalid rules mean the item plays on every screen. */
61
+ export declare function parseTagRule(raw: unknown): TagRule | null;
62
+ export declare function itemMatchesScreen(screenTags: readonly string[], item: unknown, now?: Date): boolean;
63
+ /** Returns a new policy. Does not mutate the SDK snapshot objects. */
64
+ export declare function filterPolicyForScreen(policy: unknown, screenTags: readonly string[], now?: Date): unknown;
65
+ /**
66
+ * Re-push a screen when a schedule window opens or closes.
67
+ * Current players ignore item schedules, so the CMS removes inactive items
68
+ * before the policy is sent. The check uses this computer's local clock.
69
+ */
70
+ export declare function startItemScheduleRefresher(deps: ScreenTagHttpDeps): void;
71
+ export declare class ScreenTagStore {
72
+ private readonly filePath;
73
+ private chain;
74
+ constructor(filePath: string);
75
+ get(deviceId: string): Promise<string[]>;
76
+ all(): Promise<Record<string, string[]>>;
77
+ catalog(): Promise<string[]>;
78
+ remember(tag: string): Promise<string[]>;
79
+ rename(from: string, to: string): Promise<string[]>;
80
+ forget(tag: string): Promise<void>;
81
+ add(deviceId: string, tag: string): Promise<string[]>;
82
+ remove(deviceId: string, tag: string): Promise<string[]>;
83
+ deleteDevice(deviceId: string): Promise<void>;
84
+ private rememberOn;
85
+ private enqueue;
86
+ private read;
87
+ private write;
88
+ }
89
+ export interface ScreenTagHttpDeps {
90
+ host: ScreenTagHost;
91
+ store: TomorrowOSStore;
92
+ tags: ScreenTagStore;
93
+ }
94
+ export declare function handleScreenTagHttp(req: IncomingMessage, res: ServerResponse, deps: ScreenTagHttpDeps): Promise<boolean>;
95
+ //# sourceMappingURL=screen-tags.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen-tags.d.ts","sourceRoot":"","sources":["../src/screen-tags.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAE5D,OAAO,KAAK,EAGV,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,aAAa;IAC5B,WAAW,IAAI,OAAO,CACpB,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAC5E,CAAC;IACF,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACzE,SAAS,EAAE;QACT,oBAAoB,CAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE;YAAE,SAAS,CAAC,EAAE,OAAO,CAAA;SAAE,GAC/B,OAAO,CAAC;YAAE,MAAM,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;KACjC,CAAC;CACH;AAED,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE5D,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,SAAS,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAeD,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAIxD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,EAAE,CAWvD;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE1D;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;CAClB;AAiCD,mEAAmE;AACnE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CA6BnE;AAaD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,GAAE,IAAiB,GAAG,OAAO,CAmChF;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CASzD;AAED,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,IAAI,EAAE,OAAO,EACb,GAAG,GAAE,IAAiB,GACrB,OAAO,CAuBT;AAUD,sEAAsE;AACtE,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,OAAO,EACf,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,GAAG,GAAE,IAAiB,GACrB,OAAO,CAkBT;AAmCD;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CA2DxE;AAOD,qBAAa,cAAc;IAGb,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAFrC,OAAO,CAAC,KAAK,CAAoC;gBAEpB,QAAQ,EAAE,MAAM;IAEvC,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAKxC,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IASxC,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAK5B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IASxC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAqBnD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQlC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAYrD,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAWxD,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASnD,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,OAAO;YASD,IAAI;YAyBJ,KAAK;CAMpB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,eAAe,CAAC;IACvB,IAAI,EAAE,cAAc,CAAC;CACtB;AAyND,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,OAAO,CAAC,CAoLlB"}