@tomorrowos/sdk 0.9.10 → 0.9.11

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/REPLIT_SETUP.md CHANGED
@@ -230,7 +230,7 @@ Allowed extras (optional): `"build-player": "tomorrowos build --platform tizen"`
230
230
  "node": ">=20"
231
231
  },
232
232
  "dependencies": {
233
- "@tomorrowos/sdk": "^0.9.10",
233
+ "@tomorrowos/sdk": "^0.9.11",
234
234
  "dotenv": "^17.2.3",
235
235
  "tsx": "^4.19.0"
236
236
  },
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export { TomorrowOS } from "./tomorrowos.js";
2
2
  export type { DeviceListItem, DeviceScreenshotInfo, ListenOptions, TomorrowOSBrand, TomorrowOSOptions } from "./tomorrowos.js";
3
3
  export type { ConnectorState, ConnectorStatus, ServerStatusReport, StatusBlocker } from "./server-status.js";
4
4
  export { buildServerStatus } from "./server-status.js";
5
+ export { getSdkPackageVersion } from "./sdk-version.js";
5
6
  export type { DevicePlaylistAssignment, DeviceRegistryRecord, PairedDeviceRecord, PendingCodeEntry, PendingCodeRecord, DeviceRegistryEntry, PlaylistItemRecord, PlaylistSchedule, PublishedPlaylistSnapshot, StoredPlaylist, TomorrowOSDataSnapshot, TomorrowOSMigratableStore, TomorrowOSStore } from "./store/types.js";
6
7
  export { PlaylistCatalog } from "./playlist-catalog.js";
7
8
  export type { BuiltDevicePolicy, SavePlaylistInput } from "./playlist-catalog.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;AAEvD,YAAY,EACV,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,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"}
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export { TomorrowOS } from "./tomorrowos.js";
2
2
  export { buildServerStatus } from "./server-status.js";
3
+ export { getSdkPackageVersion } from "./sdk-version.js";
3
4
  export { PlaylistCatalog } from "./playlist-catalog.js";
4
5
  export { DEFAULT_PAIRING_CODE_SECRET, generateDeterministicPairingCode, generateRandomPairingCode, isValidPairingCodeFormat, normalizePairingCode, PAIRING_CODE_ALPHABET, PAIRING_CODE_LENGTH, resolvePairingCodeSecret } from "./pairing-code.js";
5
6
  export { MemoryStore } from "./store/memory-store.js";
@@ -0,0 +1,3 @@
1
+ /** Installed `@tomorrowos/sdk` package version (from this package's package.json). */
2
+ export declare function getSdkPackageVersion(): string;
3
+ //# sourceMappingURL=sdk-version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk-version.d.ts","sourceRoot":"","sources":["../src/sdk-version.ts"],"names":[],"mappings":"AAIA,sFAAsF;AACtF,wBAAgB,oBAAoB,IAAI,MAAM,CAW7C"}
@@ -0,0 +1,15 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { fileURLToPath } from "url";
4
+ /** Installed `@tomorrowos/sdk` package version (from this package's package.json). */
5
+ export function getSdkPackageVersion() {
6
+ try {
7
+ const here = path.dirname(fileURLToPath(import.meta.url));
8
+ const pkgPath = path.join(here, "..", "package.json");
9
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
10
+ return String(pkg.version || "").trim() || "unknown";
11
+ }
12
+ catch {
13
+ return "unknown";
14
+ }
15
+ }
@@ -17,6 +17,8 @@ export interface ServerStatusReport {
17
17
  status: "success";
18
18
  overall: "ok" | "degraded" | "blocked";
19
19
  checkedAt: string;
20
+ /** Installed `@tomorrowos/sdk` version. */
21
+ sdkVersion: string;
20
22
  connectors: ConnectorStatus[];
21
23
  blockers: StatusBlocker[];
22
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server-status.d.ts","sourceRoot":"","sources":["../src/server-status.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;AAEjE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,EAAE,IAAI,GAAG,UAAU,GAAG,SAAS,CAAC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,eAAe,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAoSD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC,CA4B7B"}
1
+ {"version":3,"file":"server-status.d.ts","sourceRoot":"","sources":["../src/server-status.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;AAEjE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,EAAE,IAAI,GAAG,UAAU,GAAG,SAAS,CAAC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,eAAe,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAoSD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC,CA6B7B"}
@@ -1,6 +1,7 @@
1
1
  import fs from "fs/promises";
2
2
  import path from "path";
3
3
  import { pingCloudinary, resolveCloudinaryConfig } from "./cloudinary-storage.js";
4
+ import { getSdkPackageVersion } from "./sdk-version.js";
4
5
  function isReplitHost(env) {
5
6
  return !!(env.REPL_ID ||
6
7
  env.REPLIT_DEV_DOMAIN ||
@@ -259,6 +260,7 @@ export async function buildServerStatus(options) {
259
260
  status: "success",
260
261
  overall,
261
262
  checkedAt: new Date().toISOString(),
263
+ sdkVersion: getSdkPackageVersion(),
262
264
  connectors,
263
265
  blockers
264
266
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomorrowos/sdk",
3
- "version": "0.9.10",
3
+ "version": "0.9.11",
4
4
  "description": "TomorrowOS CMS server SDK - WebSocket transport, pairing, device commands, optional static CMS UI. Includes CLI (tomorrowos init / build) and starter templates.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "my-cms",
3
- "version": "0.9.10",
3
+ "version": "0.9.11",
4
4
  "description": "CMS server on @tomorrowos/sdk. Add your UI (React, static files, etc.) alongside this server.",
5
5
  "private": true,
6
6
  "type": "module",
@@ -13,7 +13,7 @@
13
13
  "build-player": "tomorrowos build --platform tizen"
14
14
  },
15
15
  "dependencies": {
16
- "@tomorrowos/sdk": "^0.9.10",
16
+ "@tomorrowos/sdk": "^0.9.11",
17
17
  "dotenv": "^17.2.3",
18
18
  "tsx": "^4.19.0"
19
19
  },
@@ -23,6 +23,9 @@
23
23
  <button type="button" id="downloadPlayersBtn" class="download-players-trigger">
24
24
  Download Players
25
25
  </button>
26
+ <button type="button" id="updateSdkBtn" class="download-players-trigger">
27
+ Update SDK
28
+ </button>
26
29
  </div>
27
30
  </aside>
28
31
 
@@ -194,6 +197,23 @@
194
197
  </div>
195
198
  </div>
196
199
 
200
+ <div id="updateSdkModal" class="modal hidden" role="dialog" aria-modal="true" aria-labelledby="updateSdkModalTitle">
201
+ <div class="modal-backdrop" data-close-update-sdk-modal="1"></div>
202
+ <div class="modal-card update-sdk-modal-card">
203
+ <h2 id="updateSdkModalTitle">Update SDK</h2>
204
+ <p class="hint">Current installed SDK version:</p>
205
+ <p class="update-sdk-version" id="updateSdkVersionLabel">Loading…</p>
206
+ <p class="hint">
207
+ To upgrade on Replit (or another Agent platform), paste this prompt into the Agent chat:
208
+ </p>
209
+ <pre class="update-sdk-prompt" id="updateSdkPromptText">Follow @tomorrowos/sdk REPLIT_UPGRADE.md to upgrade my CMS with the latest SDK.</pre>
210
+ <div class="modal-actions update-sdk-modal-actions">
211
+ <button type="button" id="copyUpdateSdkPromptBtn" class="primary">Copy prompt</button>
212
+ <button type="button" data-close-update-sdk-modal="1">Close</button>
213
+ </div>
214
+ </div>
215
+ </div>
216
+
197
217
  <div id="downloadPlayersModal" class="modal hidden" role="dialog" aria-modal="true" aria-labelledby="downloadPlayersModalTitle">
198
218
  <div class="modal-backdrop" data-close-download-players-modal="1"></div>
199
219
  <div class="modal-card download-players-modal-card">
@@ -28,8 +28,13 @@ let editingDeviceNameValue = "";
28
28
 
29
29
  let devicePollTimer = null;
30
30
  let serverStatusTimer = null;
31
+ /** @type {string} Latest known `@tomorrowos/sdk` version from GET /status. */
32
+ let cachedSdkVersion = "";
31
33
  /** @type {number|null} CMS server boot time (ms) from GET /devices. */
32
34
  let serverStartedAtMs = null;
35
+
36
+ const UPDATE_SDK_PROMPT =
37
+ "Follow @tomorrowos/sdk REPLIT_UPGRADE.md to upgrade my CMS with the latest SDK.";
33
38
  /** @type {ReturnType<typeof setTimeout>|null} */
34
39
  let reconnectGraceTimer = null;
35
40
  let uploadQueue = [];
@@ -1804,6 +1809,48 @@ function closeDownloadPlayersModal() {
1804
1809
  document.getElementById("downloadPlayersModal")?.classList.add("hidden");
1805
1810
  }
1806
1811
 
1812
+ function setUpdateSdkVersionLabel(version) {
1813
+ const label = document.getElementById("updateSdkVersionLabel");
1814
+ if (!label) return;
1815
+ label.textContent = version || "unknown";
1816
+ }
1817
+
1818
+ async function openUpdateSdkModal() {
1819
+ const modal = document.getElementById("updateSdkModal");
1820
+ const promptEl = document.getElementById("updateSdkPromptText");
1821
+ if (promptEl) promptEl.textContent = UPDATE_SDK_PROMPT;
1822
+ setUpdateSdkVersionLabel(cachedSdkVersion || "Loading…");
1823
+ modal?.classList.remove("hidden");
1824
+
1825
+ if (!cachedSdkVersion) {
1826
+ await fetchServerStatus();
1827
+ setUpdateSdkVersionLabel(cachedSdkVersion || "unknown");
1828
+ }
1829
+ }
1830
+
1831
+ function closeUpdateSdkModal() {
1832
+ document.getElementById("updateSdkModal")?.classList.add("hidden");
1833
+ }
1834
+
1835
+ async function copyUpdateSdkPrompt() {
1836
+ const text =
1837
+ document.getElementById("updateSdkPromptText")?.textContent?.trim() ||
1838
+ UPDATE_SDK_PROMPT;
1839
+ try {
1840
+ await navigator.clipboard.writeText(text);
1841
+ const btn = document.getElementById("copyUpdateSdkPromptBtn");
1842
+ if (btn) {
1843
+ const prev = btn.textContent;
1844
+ btn.textContent = "Copied";
1845
+ setTimeout(() => {
1846
+ btn.textContent = prev || "Copy prompt";
1847
+ }, 1200);
1848
+ }
1849
+ } catch {
1850
+ alert("Could not copy automatically. Select the prompt text and copy it manually.");
1851
+ }
1852
+ }
1853
+
1807
1854
  function handlePlayerDownloadLinkClick(ev) {
1808
1855
  ev.preventDefault();
1809
1856
  const platform = ev.currentTarget?.dataset?.playerDownload || "unknown";
@@ -1985,6 +2032,9 @@ async function fetchServerStatus() {
1985
2032
  });
1986
2033
  return;
1987
2034
  }
2035
+ if (typeof data.sdkVersion === "string" && data.sdkVersion.trim()) {
2036
+ cachedSdkVersion = data.sdkVersion.trim();
2037
+ }
1988
2038
  renderServerStatus(data);
1989
2039
  } catch (err) {
1990
2040
  renderServerStatus({
@@ -2063,6 +2113,14 @@ document.addEventListener("DOMContentLoaded", () => {
2063
2113
  el.addEventListener("click", handlePlayerDownloadLinkClick);
2064
2114
  });
2065
2115
 
2116
+ document.getElementById("updateSdkBtn")?.addEventListener("click", () => void openUpdateSdkModal());
2117
+ document.querySelectorAll("[data-close-update-sdk-modal]").forEach((el) => {
2118
+ el.addEventListener("click", closeUpdateSdkModal);
2119
+ });
2120
+ document
2121
+ .getElementById("copyUpdateSdkPromptBtn")
2122
+ ?.addEventListener("click", () => void copyUpdateSdkPrompt());
2123
+
2066
2124
  document.getElementById("addAssetBtn")?.addEventListener("click", () => {
2067
2125
  if (uploadInProgress) return;
2068
2126
  if (!isPlaylistEditorOpen()) {
@@ -908,7 +908,9 @@ button.danger {
908
908
  .download-players-nav-slot {
909
909
  margin-top: auto;
910
910
  display: flex;
911
- justify-content: center;
911
+ flex-direction: column;
912
+ align-items: stretch;
913
+ gap: 0.45rem;
912
914
  padding-top: 0.75rem;
913
915
  }
914
916
 
@@ -922,12 +924,43 @@ button.danger {
922
924
  background: #fff;
923
925
  color: #0a0908;
924
926
  cursor: pointer;
927
+ width: 100%;
928
+ text-align: center;
925
929
  }
926
930
 
927
931
  .download-players-trigger:hover {
928
932
  background: #f5f3ef;
929
933
  }
930
934
 
935
+ .update-sdk-modal-card {
936
+ width: min(92vw, 480px);
937
+ }
938
+
939
+ .update-sdk-version {
940
+ margin: 0 0 1rem;
941
+ font-size: 1.35rem;
942
+ font-weight: 600;
943
+ letter-spacing: 0.02em;
944
+ color: #0a0908;
945
+ }
946
+
947
+ .update-sdk-prompt {
948
+ margin: 0;
949
+ padding: 0.75rem 0.85rem;
950
+ border: 1px solid #e4e1dc;
951
+ border-radius: 8px;
952
+ background: #fafaf9;
953
+ font-size: 0.8rem;
954
+ line-height: 1.45;
955
+ white-space: pre-wrap;
956
+ word-break: break-word;
957
+ color: #0a0908;
958
+ }
959
+
960
+ .update-sdk-modal-actions {
961
+ justify-content: flex-end;
962
+ }
963
+
931
964
  .download-players-modal-card {
932
965
  width: min(92vw, 560px);
933
966
  padding: 1.5rem 1.75rem 1.25rem;