@glasshome/sync-layer 0.1.0

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 (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +120 -0
  3. package/dist/area-views-B-m8vwce.js +321 -0
  4. package/dist/camera/fetch.d.ts +15 -0
  5. package/dist/camera/query.d.ts +15 -0
  6. package/dist/camera/types.d.ts +85 -0
  7. package/dist/camera/webrtc.d.ts +31 -0
  8. package/dist/commands/service.d.ts +53 -0
  9. package/dist/commands/types.d.ts +113 -0
  10. package/dist/connection/adapter.d.ts +48 -0
  11. package/dist/connection/auth.d.ts +126 -0
  12. package/dist/connection/manager.d.ts +42 -0
  13. package/dist/connection/subscriptions.d.ts +25 -0
  14. package/dist/connection/types.d.ts +161 -0
  15. package/dist/core/reducers.d.ts +99 -0
  16. package/dist/core/store.d.ts +64 -0
  17. package/dist/core/types.d.ts +336 -0
  18. package/dist/demo/demo-data.d.ts +24 -0
  19. package/dist/demo/demo-provider.d.ts +33 -0
  20. package/dist/demo/demo-provider.js +103 -0
  21. package/dist/demo-data-D8JXWRpw.js +419 -0
  22. package/dist/entities/area-views.d.ts +25 -0
  23. package/dist/entities/index.d.ts +54 -0
  24. package/dist/entities/views.d.ts +30 -0
  25. package/dist/history/constants.d.ts +16 -0
  26. package/dist/history/fetch.d.ts +19 -0
  27. package/dist/history/query.d.ts +13 -0
  28. package/dist/history/types.d.ts +146 -0
  29. package/dist/index.d.ts +38 -0
  30. package/dist/index.js +1747 -0
  31. package/dist/query/area-builder.d.ts +25 -0
  32. package/dist/query/builder.d.ts +18 -0
  33. package/dist/query/helpers.d.ts +21 -0
  34. package/dist/query/memoization.d.ts +18 -0
  35. package/dist/query/projections.d.ts +74 -0
  36. package/dist/query/types.d.ts +260 -0
  37. package/dist/solid/hooks.d.ts +88 -0
  38. package/dist/solid/index.d.ts +10 -0
  39. package/dist/solid/index.js +176 -0
  40. package/dist/solid/indices.d.ts +14 -0
  41. package/dist/store-B1sbyexX.js +54 -0
  42. package/dist/testing/fixtures.d.ts +161 -0
  43. package/dist/testing/helpers.d.ts +160 -0
  44. package/dist/testing/index.d.ts +13 -0
  45. package/dist/testing/index.js +2047 -0
  46. package/dist/testing/mock-behaviors/base.d.ts +73 -0
  47. package/dist/testing/mock-behaviors/climate.d.ts +22 -0
  48. package/dist/testing/mock-behaviors/cover.d.ts +22 -0
  49. package/dist/testing/mock-behaviors/index.d.ts +11 -0
  50. package/dist/testing/mock-behaviors/light.d.ts +20 -0
  51. package/dist/testing/mock-behaviors/lock.d.ts +20 -0
  52. package/dist/testing/mock-behaviors/media_player.d.ts +42 -0
  53. package/dist/testing/mock-behaviors/registry.d.ts +55 -0
  54. package/dist/testing/mock-behaviors/switch.d.ts +17 -0
  55. package/dist/testing/mock.d.ts +191 -0
  56. package/dist/testing/types.d.ts +87 -0
  57. package/dist/types-Csog0nqk.js +10 -0
  58. package/dist/weather/fetch.d.ts +19 -0
  59. package/dist/weather/query.d.ts +23 -0
  60. package/dist/weather/types.d.ts +126 -0
  61. package/package.json +85 -0
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Command types
3
+ *
4
+ * Type definitions for service calls and commands.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ import type { Domain, ServiceCall, ServiceName, WsCommandType } from "@glasshome/ha-types";
9
+ import type { EntityId } from "../core/types";
10
+ /**
11
+ * Service call options
12
+ */
13
+ export interface ServiceCallOptions {
14
+ /** Entity ID or array of entity IDs to target */
15
+ entity_id?: EntityId | EntityId[];
16
+ /** Area ID or array of area IDs to target */
17
+ area_id?: string | string[];
18
+ /** Device ID or array of device IDs to target */
19
+ device_id?: string | string[];
20
+ }
21
+ /**
22
+ * Service call target
23
+ *
24
+ * Defines what entities the service call should affect
25
+ */
26
+ export interface ServiceTarget {
27
+ /** Entity IDs */
28
+ entity_id?: string | string[];
29
+ /** Device IDs */
30
+ device_id?: string | string[];
31
+ /** Area IDs */
32
+ area_id?: string | string[];
33
+ }
34
+ /**
35
+ * Service call with full context
36
+ */
37
+ export interface ServiceCallContext {
38
+ /** Domain (e.g., "light", "switch") */
39
+ domain: Domain;
40
+ /** Service name (e.g., "turn_on", "toggle") */
41
+ service: ServiceName<Domain>;
42
+ /** Service data */
43
+ serviceData?: ServiceCall<Domain, ServiceName<Domain>>;
44
+ /** Target entities/devices/areas */
45
+ target?: ServiceTarget;
46
+ }
47
+ /**
48
+ * Command success result
49
+ */
50
+ export interface CommandSuccess<T = unknown> {
51
+ success: true;
52
+ result: T;
53
+ }
54
+ /**
55
+ * Command error result
56
+ */
57
+ export interface CommandError {
58
+ success: false;
59
+ error: {
60
+ code: string;
61
+ message: string;
62
+ };
63
+ }
64
+ /**
65
+ * Command result (success or error)
66
+ */
67
+ export type CommandResult<T = unknown> = CommandSuccess<T> | CommandError;
68
+ /**
69
+ * Entity registry update fields
70
+ *
71
+ * Fields that can be updated in the entity registry
72
+ */
73
+ export interface EntityUpdateFields {
74
+ /** Friendly name */
75
+ name?: string;
76
+ /** Icon */
77
+ icon?: string;
78
+ /** Area ID */
79
+ area_id?: string | null;
80
+ /** Disabled by (null to enable) */
81
+ disabled_by?: string | null;
82
+ /** Hidden by (null to unhide) */
83
+ hidden_by?: string | null;
84
+ }
85
+ /**
86
+ * Entity registry update request
87
+ */
88
+ export interface EntityUpdateRequest {
89
+ /** Entity ID to update */
90
+ entity_id: EntityId;
91
+ /** Fields to update */
92
+ updates: EntityUpdateFields;
93
+ }
94
+ /**
95
+ * Generic WebSocket command
96
+ */
97
+ export interface GenericCommand {
98
+ /** Command type */
99
+ type: WsCommandType | string;
100
+ /** Command payload */
101
+ [key: string]: unknown;
102
+ }
103
+ /**
104
+ * Command execution options
105
+ */
106
+ export interface CommandOptions {
107
+ /** Timeout in milliseconds */
108
+ timeout?: number;
109
+ /** Retry on failure */
110
+ retry?: boolean;
111
+ /** Number of retry attempts */
112
+ retries?: number;
113
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * HA Connection Adapter
3
+ *
4
+ * Wraps home-assistant-js-websocket Connection to SyncLayerConnection interface.
5
+ * This allows seamless swapping between mock and real connections.
6
+ *
7
+ * Debug listeners intercept messages at the adapter boundary:
8
+ * - Outgoing: fired from sendMessagePromise, subscribeMessage, subscribeEvents
9
+ * - Incoming: fired from subscribeMessage/subscribeEvents callbacks and sendMessagePromise responses
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ import type { Connection } from "home-assistant-js-websocket";
14
+ import type { SyncLayerConnection } from "./types";
15
+ /**
16
+ * Register a listener for all outgoing WebSocket messages.
17
+ * Returns an unsubscribe function.
18
+ *
19
+ * @param listener - Function called with each outgoing message object
20
+ * @returns Unsubscribe function to remove the listener
21
+ */
22
+ export declare function addDebugOutgoingMessageListener(listener: (message: any) => void): () => void;
23
+ /**
24
+ * Register a listener for all incoming WebSocket messages.
25
+ * Returns an unsubscribe function. Receives subscription updates,
26
+ * event callbacks, and sendMessagePromise responses.
27
+ *
28
+ * @param listener - Function called with each incoming message object
29
+ * @returns Unsubscribe function to remove the listener
30
+ */
31
+ export declare function addDebugIncomingMessageListener(listener: (message: any) => void): () => void;
32
+ /**
33
+ * Wrap HA Connection to SyncLayerConnection interface
34
+ *
35
+ * This adapter makes the real HA Connection compatible with our unified interface,
36
+ * allowing it to be used interchangeably with MockConnection.
37
+ *
38
+ * @param conn - Home Assistant WebSocket connection
39
+ * @returns Wrapped connection implementing SyncLayerConnection
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * const haConn = await createConnection({ auth });
44
+ * const wrappedConn = wrapHAConnection(haConn);
45
+ * await syncLayer.connect({ connection: wrappedConn });
46
+ * ```
47
+ */
48
+ export declare function wrapHAConnection(conn: Connection): SyncLayerConnection;
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Authentication Helpers
3
+ *
4
+ * Provides OAuth and token-based authentication for Home Assistant connections.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ import { type Auth } from "home-assistant-js-websocket";
9
+ /**
10
+ * Options for OAuth authentication flow
11
+ */
12
+ export interface OAuthOptions {
13
+ /**
14
+ * Home Assistant instance URL
15
+ * (e.g., "https://homeassistant.local:8123")
16
+ */
17
+ url: string;
18
+ /**
19
+ * Client ID for OAuth
20
+ * Typically the same as the Home Assistant URL
21
+ */
22
+ clientId: string;
23
+ /**
24
+ * Redirect URI after OAuth authorization
25
+ * (e.g., "https://myapp.com/auth/callback")
26
+ */
27
+ redirectUri?: string;
28
+ /**
29
+ * Optional authorization code if already obtained
30
+ * If provided, will be used directly instead of starting OAuth flow
31
+ */
32
+ authCode?: string;
33
+ /**
34
+ * Optional function to get authorization code
35
+ * If provided, will be called to get the code before token exchange
36
+ */
37
+ getAuthCode?: () => Promise<string>;
38
+ /**
39
+ * Optional function to save auth data
40
+ * Useful for persisting auth tokens
41
+ */
42
+ saveAuth?: (auth: Auth) => void | Promise<void>;
43
+ /**
44
+ * Optional function to load saved auth data
45
+ */
46
+ loadAuth?: () => Promise<Auth | null>;
47
+ /**
48
+ * Optional flag to limit to specific Home Assistant instance
49
+ */
50
+ limitHassInstance?: boolean;
51
+ }
52
+ /**
53
+ * Authenticate using OAuth flow
54
+ *
55
+ * This function uses `getAuth` from `home-assistant-js-websocket` which:
56
+ * 1. Opens Home Assistant authorization page in a popup
57
+ * 2. Waits for user authorization
58
+ * 3. Exchanges authorization code for tokens
59
+ * 4. Returns authenticated Auth object
60
+ *
61
+ * Note: For a complete OAuth flow, you typically need to:
62
+ * - Set up a redirect URI endpoint in your app
63
+ * - Handle the OAuth callback with the authorization code
64
+ * - Use `getAuthCode` callback to provide the code
65
+ *
66
+ * Alternatively, `getAuth` can automatically handle the flow in browser environments
67
+ * by opening a popup and listening for the callback.
68
+ *
69
+ * @param options - OAuth options
70
+ * @returns Authenticated Auth object
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * // Basic OAuth flow (browser only)
75
+ * const auth = await authenticateWithOAuth({
76
+ * url: 'https://homeassistant.local:8123',
77
+ * clientId: 'https://homeassistant.local:8123',
78
+ * redirectUri: 'https://myapp.com/auth/callback',
79
+ * });
80
+ * ```
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * // OAuth with custom code handling
85
+ * const auth = await authenticateWithOAuth({
86
+ * url: 'https://homeassistant.local:8123',
87
+ * clientId: 'https://homeassistant.local:8123',
88
+ * redirectUri: 'https://myapp.com/auth/callback',
89
+ * getAuthCode: async () => {
90
+ * // Wait for user to authorize and get code from callback
91
+ * return await waitForAuthCode();
92
+ * },
93
+ * });
94
+ * ```
95
+ */
96
+ export declare function authenticateWithOAuth(options: OAuthOptions): Promise<Auth>;
97
+ /**
98
+ * Authenticate using a long-lived token
99
+ *
100
+ * @param url - Home Assistant instance URL
101
+ * @param token - Long-lived access token
102
+ * @returns Authenticated Auth object
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * const auth = authenticateWithToken(
107
+ * 'https://homeassistant.local:8123',
108
+ * 'your_long_lived_token'
109
+ * );
110
+ * ```
111
+ */
112
+ export declare function authenticateWithToken(url: string, token: string): Auth;
113
+ /**
114
+ * Check if auth object is valid
115
+ *
116
+ * @param auth - Auth object to check
117
+ * @returns True if auth is valid
118
+ */
119
+ export declare function isAuthValid(auth: Auth): Promise<boolean>;
120
+ /**
121
+ * Refresh auth tokens
122
+ *
123
+ * @param auth - Auth object to refresh
124
+ * @returns Refreshed Auth object
125
+ */
126
+ export declare function refreshAuth(auth: Auth): Promise<Auth>;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Connection Manager
3
+ *
4
+ * Handles WebSocket connection lifecycle, authentication,
5
+ * and initial data loading.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ import { type Auth, type Connection, type ConnectionOptions as HAConnectionOptions } from "home-assistant-js-websocket";
10
+ import { type OAuthOptions } from "./auth";
11
+ /**
12
+ * Options for initializing a connection
13
+ */
14
+ export interface ConnectionOptions {
15
+ url: string;
16
+ auth: Auth | string | OAuthOptions;
17
+ createSocket?: HAConnectionOptions["createSocket"];
18
+ onConnect?: () => void;
19
+ onDisconnect?: () => void;
20
+ onReconnect?: () => void;
21
+ onError?: (error: Error) => void;
22
+ }
23
+ /**
24
+ * Initialize connection to Home Assistant
25
+ */
26
+ export declare function initConnection(options: ConnectionOptions): Promise<Connection>;
27
+ /**
28
+ * Disconnect from Home Assistant
29
+ */
30
+ export declare function disconnect(): void;
31
+ /**
32
+ * Get current connection
33
+ */
34
+ export declare function getConnection(): Connection | null;
35
+ /**
36
+ * Check if currently connected
37
+ */
38
+ export declare function isConnected(): boolean;
39
+ /**
40
+ * Refresh all data
41
+ */
42
+ export declare function refreshData(): Promise<void>;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Event Subscriptions
3
+ *
4
+ * Sets up WebSocket event subscriptions to keep state in sync
5
+ * with Home Assistant.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ import type { SyncLayerConnection } from "./types";
10
+ /**
11
+ * Subscribe to all relevant events from Home Assistant
12
+ */
13
+ export declare function subscribeToUpdates(conn: SyncLayerConnection): Promise<void>;
14
+ /**
15
+ * Clean up all active subscriptions
16
+ */
17
+ export declare function cleanupSubscriptions(): Promise<void>;
18
+ /**
19
+ * Check if subscriptions are active
20
+ */
21
+ export declare function hasActiveSubscriptions(): boolean;
22
+ /**
23
+ * Get number of active subscriptions
24
+ */
25
+ export declare function getSubscriptionCount(): number;
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Connection Interface Types
3
+ *
4
+ * Defines the unified interface for both mock and real Home Assistant connections.
5
+ * This allows seamless swapping between test and production connections.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ import type { HAEvent } from "@glasshome/ha-types";
10
+ import type { Fixtures } from "../testing/types";
11
+ /**
12
+ * Unified connection interface for Home Assistant connections
13
+ *
14
+ * This interface is implemented by both:
15
+ * - MockConnection (for testing)
16
+ * - Wrapped HA Connection (for production)
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * // In tests
21
+ * const mockConn: SyncLayerConnection = new MockConnection(fixtures);
22
+ * await syncLayer.connect({ connection: mockConn });
23
+ *
24
+ * // In production
25
+ * const haConn = await createConnection({ auth });
26
+ * const wrappedConn: SyncLayerConnection = wrapHAConnection(haConn);
27
+ * await syncLayer.connect({ connection: wrappedConn });
28
+ * ```
29
+ */
30
+ export interface SyncLayerConnection {
31
+ /**
32
+ * Connect to Home Assistant (or mock)
33
+ *
34
+ * Establishes the WebSocket connection. For real HA connections,
35
+ * this is called automatically by createConnection. For mock connections,
36
+ * this simulates the connection process.
37
+ *
38
+ * @returns Promise that resolves when connection is established
39
+ */
40
+ connect(): Promise<void>;
41
+ /**
42
+ * Disconnect from Home Assistant
43
+ *
44
+ * Closes the WebSocket connection and cleans up resources.
45
+ */
46
+ disconnect(): void;
47
+ /**
48
+ * Check if connection is currently active
49
+ *
50
+ * @returns true if connected, false otherwise
51
+ */
52
+ get connected$(): boolean;
53
+ /**
54
+ * Authenticate with Home Assistant
55
+ *
56
+ * Sends authentication credentials. For real HA connections,
57
+ * authentication is handled during connection creation. For mock connections,
58
+ * this simulates the authentication process.
59
+ *
60
+ * @param accessToken - Access token for authentication
61
+ * @returns Promise that resolves when authentication completes
62
+ */
63
+ authenticate(accessToken: string): Promise<void>;
64
+ /**
65
+ * Get current authentication state
66
+ *
67
+ * @returns Authentication state: "pending", "authenticated", or "failed"
68
+ */
69
+ get authState(): "pending" | "authenticated" | "failed";
70
+ /**
71
+ * Subscribe to Home Assistant events
72
+ *
73
+ * Registers a callback to receive events of a specific type (or all events).
74
+ *
75
+ * @param callback - Function called when events are received
76
+ * @param eventType - Optional event type filter (e.g., "entity_registry_updated")
77
+ * @returns Promise resolving to unsubscribe function
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * const unsubscribe = await connection.subscribeEvents((event) => {
82
+ * console.log("Event received:", event);
83
+ * }, "entity_registry_updated");
84
+ *
85
+ * // Later, unsubscribe
86
+ * await unsubscribe();
87
+ * ```
88
+ */
89
+ subscribeEvents(callback: (event: HAEvent<any>) => void, eventType?: string): Promise<() => void>;
90
+ /**
91
+ * Subscribe to message stream
92
+ *
93
+ * Used for streaming subscriptions like history/stream.
94
+ * Sends a subscription message and receives streaming responses.
95
+ *
96
+ * @param callback - Function called when messages are received
97
+ * @param message - Subscription message (e.g., { type: "history/stream", ... })
98
+ * @returns Promise resolving to unsubscribe function
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * const unsubscribe = await connection.subscribeMessage((message) => {
103
+ * console.log("Stream message:", message);
104
+ * }, {
105
+ * type: "history/stream",
106
+ * entity_ids: ["sensor.temperature"],
107
+ * start_time: startTime.toISOString(),
108
+ * });
109
+ *
110
+ * // Later, unsubscribe
111
+ * await unsubscribe();
112
+ * ```
113
+ */
114
+ subscribeMessage<T>(callback: (message: T) => void, message: any): Promise<() => Promise<void>>;
115
+ /**
116
+ * Send a message and wait for response
117
+ *
118
+ * Sends a WebSocket message and returns a promise that resolves
119
+ * with the response.
120
+ *
121
+ * @param message - Message to send
122
+ * @returns Promise resolving to the response data
123
+ *
124
+ * @example
125
+ * ```typescript
126
+ * const states = await connection.sendMessagePromise({
127
+ * type: "get_states",
128
+ * });
129
+ * ```
130
+ */
131
+ sendMessagePromise<T>(message: any): Promise<T>;
132
+ /**
133
+ * Add event listener for WebSocket messages
134
+ *
135
+ * Registers a handler for all WebSocket messages (not just events).
136
+ * Useful for listening to auth messages, connection status, etc.
137
+ *
138
+ * @param handler - Function called when any message is received
139
+ * @returns Unsubscribe function
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * const unsubscribe = connection.addEventListener((message) => {
144
+ * console.log("Any message:", message);
145
+ * });
146
+ *
147
+ * // Later, unsubscribe
148
+ * unsubscribe();
149
+ * ```
150
+ */
151
+ addEventListener(handler: (message: any) => void): () => void;
152
+ /**
153
+ * Get fixtures (MockConnection only)
154
+ *
155
+ * Returns the fixture data for mock connections. SyncLayer uses this
156
+ * to load fixtures into its store during connection setup.
157
+ *
158
+ * @returns Fixture data (entities, registries, etc.)
159
+ */
160
+ getFixtures?(): Fixtures;
161
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * State update reducers
3
+ *
4
+ * These functions handle state updates in response to events from
5
+ * Home Assistant. They use SolidJS store's produce() for safe mutations.
6
+ *
7
+ * NOTE: All index maintenance code has been stripped.
8
+ * Indices are derived reactively in Plan 03.
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ import type { EntityRegistryEntry } from "@glasshome/ha-types";
13
+ import type { AreaRegistryEntry, DeviceRegistryEntry, EntityId, FloorRegistryEntry, HassEntity, LabelRegistryEntry, StatisticData, StatisticMetadata } from "./types";
14
+ /**
15
+ * Bulk update multiple entities
16
+ *
17
+ * Used during initial load or bulk sync operations.
18
+ *
19
+ * @param entities - Array of entity states
20
+ */
21
+ export declare function bulkUpdateEntities(entities: HassEntity[]): void;
22
+ /**
23
+ * Update entity registry entry
24
+ *
25
+ * @param entry - Entity registry entry
26
+ */
27
+ export declare function updateEntityRegistry(entry: EntityRegistryEntry): void;
28
+ /**
29
+ * Remove entity registry entry
30
+ *
31
+ * @param entityId - Entity ID to remove
32
+ */
33
+ export declare function removeEntityRegistry(entityId: EntityId): void;
34
+ /**
35
+ * Bulk update entity registry
36
+ *
37
+ * @param entries - Array of registry entries
38
+ */
39
+ export declare function bulkUpdateEntityRegistry(entries: EntityRegistryEntry[]): void;
40
+ /**
41
+ * Update device registry entry
42
+ *
43
+ * @param device - Device registry entry
44
+ */
45
+ export declare function updateDevice(device: DeviceRegistryEntry): void;
46
+ /**
47
+ * Remove device registry entry
48
+ *
49
+ * @param deviceId - Device ID to remove
50
+ */
51
+ export declare function removeDevice(deviceId: string): void;
52
+ /**
53
+ * Update area registry entry
54
+ *
55
+ * @param area - Area registry entry
56
+ */
57
+ export declare function updateArea(area: AreaRegistryEntry): void;
58
+ /**
59
+ * Remove area registry entry
60
+ *
61
+ * @param areaId - Area ID to remove
62
+ */
63
+ export declare function removeArea(areaId: string): void;
64
+ /**
65
+ * Update floor registry entry
66
+ *
67
+ * @param floor - Floor registry entry
68
+ */
69
+ export declare function updateFloor(floor: FloorRegistryEntry): void;
70
+ /**
71
+ * Remove floor registry entry
72
+ *
73
+ * @param floorId - Floor ID to remove
74
+ */
75
+ export declare function removeFloor(floorId: string): void;
76
+ /**
77
+ * Update label registry entry
78
+ *
79
+ * @param label - Label registry entry
80
+ */
81
+ export declare function updateLabel(label: LabelRegistryEntry): void;
82
+ /**
83
+ * Remove label registry entry
84
+ *
85
+ * @param labelId - Label ID to remove
86
+ */
87
+ export declare function removeLabel(labelId: string): void;
88
+ /**
89
+ * Update statistics metadata
90
+ *
91
+ * @param metadata - Statistics metadata
92
+ */
93
+ export declare function updateStatisticsMetadata(metadata: StatisticMetadata[]): void;
94
+ /**
95
+ * Update statistics data
96
+ *
97
+ * @param data - Statistics data points
98
+ */
99
+ export declare function updateStatisticsData(data: StatisticData[]): void;
@@ -0,0 +1,64 @@
1
+ /** Central reactive state store for sync-layer using SolidJS createStore. */
2
+ import type { Connection } from "home-assistant-js-websocket";
3
+ import type { SetStoreFunction, Store } from "solid-js/store";
4
+ import type { CameraStreamData } from "../camera/types";
5
+ import type { EntityHistoryData } from "../history/types";
6
+ import type { WeatherForecastsData } from "../weather/types";
7
+ import type { AreaId, AreaRegistryEntry, ConnectionState, DeviceId, DeviceRegistryEntry, EntityId, FloorId, FloorRegistryEntry, HassEntity, LabelId, LabelRegistryEntry, StatisticData, StatisticMetadata } from "./types";
8
+ /**
9
+ * Complete state shape for the sync-layer store
10
+ *
11
+ * All updates use SolidJS store's produce() for mutations
12
+ * or reconcile() for bulk replacements.
13
+ *
14
+ * NOTE: No EntityIndices field -- indices are derived reactively in Plan 03.
15
+ * NOTE: No _activeSubscriptions -- managed externally.
16
+ */
17
+ export interface GlassHomeState {
18
+ /** WebSocket connection instance */
19
+ conn: Connection | null;
20
+ /** Current connection state */
21
+ connectionState: ConnectionState;
22
+ /** Connection error (if any) */
23
+ connectionError: Error | null;
24
+ /** Home Assistant base URL */
25
+ hassUrl: string | null;
26
+ /** Live entity state (keyed by entity_id) */
27
+ entities: Record<EntityId, HassEntity>;
28
+ /** Entity registry entries (keyed by entity_id) */
29
+ entityRegistry: Record<EntityId, import("@glasshome/ha-types").EntityRegistryEntry>;
30
+ /** Device registry entries (keyed by device ID) */
31
+ devices: Record<DeviceId, DeviceRegistryEntry>;
32
+ /** Area registry entries (keyed by area ID) */
33
+ areas: Record<AreaId, AreaRegistryEntry>;
34
+ /** Floor registry entries (keyed by floor ID) */
35
+ floors: Record<FloorId, FloorRegistryEntry>;
36
+ /** Label registry entries (keyed by label ID) */
37
+ labels: Record<LabelId, LabelRegistryEntry>;
38
+ /** Statistics data (keyed by statistic_id) */
39
+ statistics: Record<string, StatisticData[]>;
40
+ /** Statistics metadata (keyed by statistic_id) */
41
+ statisticsMetadata: Record<string, StatisticMetadata>;
42
+ /** Entity history data (keyed by entity ID) */
43
+ history: Record<EntityId, EntityHistoryData>;
44
+ /** Weather forecasts data (keyed by entity ID) */
45
+ forecasts: Record<EntityId, WeatherForecastsData>;
46
+ /** Camera stream data (keyed by entity ID) */
47
+ streams: Record<EntityId, CameraStreamData>;
48
+ }
49
+ export declare const state: Store<GlassHomeState>;
50
+ export declare const setState: SetStoreFunction<GlassHomeState>;
51
+ /**
52
+ * Reset store to initial state
53
+ */
54
+ export declare function resetStore(): void;
55
+ /**
56
+ * Factory for testing isolation
57
+ *
58
+ * Creates a new, independent store instance for test isolation.
59
+ */
60
+ export declare function createStoreInstance(): [GlassHomeState, SetStoreFunction<GlassHomeState>];
61
+ /**
62
+ * Store tuple type for dependency injection
63
+ */
64
+ export type Store = [get: GlassHomeState, set: SetStoreFunction<GlassHomeState>];