@tomorrowos/sdk 0.9.44 → 0.9.50
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/LOVABLE_SETUP.md +1 -1
- package/VERCEL_QUESTIONS.md +1 -1
- package/VERCEL_SETUP.md +1 -1
- package/dist/tomorrowos.d.ts +11 -2
- package/dist/tomorrowos.d.ts.map +1 -1
- package/dist/tomorrowos.js +90 -20
- package/package.json +1 -1
- package/templates/cms-starter/package.json +2 -2
- package/templates/cms-starter/public/index.html +1 -1
- package/templates/cms-starter/public/methods.js +1 -1
- package/templates/cms-starter-v0/cms-panel/index.html +1 -1
- package/templates/cms-starter-v0/cms-panel/methods.js +1 -1
- package/templates/cms-starter-v0/package.json +2 -2
package/LOVABLE_SETUP.md
CHANGED
package/VERCEL_QUESTIONS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Vercel / v0 閳?Verbatim question bank
|
|
2
2
|
|
|
3
|
-
> **Protocol:** `vercel-questions/1.0` (pairs with `VERCEL_SETUP.md` 1.9+ / `@tomorrowos/sdk` 0.9.
|
|
3
|
+
> **Protocol:** `vercel-questions/1.0` (pairs with `VERCEL_SETUP.md` 1.9+ / `@tomorrowos/sdk` 0.9.50+)
|
|
4
4
|
> **For Agents:** When asking the user a setup question, **copy-paste the block below for that step EXACTLY**.
|
|
5
5
|
> Do **not** paraphrase, reorder, rename options, or invent alternatives (no S3, no Supabase Storage, no 閳ユ窂lob recommended閳? no 閳ユ竸isable media閳?.
|
|
6
6
|
> After each answer, configure per `VERCEL_SETUP.md`, then paste the **next** block.
|
package/VERCEL_SETUP.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
>
|
|
6
6
|
> **On Vercel, this file is the setup questionnaire** (not `REPLIT_SETUP.md`, not `LLM_PROMPT.md`).
|
|
7
7
|
>
|
|
8
|
-
> Protocol id: `vercel-setup/1.9`
|
|
8
|
+
> Protocol id: `vercel-setup/1.9` — pairs with `@tomorrowos/sdk` **0.9.50+** (`templates/cms-starter-v0`, Fluid Functions WebSockets).
|
|
9
9
|
>
|
|
10
10
|
> **Questions source of truth:** `VERCEL_QUESTIONS.md` ? Agents must **open that file and paste each Q block verbatim**. Do not paraphrase.
|
|
11
11
|
> **Copy questions verbatim from `VERCEL_QUESTIONS.md`.** Do not invent alternate Q2 options (no ?Supabase Storage?? no S3, no ?disable media?? no making Blob the recommended option).
|
package/dist/tomorrowos.d.ts
CHANGED
|
@@ -149,8 +149,8 @@ export declare class TomorrowOS extends EventEmitter {
|
|
|
149
149
|
pushed: boolean;
|
|
150
150
|
}>;
|
|
151
151
|
/**
|
|
152
|
-
* Clear the daily on/off timer
|
|
153
|
-
*
|
|
152
|
+
* Clear the daily on/off timer and push null to the device.
|
|
153
|
+
* Connected players drop the schedule and turn the screen back on.
|
|
154
154
|
*/
|
|
155
155
|
clearDeviceOnOffTimer(deviceId: string): Promise<{
|
|
156
156
|
deviceId: string;
|
|
@@ -170,6 +170,15 @@ export declare class TomorrowOS extends EventEmitter {
|
|
|
170
170
|
private pushDeviceLog;
|
|
171
171
|
private getDeviceLogs;
|
|
172
172
|
private isDeviceConnected;
|
|
173
|
+
/**
|
|
174
|
+
* Bind a live device socket. Never register a closed socket (avoids a late
|
|
175
|
+
* hello overwriting a healthy reconnect with a dead peer).
|
|
176
|
+
*/
|
|
177
|
+
private bindDeviceSocket;
|
|
178
|
+
/** Wait briefly for the device WebSocket to appear (first-pair hello races). */
|
|
179
|
+
private waitForOpenDeviceSocket;
|
|
180
|
+
private sendPairingVerified;
|
|
181
|
+
private afterDevicePairedNotify;
|
|
173
182
|
private captureHelloMeta;
|
|
174
183
|
private getOrCreatePermanentPairingCode;
|
|
175
184
|
private mergePairedRecord;
|
package/dist/tomorrowos.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tomorrowos.d.ts","sourceRoot":"","sources":["../src/tomorrowos.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"tomorrowos.d.ts","sourceRoot":"","sources":["../src/tomorrowos.ts"],"names":[],"mappings":"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"}
|
package/dist/tomorrowos.js
CHANGED
|
@@ -316,21 +316,29 @@ export class TomorrowOS extends EventEmitter {
|
|
|
316
316
|
await this.seedRegistryDisplayNameIfEmpty(deviceId, deviceName);
|
|
317
317
|
}
|
|
318
318
|
await this.store.deletePendingCode(normalized);
|
|
319
|
-
|
|
319
|
+
// First-pair races: hello may still be awaiting registry I/O, or the socket
|
|
320
|
+
// briefly dropped between showing the code and verify. Wait a short window
|
|
321
|
+
// before giving up — hello-heal will still deliver verified on reconnect.
|
|
322
|
+
let ws = this.devices.get(deviceId);
|
|
323
|
+
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
|
324
|
+
ws = await this.waitForOpenDeviceSocket(deviceId, 5000);
|
|
325
|
+
}
|
|
320
326
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
327
|
+
// Re-read in case a concurrent hello path touched the record.
|
|
328
|
+
const latest = await this.store.getPairedDevice(deviceId);
|
|
329
|
+
const tokenToSend = latest?.pairingToken || pairingToken;
|
|
330
|
+
if (latest && !latest.lastOnlineAt) {
|
|
331
|
+
await this.store.setPairedDevice(deviceId, {
|
|
332
|
+
...latest,
|
|
333
|
+
lastOnlineAt: now,
|
|
334
|
+
lastOfflineAt: undefined
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
this.sendPairingVerified(ws, deviceId, tokenToSend);
|
|
338
|
+
this.afterDevicePairedNotify(deviceId);
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
console.warn(`[TomorrowOS] pairing verified in store for ${deviceId}, but device socket not ready; will heal on next hello`);
|
|
334
342
|
}
|
|
335
343
|
this.emit("device.paired", { deviceId });
|
|
336
344
|
return { deviceId };
|
|
@@ -467,8 +475,8 @@ export class TomorrowOS extends EventEmitter {
|
|
|
467
475
|
return { deviceId: id, onOffTimer, pushed };
|
|
468
476
|
}
|
|
469
477
|
/**
|
|
470
|
-
* Clear the daily on/off timer
|
|
471
|
-
*
|
|
478
|
+
* Clear the daily on/off timer and push null to the device.
|
|
479
|
+
* Connected players drop the schedule and turn the screen back on.
|
|
472
480
|
*/
|
|
473
481
|
async clearDeviceOnOffTimer(deviceId) {
|
|
474
482
|
const id = String(deviceId || "").trim();
|
|
@@ -568,6 +576,48 @@ export class TomorrowOS extends EventEmitter {
|
|
|
568
576
|
const ws = this.devices.get(deviceId);
|
|
569
577
|
return !!ws && ws.readyState === WebSocket.OPEN;
|
|
570
578
|
}
|
|
579
|
+
/**
|
|
580
|
+
* Bind a live device socket. Never register a closed socket (avoids a late
|
|
581
|
+
* hello overwriting a healthy reconnect with a dead peer).
|
|
582
|
+
*/
|
|
583
|
+
bindDeviceSocket(deviceId, ws) {
|
|
584
|
+
if (ws.readyState !== WebSocket.OPEN)
|
|
585
|
+
return false;
|
|
586
|
+
ws.deviceId = deviceId;
|
|
587
|
+
this.devices.set(deviceId, ws);
|
|
588
|
+
return true;
|
|
589
|
+
}
|
|
590
|
+
/** Wait briefly for the device WebSocket to appear (first-pair hello races). */
|
|
591
|
+
async waitForOpenDeviceSocket(deviceId, timeoutMs = 5000) {
|
|
592
|
+
const deadline = Date.now() + timeoutMs;
|
|
593
|
+
for (;;) {
|
|
594
|
+
const ws = this.devices.get(deviceId);
|
|
595
|
+
if (ws && ws.readyState === WebSocket.OPEN)
|
|
596
|
+
return ws;
|
|
597
|
+
if (Date.now() >= deadline)
|
|
598
|
+
return undefined;
|
|
599
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
sendPairingVerified(ws, deviceId, pairingToken) {
|
|
603
|
+
if (ws.readyState !== WebSocket.OPEN)
|
|
604
|
+
return;
|
|
605
|
+
ws.send(JSON.stringify({
|
|
606
|
+
type: "pairing.verified",
|
|
607
|
+
method: "tomorrowos.pairing.verify",
|
|
608
|
+
deviceId,
|
|
609
|
+
pairingToken
|
|
610
|
+
}));
|
|
611
|
+
}
|
|
612
|
+
afterDevicePairedNotify(deviceId) {
|
|
613
|
+
void this.refreshPairedDeviceInfo(deviceId);
|
|
614
|
+
void this.pushLatestPolicyToDevice(deviceId).catch((err) => {
|
|
615
|
+
console.error("[TomorrowOS] pushLatestPolicy on paired failed:", err);
|
|
616
|
+
});
|
|
617
|
+
void this.pushOnOffTimerToDevice(deviceId).catch((err) => {
|
|
618
|
+
console.error("[TomorrowOS] pushOnOffTimer on paired failed:", err);
|
|
619
|
+
});
|
|
620
|
+
}
|
|
571
621
|
captureHelloMeta(deviceId, msg) {
|
|
572
622
|
const bootUptimeSec = parseBootUptimeSec(msg);
|
|
573
623
|
const platform = typeof msg.platform === "string" ? msg.platform : undefined;
|
|
@@ -1592,16 +1642,35 @@ export class TomorrowOS extends EventEmitter {
|
|
|
1592
1642
|
const serialNumber = typeof msg.serialNumber === "string" && msg.serialNumber.trim()
|
|
1593
1643
|
? msg.serialNumber.trim()
|
|
1594
1644
|
: deviceId;
|
|
1645
|
+
// Bind identity before await so close can reconcile, and so verify can
|
|
1646
|
+
// find this socket if pairing completes during registry I/O.
|
|
1647
|
+
ws.deviceId = deviceId;
|
|
1648
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
1649
|
+
this.devices.set(deviceId, ws);
|
|
1650
|
+
}
|
|
1595
1651
|
void (async () => {
|
|
1596
1652
|
try {
|
|
1597
1653
|
const code = await this.getOrCreatePermanentPairingCode(deviceId, serialNumber);
|
|
1654
|
+
if (!this.bindDeviceSocket(deviceId, ws)) {
|
|
1655
|
+
return;
|
|
1656
|
+
}
|
|
1598
1657
|
this.captureHelloMeta(deviceId, msg);
|
|
1599
|
-
|
|
1658
|
+
// Heal first-pair miss: CMS already paired but player never got
|
|
1659
|
+
// pairing.verified (socket missing at verify time). Send verified
|
|
1660
|
+
// instead of showing the pairing code again.
|
|
1661
|
+
const paired = await this.store.getPairedDevice(deviceId);
|
|
1662
|
+
if (paired?.pairingToken) {
|
|
1663
|
+
await this.touchPairedOnline(deviceId, msg);
|
|
1664
|
+
this.sendBrandSnapshot(ws);
|
|
1665
|
+
this.sendPairingVerified(ws, deviceId, paired.pairingToken);
|
|
1666
|
+
this.afterDevicePairedNotify(deviceId);
|
|
1667
|
+
this.emit("device.online", { deviceId });
|
|
1668
|
+
return;
|
|
1669
|
+
}
|
|
1600
1670
|
void this.store.setPendingCode(code, {
|
|
1601
1671
|
deviceId,
|
|
1602
1672
|
createdAt: Date.now()
|
|
1603
1673
|
});
|
|
1604
|
-
ws.deviceId = deviceId;
|
|
1605
1674
|
this.sendBrandSnapshot(ws);
|
|
1606
1675
|
ws.send(JSON.stringify({
|
|
1607
1676
|
type: "pairing.code",
|
|
@@ -1631,8 +1700,9 @@ export class TomorrowOS extends EventEmitter {
|
|
|
1631
1700
|
return;
|
|
1632
1701
|
}
|
|
1633
1702
|
this.captureHelloMeta(deviceId, msg);
|
|
1634
|
-
this.
|
|
1635
|
-
|
|
1703
|
+
if (!this.bindDeviceSocket(deviceId, ws)) {
|
|
1704
|
+
return;
|
|
1705
|
+
}
|
|
1636
1706
|
await this.touchPairedOnline(deviceId, msg);
|
|
1637
1707
|
ws.send(JSON.stringify({
|
|
1638
1708
|
type: "device.resumed",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tomorrowos/sdk",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.50",
|
|
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.
|
|
3
|
+
"version": "0.9.50",
|
|
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.
|
|
16
|
+
"@tomorrowos/sdk": "^0.9.50",
|
|
17
17
|
"dotenv": "^17.2.3",
|
|
18
18
|
"tsx": "^4.19.0"
|
|
19
19
|
},
|
|
@@ -187,7 +187,7 @@
|
|
|
187
187
|
<h2>On / off timer</h2>
|
|
188
188
|
<p class="hint" id="onOffTimerModalHint">
|
|
189
189
|
Daily on/off times follow the device clock. Off blacks the screen; the player stays powered and connected to the CMS.
|
|
190
|
-
Removing the timer
|
|
190
|
+
Removing the timer clears the schedule and turns the screen back on.
|
|
191
191
|
</p>
|
|
192
192
|
<div class="on-off-timer-grid">
|
|
193
193
|
<label class="field-label">
|
|
@@ -1999,7 +1999,7 @@ async function removeOnOffTimerModal() {
|
|
|
1999
1999
|
|
|
2000
2000
|
if (
|
|
2001
2001
|
!confirm(
|
|
2002
|
-
"Remove the on/off timer? The
|
|
2002
|
+
"Remove the on/off timer? The schedule will be cleared and the screen will turn back on."
|
|
2003
2003
|
)
|
|
2004
2004
|
) {
|
|
2005
2005
|
return;
|
|
@@ -187,7 +187,7 @@
|
|
|
187
187
|
<h2>On / off timer</h2>
|
|
188
188
|
<p class="hint" id="onOffTimerModalHint">
|
|
189
189
|
Daily on/off times follow the device clock. Off blacks the screen; the player stays powered and connected to the CMS.
|
|
190
|
-
Removing the timer
|
|
190
|
+
Removing the timer clears the schedule and turns the screen back on.
|
|
191
191
|
</p>
|
|
192
192
|
<div class="on-off-timer-grid">
|
|
193
193
|
<label class="field-label">
|
|
@@ -2000,7 +2000,7 @@ async function removeOnOffTimerModal() {
|
|
|
2000
2000
|
|
|
2001
2001
|
if (
|
|
2002
2002
|
!confirm(
|
|
2003
|
-
"Remove the on/off timer? The
|
|
2003
|
+
"Remove the on/off timer? The schedule will be cleared and the screen will turn back on."
|
|
2004
2004
|
)
|
|
2005
2005
|
) {
|
|
2006
2006
|
return;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-cms",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.50",
|
|
4
4
|
"description": "TomorrowOS CMS for Vercel / v0 Publish (Fluid Function + WebSockets + optional Next Preview).",
|
|
5
5
|
"private": true,
|
|
6
6
|
"type": "module",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"build-player": "tomorrowos build --platform tizen"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@tomorrowos/sdk": "^0.9.
|
|
20
|
+
"@tomorrowos/sdk": "^0.9.50",
|
|
21
21
|
"dotenv": "^17.2.3",
|
|
22
22
|
"tsx": "^4.19.0"
|
|
23
23
|
},
|