@glasshome/sync-layer 0.1.3 → 0.1.5
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/camera/fetch.d.ts +2 -1
- package/dist/demo/demo-provider.js +2 -101
- package/dist/{demo-data-Bir7Px_e.js → demo-data-gELwUOS_.js} +58 -4
- package/dist/demo-provider-I4BC9Woh.js +112 -0
- package/dist/index.js +13 -5
- package/dist/testing/index.js +1 -2
- package/package.json +2 -2
- package/dist/store-B1sbyexX.js +0 -54
- package/dist/types-CxMcKkJQ.js +0 -10
package/dist/camera/fetch.d.ts
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
import type { EntityId } from "../core/types";
|
|
7
7
|
import type { CameraStreamData, StreamFormat, StreamQueryOptions } from "./types";
|
|
8
8
|
/**
|
|
9
|
-
* Fetch stream for a camera entity
|
|
9
|
+
* Fetch stream for a camera entity.
|
|
10
|
+
* Returns a public demo HLS stream when not connected.
|
|
10
11
|
*/
|
|
11
12
|
export declare function fetchStream(entityId: EntityId, format?: StreamFormat): Promise<string | null>;
|
|
12
13
|
/**
|
|
@@ -1,103 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { createDemoFixtures } from "../demo-data-Bir7Px_e.js";
|
|
4
|
-
import { produce, reconcile } from "solid-js/store";
|
|
1
|
+
import { createDemoFixtures } from "../demo-data-gELwUOS_.js";
|
|
2
|
+
import { applyDemoServiceCall, isDemoMode, loadDemoData, unloadDemoData } from "../demo-provider-I4BC9Woh.js";
|
|
5
3
|
|
|
6
|
-
//#region src/demo/demo-provider.ts
|
|
7
|
-
let _isDemoMode = false;
|
|
8
|
-
/**
|
|
9
|
-
* Whether demo mode is currently active.
|
|
10
|
-
*/
|
|
11
|
-
function isDemoMode() {
|
|
12
|
-
return _isDemoMode;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Load demo fixtures into the SolidJS store.
|
|
16
|
-
*
|
|
17
|
-
* Populates entities, entity registry, areas, and devices.
|
|
18
|
-
* Sets connection state to "connected" (pretend connected).
|
|
19
|
-
*/
|
|
20
|
-
async function loadDemoData() {
|
|
21
|
-
const fixtures = createDemoFixtures();
|
|
22
|
-
setState("entities", reconcile(fixtures.entities));
|
|
23
|
-
setState("entityRegistry", reconcile(fixtures.entityRegistry));
|
|
24
|
-
setState("areas", reconcile(fixtures.areas));
|
|
25
|
-
setState("devices", reconcile(fixtures.devices));
|
|
26
|
-
setState("connectionState", "connected");
|
|
27
|
-
_isDemoMode = true;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Unload demo data and reset to disconnected state.
|
|
31
|
-
*/
|
|
32
|
-
function unloadDemoData() {
|
|
33
|
-
setState("entities", reconcile({}));
|
|
34
|
-
setState("entityRegistry", reconcile({}));
|
|
35
|
-
setState("areas", reconcile({}));
|
|
36
|
-
setState("devices", reconcile({}));
|
|
37
|
-
setState("connectionState", "disconnected");
|
|
38
|
-
_isDemoMode = false;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Apply an optimistic state update for demo mode.
|
|
42
|
-
*
|
|
43
|
-
* When a service call is made in demo mode, this updates the entity
|
|
44
|
-
* state locally (no WebSocket message sent). State resets on page refresh.
|
|
45
|
-
*/
|
|
46
|
-
function applyDemoServiceCall(domain, service, _serviceData = {}, target = {}) {
|
|
47
|
-
if (!_isDemoMode) return;
|
|
48
|
-
const entityIds = Array.isArray(target.entity_id) ? target.entity_id : target.entity_id ? [target.entity_id] : [];
|
|
49
|
-
for (const entityId of entityIds) {
|
|
50
|
-
const entity = state.entities[entityId];
|
|
51
|
-
if (!entity) continue;
|
|
52
|
-
const entityDomain = extractDomain(entityId);
|
|
53
|
-
setState(produce((s) => {
|
|
54
|
-
const e = s.entities[entityId];
|
|
55
|
-
if (!e) return;
|
|
56
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
57
|
-
e.last_changed = now;
|
|
58
|
-
e.last_updated = now;
|
|
59
|
-
if (service === "turn_on") applyTurnOn(e, entityDomain, _serviceData);
|
|
60
|
-
else if (service === "turn_off") applyTurnOff(e, entityDomain);
|
|
61
|
-
else if (service === "toggle") if (e.state === "on" || e.state === "playing" || e.state === "open") applyTurnOff(e, entityDomain);
|
|
62
|
-
else applyTurnOn(e, entityDomain, _serviceData);
|
|
63
|
-
else if (service === "lock") e.state = "locked";
|
|
64
|
-
else if (service === "unlock") e.state = "unlocked";
|
|
65
|
-
else if (service === "open_cover") {
|
|
66
|
-
e.state = "open";
|
|
67
|
-
e.attributes.current_position = 100;
|
|
68
|
-
} else if (service === "close_cover") {
|
|
69
|
-
e.state = "closed";
|
|
70
|
-
e.attributes.current_position = 0;
|
|
71
|
-
} else if (service === "set_cover_position" && _serviceData.position != null) {
|
|
72
|
-
e.attributes.current_position = _serviceData.position;
|
|
73
|
-
e.state = _serviceData.position > 0 ? "open" : "closed";
|
|
74
|
-
} else if (service === "set_temperature" && _serviceData.temperature != null) e.attributes.temperature = _serviceData.temperature;
|
|
75
|
-
else if (service === "set_hvac_mode" && _serviceData.hvac_mode != null) e.state = _serviceData.hvac_mode;
|
|
76
|
-
else if (service === "volume_set" && _serviceData.volume_level != null) e.attributes.volume_level = _serviceData.volume_level;
|
|
77
|
-
}));
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
function applyTurnOn(e, domain, serviceData = {}) {
|
|
81
|
-
if (domain === "light") {
|
|
82
|
-
e.state = "on";
|
|
83
|
-
e.attributes.brightness = serviceData.brightness ?? e.attributes.brightness ?? 255;
|
|
84
|
-
if (serviceData.color_temp_kelvin) e.attributes.color_temp_kelvin = serviceData.color_temp_kelvin;
|
|
85
|
-
} else if (domain === "media_player") e.state = "playing";
|
|
86
|
-
else if (domain === "cover") {
|
|
87
|
-
e.state = "open";
|
|
88
|
-
e.attributes.current_position = 100;
|
|
89
|
-
} else e.state = "on";
|
|
90
|
-
}
|
|
91
|
-
function applyTurnOff(e, domain) {
|
|
92
|
-
if (domain === "light") {
|
|
93
|
-
e.state = "off";
|
|
94
|
-
delete e.attributes.brightness;
|
|
95
|
-
} else if (domain === "media_player") e.state = "paused";
|
|
96
|
-
else if (domain === "cover") {
|
|
97
|
-
e.state = "closed";
|
|
98
|
-
e.attributes.current_position = 0;
|
|
99
|
-
} else e.state = "off";
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
//#endregion
|
|
103
4
|
export { applyDemoServiceCall, createDemoFixtures, isDemoMode, loadDemoData, unloadDemoData };
|
|
@@ -1,3 +1,56 @@
|
|
|
1
|
+
import { createStore, reconcile } from "solid-js/store";
|
|
2
|
+
|
|
3
|
+
//#region src/core/store.ts
|
|
4
|
+
const initialState = {
|
|
5
|
+
conn: null,
|
|
6
|
+
connectionState: "disconnected",
|
|
7
|
+
connectionError: null,
|
|
8
|
+
hassUrl: null,
|
|
9
|
+
entities: {},
|
|
10
|
+
entityRegistry: {},
|
|
11
|
+
devices: {},
|
|
12
|
+
areas: {},
|
|
13
|
+
floors: {},
|
|
14
|
+
labels: {},
|
|
15
|
+
statistics: {},
|
|
16
|
+
statisticsMetadata: {},
|
|
17
|
+
history: {},
|
|
18
|
+
forecasts: {},
|
|
19
|
+
streams: {}
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Module-level SolidJS createStore singleton
|
|
23
|
+
*
|
|
24
|
+
* `state` is a read-only reactive proxy.
|
|
25
|
+
* `setState` is used for mutations via produce() or direct path setting.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* import { state, setState } from '@glasshome/sync-layer/core/store';
|
|
30
|
+
*
|
|
31
|
+
* // Read state (auto-tracked in SolidJS reactive contexts)
|
|
32
|
+
* const entities = state.entities;
|
|
33
|
+
*
|
|
34
|
+
* // Mutate via produce
|
|
35
|
+
* setState(produce((s) => {
|
|
36
|
+
* s.entities['light.living_room'] = newEntity;
|
|
37
|
+
* }));
|
|
38
|
+
*
|
|
39
|
+
* // Bulk replace
|
|
40
|
+
* setState("entities", reconcile(newEntities));
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
const storeTuple = createStore(initialState);
|
|
44
|
+
const state = storeTuple[0];
|
|
45
|
+
const setState = storeTuple[1];
|
|
46
|
+
/**
|
|
47
|
+
* Reset store to initial state
|
|
48
|
+
*/
|
|
49
|
+
function resetStore() {
|
|
50
|
+
setState(reconcile(initialState));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
//#endregion
|
|
1
54
|
//#region src/demo/demo-data.ts
|
|
2
55
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3
56
|
let contextCounter = 0;
|
|
@@ -8,10 +61,10 @@ function ctx() {
|
|
|
8
61
|
user_id: null
|
|
9
62
|
};
|
|
10
63
|
}
|
|
11
|
-
function makeEntity(entity_id, state, attributes = {}) {
|
|
64
|
+
function makeEntity(entity_id, state$1, attributes = {}) {
|
|
12
65
|
return {
|
|
13
66
|
entity_id,
|
|
14
|
-
state,
|
|
67
|
+
state: state$1,
|
|
15
68
|
attributes: {
|
|
16
69
|
friendly_name: friendlyName(entity_id),
|
|
17
70
|
...attributes
|
|
@@ -363,7 +416,8 @@ function createDemoFixtures() {
|
|
|
363
416
|
}), { platform: "met" });
|
|
364
417
|
add(makeEntity("camera.front_door_camera", "streaming", {
|
|
365
418
|
entity_picture: "/api/camera_proxy/camera.front_door_camera",
|
|
366
|
-
frontend_stream_type: "hls"
|
|
419
|
+
frontend_stream_type: "hls",
|
|
420
|
+
access_token: "demo-token"
|
|
367
421
|
}), {
|
|
368
422
|
device_id: "camera_front",
|
|
369
423
|
area_id: "entry",
|
|
@@ -416,4 +470,4 @@ function createDemoFixtures() {
|
|
|
416
470
|
}
|
|
417
471
|
|
|
418
472
|
//#endregion
|
|
419
|
-
export { createDemoFixtures };
|
|
473
|
+
export { createDemoFixtures, resetStore, setState, state };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { createDemoFixtures, setState, state } from "./demo-data-gELwUOS_.js";
|
|
2
|
+
import { produce, reconcile } from "solid-js/store";
|
|
3
|
+
|
|
4
|
+
//#region src/core/types.ts
|
|
5
|
+
/**
|
|
6
|
+
* Extract domain from entity ID
|
|
7
|
+
*/
|
|
8
|
+
function extractDomain(entityId) {
|
|
9
|
+
return entityId.split(".")[0] ?? "";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/demo/demo-provider.ts
|
|
14
|
+
let _isDemoMode = false;
|
|
15
|
+
/**
|
|
16
|
+
* Whether demo mode is currently active.
|
|
17
|
+
*/
|
|
18
|
+
function isDemoMode() {
|
|
19
|
+
return _isDemoMode;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Load demo fixtures into the SolidJS store.
|
|
23
|
+
*
|
|
24
|
+
* Populates entities, entity registry, areas, and devices.
|
|
25
|
+
* Sets connection state to "connected" (pretend connected).
|
|
26
|
+
*/
|
|
27
|
+
async function loadDemoData() {
|
|
28
|
+
const fixtures = createDemoFixtures();
|
|
29
|
+
setState("entities", reconcile(fixtures.entities));
|
|
30
|
+
setState("entityRegistry", reconcile(fixtures.entityRegistry));
|
|
31
|
+
setState("areas", reconcile(fixtures.areas));
|
|
32
|
+
setState("devices", reconcile(fixtures.devices));
|
|
33
|
+
setState("hassUrl", "https://demo.home-assistant.local");
|
|
34
|
+
setState("connectionState", "connected");
|
|
35
|
+
_isDemoMode = true;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Unload demo data and reset to disconnected state.
|
|
39
|
+
*/
|
|
40
|
+
function unloadDemoData() {
|
|
41
|
+
setState("entities", reconcile({}));
|
|
42
|
+
setState("entityRegistry", reconcile({}));
|
|
43
|
+
setState("areas", reconcile({}));
|
|
44
|
+
setState("devices", reconcile({}));
|
|
45
|
+
setState("hassUrl", null);
|
|
46
|
+
setState("connectionState", "disconnected");
|
|
47
|
+
_isDemoMode = false;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Apply an optimistic state update for demo mode.
|
|
51
|
+
*
|
|
52
|
+
* When a service call is made in demo mode, this updates the entity
|
|
53
|
+
* state locally (no WebSocket message sent). State resets on page refresh.
|
|
54
|
+
*/
|
|
55
|
+
function applyDemoServiceCall(domain, service, _serviceData = {}, target = {}) {
|
|
56
|
+
if (!_isDemoMode) return;
|
|
57
|
+
const entityIds = Array.isArray(target.entity_id) ? target.entity_id : target.entity_id ? [target.entity_id] : [];
|
|
58
|
+
for (const entityId of entityIds) {
|
|
59
|
+
const entity = state.entities[entityId];
|
|
60
|
+
if (!entity) continue;
|
|
61
|
+
const entityDomain = extractDomain(entityId);
|
|
62
|
+
setState(produce((s) => {
|
|
63
|
+
const e = s.entities[entityId];
|
|
64
|
+
if (!e) return;
|
|
65
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
66
|
+
e.last_changed = now;
|
|
67
|
+
e.last_updated = now;
|
|
68
|
+
if (service === "turn_on") applyTurnOn(e, entityDomain, _serviceData);
|
|
69
|
+
else if (service === "turn_off") applyTurnOff(e, entityDomain);
|
|
70
|
+
else if (service === "toggle") if (e.state === "on" || e.state === "playing" || e.state === "open") applyTurnOff(e, entityDomain);
|
|
71
|
+
else applyTurnOn(e, entityDomain, _serviceData);
|
|
72
|
+
else if (service === "lock") e.state = "locked";
|
|
73
|
+
else if (service === "unlock") e.state = "unlocked";
|
|
74
|
+
else if (service === "open_cover") {
|
|
75
|
+
e.state = "open";
|
|
76
|
+
e.attributes.current_position = 100;
|
|
77
|
+
} else if (service === "close_cover") {
|
|
78
|
+
e.state = "closed";
|
|
79
|
+
e.attributes.current_position = 0;
|
|
80
|
+
} else if (service === "set_cover_position" && _serviceData.position != null) {
|
|
81
|
+
e.attributes.current_position = _serviceData.position;
|
|
82
|
+
e.state = _serviceData.position > 0 ? "open" : "closed";
|
|
83
|
+
} else if (service === "set_temperature" && _serviceData.temperature != null) e.attributes.temperature = _serviceData.temperature;
|
|
84
|
+
else if (service === "set_hvac_mode" && _serviceData.hvac_mode != null) e.state = _serviceData.hvac_mode;
|
|
85
|
+
else if (service === "volume_set" && _serviceData.volume_level != null) e.attributes.volume_level = _serviceData.volume_level;
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function applyTurnOn(e, domain, serviceData = {}) {
|
|
90
|
+
if (domain === "light") {
|
|
91
|
+
e.state = "on";
|
|
92
|
+
e.attributes.brightness = serviceData.brightness ?? e.attributes.brightness ?? 255;
|
|
93
|
+
if (serviceData.color_temp_kelvin) e.attributes.color_temp_kelvin = serviceData.color_temp_kelvin;
|
|
94
|
+
} else if (domain === "media_player") e.state = "playing";
|
|
95
|
+
else if (domain === "cover") {
|
|
96
|
+
e.state = "open";
|
|
97
|
+
e.attributes.current_position = 100;
|
|
98
|
+
} else e.state = "on";
|
|
99
|
+
}
|
|
100
|
+
function applyTurnOff(e, domain) {
|
|
101
|
+
if (domain === "light") {
|
|
102
|
+
e.state = "off";
|
|
103
|
+
delete e.attributes.brightness;
|
|
104
|
+
} else if (domain === "media_player") e.state = "paused";
|
|
105
|
+
else if (domain === "cover") {
|
|
106
|
+
e.state = "closed";
|
|
107
|
+
e.attributes.current_position = 0;
|
|
108
|
+
} else e.state = "off";
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
//#endregion
|
|
112
|
+
export { applyDemoServiceCall, extractDomain, isDemoMode, loadDemoData, unloadDemoData };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { resetStore, setState, state } from "./
|
|
2
|
-
import { extractDomain } from "./
|
|
1
|
+
import { resetStore, setState, state } from "./demo-data-gELwUOS_.js";
|
|
2
|
+
import { applyDemoServiceCall, extractDomain } from "./demo-provider-I4BC9Woh.js";
|
|
3
3
|
import { callService as callService$1, createConnection, createLongLivedTokenAuth, getAuth } from "home-assistant-js-websocket";
|
|
4
4
|
import { produce } from "solid-js/store";
|
|
5
5
|
|
|
@@ -402,7 +402,10 @@ async function refreshAuth(auth) {
|
|
|
402
402
|
*/
|
|
403
403
|
async function callService(domain, service, serviceData = {}, target = {}) {
|
|
404
404
|
const connection = state.conn;
|
|
405
|
-
if (!connection)
|
|
405
|
+
if (!connection) {
|
|
406
|
+
applyDemoServiceCall(domain, service, serviceData, target);
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
406
409
|
try {
|
|
407
410
|
const mockConnection = connection;
|
|
408
411
|
if (mockConnection && typeof mockConnection.callService === "function") await mockConnection.callService(domain, service, serviceData, target);
|
|
@@ -882,6 +885,7 @@ async function initConnection(options) {
|
|
|
882
885
|
const wrappedConn = wrapHAConnection(conn);
|
|
883
886
|
setState(produce((s) => {
|
|
884
887
|
s.conn = conn;
|
|
888
|
+
s.hassUrl = options.url.replace(/\/$/, "");
|
|
885
889
|
s.connectionState = "connected";
|
|
886
890
|
}));
|
|
887
891
|
setupEventHandlers(conn, options);
|
|
@@ -1638,10 +1642,14 @@ function entitiesWhere(predicate) {
|
|
|
1638
1642
|
|
|
1639
1643
|
//#endregion
|
|
1640
1644
|
//#region src/camera/fetch.ts
|
|
1645
|
+
/** Public HLS test stream for demo/disconnected mode */
|
|
1646
|
+
const DEMO_HLS_STREAM = "https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8";
|
|
1641
1647
|
/**
|
|
1642
|
-
* Fetch stream for a camera entity
|
|
1648
|
+
* Fetch stream for a camera entity.
|
|
1649
|
+
* Returns a public demo HLS stream when not connected.
|
|
1643
1650
|
*/
|
|
1644
1651
|
async function fetchStream(entityId, format = "hls") {
|
|
1652
|
+
if (!state.conn) return format === "hls" ? DEMO_HLS_STREAM : null;
|
|
1645
1653
|
const response = await sendCommand({
|
|
1646
1654
|
type: "camera/stream",
|
|
1647
1655
|
entity_id: entityId,
|
|
@@ -1761,7 +1769,7 @@ async function refreshStream(entityId, format = "hls") {
|
|
|
1761
1769
|
*/
|
|
1762
1770
|
async function getWebRtcClientConfig(entityId) {
|
|
1763
1771
|
const conn = state.conn;
|
|
1764
|
-
if (!conn) throw new Error("
|
|
1772
|
+
if (!conn) throw new Error("No connection available");
|
|
1765
1773
|
return conn.sendMessagePromise({
|
|
1766
1774
|
type: "camera/webrtc/get_client_config",
|
|
1767
1775
|
entity_id: entityId
|
package/dist/testing/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glasshome/sync-layer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Type-safe, reactive state synchronization layer for Home Assistant",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"./package.json": "./package.json"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@glasshome/ha-types": "
|
|
37
|
+
"@glasshome/ha-types": "0.1.0",
|
|
38
38
|
"solid-js": "^1.9.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependenciesMeta": {
|
package/dist/store-B1sbyexX.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { createStore, reconcile } from "solid-js/store";
|
|
2
|
-
|
|
3
|
-
//#region src/core/store.ts
|
|
4
|
-
const initialState = {
|
|
5
|
-
conn: null,
|
|
6
|
-
connectionState: "disconnected",
|
|
7
|
-
connectionError: null,
|
|
8
|
-
hassUrl: null,
|
|
9
|
-
entities: {},
|
|
10
|
-
entityRegistry: {},
|
|
11
|
-
devices: {},
|
|
12
|
-
areas: {},
|
|
13
|
-
floors: {},
|
|
14
|
-
labels: {},
|
|
15
|
-
statistics: {},
|
|
16
|
-
statisticsMetadata: {},
|
|
17
|
-
history: {},
|
|
18
|
-
forecasts: {},
|
|
19
|
-
streams: {}
|
|
20
|
-
};
|
|
21
|
-
/**
|
|
22
|
-
* Module-level SolidJS createStore singleton
|
|
23
|
-
*
|
|
24
|
-
* `state` is a read-only reactive proxy.
|
|
25
|
-
* `setState` is used for mutations via produce() or direct path setting.
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```typescript
|
|
29
|
-
* import { state, setState } from '@glasshome/sync-layer/core/store';
|
|
30
|
-
*
|
|
31
|
-
* // Read state (auto-tracked in SolidJS reactive contexts)
|
|
32
|
-
* const entities = state.entities;
|
|
33
|
-
*
|
|
34
|
-
* // Mutate via produce
|
|
35
|
-
* setState(produce((s) => {
|
|
36
|
-
* s.entities['light.living_room'] = newEntity;
|
|
37
|
-
* }));
|
|
38
|
-
*
|
|
39
|
-
* // Bulk replace
|
|
40
|
-
* setState("entities", reconcile(newEntities));
|
|
41
|
-
* ```
|
|
42
|
-
*/
|
|
43
|
-
const storeTuple = createStore(initialState);
|
|
44
|
-
const state = storeTuple[0];
|
|
45
|
-
const setState = storeTuple[1];
|
|
46
|
-
/**
|
|
47
|
-
* Reset store to initial state
|
|
48
|
-
*/
|
|
49
|
-
function resetStore() {
|
|
50
|
-
setState(reconcile(initialState));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
//#endregion
|
|
54
|
-
export { resetStore, setState, state };
|