@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.
- package/LICENSE +21 -0
- package/README.md +120 -0
- package/dist/area-views-B-m8vwce.js +321 -0
- package/dist/camera/fetch.d.ts +15 -0
- package/dist/camera/query.d.ts +15 -0
- package/dist/camera/types.d.ts +85 -0
- package/dist/camera/webrtc.d.ts +31 -0
- package/dist/commands/service.d.ts +53 -0
- package/dist/commands/types.d.ts +113 -0
- package/dist/connection/adapter.d.ts +48 -0
- package/dist/connection/auth.d.ts +126 -0
- package/dist/connection/manager.d.ts +42 -0
- package/dist/connection/subscriptions.d.ts +25 -0
- package/dist/connection/types.d.ts +161 -0
- package/dist/core/reducers.d.ts +99 -0
- package/dist/core/store.d.ts +64 -0
- package/dist/core/types.d.ts +336 -0
- package/dist/demo/demo-data.d.ts +24 -0
- package/dist/demo/demo-provider.d.ts +33 -0
- package/dist/demo/demo-provider.js +103 -0
- package/dist/demo-data-D8JXWRpw.js +419 -0
- package/dist/entities/area-views.d.ts +25 -0
- package/dist/entities/index.d.ts +54 -0
- package/dist/entities/views.d.ts +30 -0
- package/dist/history/constants.d.ts +16 -0
- package/dist/history/fetch.d.ts +19 -0
- package/dist/history/query.d.ts +13 -0
- package/dist/history/types.d.ts +146 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +1747 -0
- package/dist/query/area-builder.d.ts +25 -0
- package/dist/query/builder.d.ts +18 -0
- package/dist/query/helpers.d.ts +21 -0
- package/dist/query/memoization.d.ts +18 -0
- package/dist/query/projections.d.ts +74 -0
- package/dist/query/types.d.ts +260 -0
- package/dist/solid/hooks.d.ts +88 -0
- package/dist/solid/index.d.ts +10 -0
- package/dist/solid/index.js +176 -0
- package/dist/solid/indices.d.ts +14 -0
- package/dist/store-B1sbyexX.js +54 -0
- package/dist/testing/fixtures.d.ts +161 -0
- package/dist/testing/helpers.d.ts +160 -0
- package/dist/testing/index.d.ts +13 -0
- package/dist/testing/index.js +2047 -0
- package/dist/testing/mock-behaviors/base.d.ts +73 -0
- package/dist/testing/mock-behaviors/climate.d.ts +22 -0
- package/dist/testing/mock-behaviors/cover.d.ts +22 -0
- package/dist/testing/mock-behaviors/index.d.ts +11 -0
- package/dist/testing/mock-behaviors/light.d.ts +20 -0
- package/dist/testing/mock-behaviors/lock.d.ts +20 -0
- package/dist/testing/mock-behaviors/media_player.d.ts +42 -0
- package/dist/testing/mock-behaviors/registry.d.ts +55 -0
- package/dist/testing/mock-behaviors/switch.d.ts +17 -0
- package/dist/testing/mock.d.ts +191 -0
- package/dist/testing/types.d.ts +87 -0
- package/dist/types-Csog0nqk.js +10 -0
- package/dist/weather/fetch.d.ts +19 -0
- package/dist/weather/query.d.ts +23 -0
- package/dist/weather/types.d.ts +126 -0
- package/package.json +85 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Area Query Builder
|
|
3
|
+
*
|
|
4
|
+
* Fluent API for filtering and querying areas.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
import type { AreaId, AreaView, Callback, FloorId, LabelId, PredicateFunc, UnsubscribeFunc } from "../core/types";
|
|
9
|
+
export interface AreaQueryBuilder {
|
|
10
|
+
byFloor(floorId: FloorId): AreaQueryBuilder;
|
|
11
|
+
byLabel(labelId: LabelId): AreaQueryBuilder;
|
|
12
|
+
where(predicate: PredicateFunc<AreaView>): AreaQueryBuilder;
|
|
13
|
+
orderBy(key: keyof AreaView | string, direction?: "asc" | "desc"): AreaQueryBuilder;
|
|
14
|
+
get(): AreaView[];
|
|
15
|
+
first(): AreaView | undefined;
|
|
16
|
+
subscribe(callback: Callback<AreaView[]>): UnsubscribeFunc;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create a query builder for areas
|
|
20
|
+
*/
|
|
21
|
+
export declare function areas(): AreaQueryBuilder;
|
|
22
|
+
/**
|
|
23
|
+
* Create a query for a single area
|
|
24
|
+
*/
|
|
25
|
+
export declare function area(areaId: AreaId): AreaView | undefined;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query Builder
|
|
3
|
+
*
|
|
4
|
+
* Fluent API for filtering, sorting, projecting, and subscribing to entities.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
import type { EntityId, EntityView } from "../core/types";
|
|
9
|
+
import type { EntitiesQueryBuilder, EntityQueryBuilder } from "./types";
|
|
10
|
+
/**
|
|
11
|
+
* Create a query builder for multiple entities
|
|
12
|
+
*/
|
|
13
|
+
export declare function entities(): EntitiesQueryBuilder<EntityView>;
|
|
14
|
+
/**
|
|
15
|
+
* Create a query builder for a single entity
|
|
16
|
+
*/
|
|
17
|
+
export declare function entity(entityId: EntityId): EntityQueryBuilder;
|
|
18
|
+
export type { EntitiesQueryBuilder, EntityQueryBuilder, UnsubscribeFunc } from "./types";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query Engine Helpers
|
|
3
|
+
*
|
|
4
|
+
* Helper functions to make query engine usage easier and more intuitive.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
import type { AreaId, EntityDomain, EntityView } from "../core/types";
|
|
9
|
+
import type { EntitiesQueryBuilder } from "./types";
|
|
10
|
+
/**
|
|
11
|
+
* Create a search query builder
|
|
12
|
+
*/
|
|
13
|
+
export declare function searchEntities(searchText: string): EntitiesQueryBuilder<EntityView>;
|
|
14
|
+
/**
|
|
15
|
+
* Create a query for entities in an area by domain
|
|
16
|
+
*/
|
|
17
|
+
export declare function entitiesByAreaAndDomain(areaId: AreaId, domain: EntityDomain): EntitiesQueryBuilder<EntityView>;
|
|
18
|
+
/**
|
|
19
|
+
* Create a query for entities matching a predicate
|
|
20
|
+
*/
|
|
21
|
+
export declare function entitiesWhere(predicate: (entity: EntityView) => boolean): EntitiesQueryBuilder<EntityView>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query memoization
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
import type { QueryState } from "./types";
|
|
7
|
+
/**
|
|
8
|
+
* Build a unique signature for a query
|
|
9
|
+
*/
|
|
10
|
+
export declare function buildQuerySignature(query: QueryState): string;
|
|
11
|
+
/**
|
|
12
|
+
* Execute query (no caching -- SolidJS createMemo handles this in Plan 03)
|
|
13
|
+
*/
|
|
14
|
+
export declare function memoizedExecute<T>(signature: string, compute: () => T): T;
|
|
15
|
+
/**
|
|
16
|
+
* Check if cache should be invalidated
|
|
17
|
+
*/
|
|
18
|
+
export declare function isCacheStale(lastCheck: number, maxAge: number): boolean;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Projection utilities
|
|
3
|
+
*
|
|
4
|
+
* Functions for transforming entity views into different shapes.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
import type { EntityId, EntityView, MapFunc } from "../core/types";
|
|
9
|
+
/**
|
|
10
|
+
* Project entities to IDs only
|
|
11
|
+
*
|
|
12
|
+
* @param entities - Array of entity views
|
|
13
|
+
* @returns Array of entity IDs
|
|
14
|
+
*/
|
|
15
|
+
export declare function projectToIds(entities: EntityView[]): EntityId[];
|
|
16
|
+
/**
|
|
17
|
+
* Pick specific fields from entities
|
|
18
|
+
*
|
|
19
|
+
* @param entities - Array of entity views
|
|
20
|
+
* @param keys - Array of field names to include
|
|
21
|
+
* @returns Array of objects with only specified fields
|
|
22
|
+
*/
|
|
23
|
+
export declare function projectPick<K extends keyof EntityView>(entities: EntityView[], keys: K[]): Pick<EntityView, K>[];
|
|
24
|
+
/**
|
|
25
|
+
* Pluck a single field from entities
|
|
26
|
+
*
|
|
27
|
+
* Supports dot-notation for nested fields (e.g., "attributes.brightness")
|
|
28
|
+
*
|
|
29
|
+
* @param entities - Array of entity views
|
|
30
|
+
* @param key - Field name or dot-path to extract
|
|
31
|
+
* @returns Array of field values
|
|
32
|
+
*/
|
|
33
|
+
export declare function projectPluck(entities: EntityView[], key: string): any[];
|
|
34
|
+
/**
|
|
35
|
+
* Map entities using a custom function
|
|
36
|
+
*
|
|
37
|
+
* @param entities - Array of entity views
|
|
38
|
+
* @param mapper - Function to transform each entity
|
|
39
|
+
* @returns Array of mapped values
|
|
40
|
+
*/
|
|
41
|
+
export declare function projectMap<R>(entities: EntityView[], mapper: MapFunc<EntityView, R>): R[];
|
|
42
|
+
/**
|
|
43
|
+
* Get nested value from object using dot-notation
|
|
44
|
+
*
|
|
45
|
+
* @param obj - Object to extract value from
|
|
46
|
+
* @param path - Dot-notation path (e.g., "attributes.brightness")
|
|
47
|
+
* @returns Value at path or undefined
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const entity = { attributes: { brightness: 255 } };
|
|
52
|
+
* getNestedValue(entity, "attributes.brightness"); // 255
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function getNestedValue(obj: any, path: string): any;
|
|
56
|
+
/**
|
|
57
|
+
* Set nested value in object using dot-notation
|
|
58
|
+
*
|
|
59
|
+
* @param obj - Object to set value in
|
|
60
|
+
* @param path - Dot-notation path
|
|
61
|
+
* @param value - Value to set
|
|
62
|
+
*
|
|
63
|
+
* @internal
|
|
64
|
+
*/
|
|
65
|
+
export declare function setNestedValue(obj: any, path: string, value: any): void;
|
|
66
|
+
/**
|
|
67
|
+
* Check if a value is a primitive
|
|
68
|
+
*
|
|
69
|
+
* @param value - Value to check
|
|
70
|
+
* @returns True if primitive
|
|
71
|
+
*
|
|
72
|
+
* @internal
|
|
73
|
+
*/
|
|
74
|
+
export declare function isPrimitive(value: any): boolean;
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query-related types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for the query builder system.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
import type { AreaId, AreaView, Callback, DeviceId, EntityDomain, EntityId, EntityView, FloorId, LabelId, MapFunc, PredicateFunc, UnsubscribeFunc } from "../core/types";
|
|
9
|
+
export type { UnsubscribeFunc };
|
|
10
|
+
/**
|
|
11
|
+
* Main query builder interface for multiple entities
|
|
12
|
+
*
|
|
13
|
+
* Provides a fluent API for filtering, sorting, projecting, and subscribing.
|
|
14
|
+
*
|
|
15
|
+
* @template T - The result type (defaults to EntityView)
|
|
16
|
+
*/
|
|
17
|
+
export interface EntitiesQueryBuilder<T = EntityView> {
|
|
18
|
+
/**
|
|
19
|
+
* Filter by area
|
|
20
|
+
*
|
|
21
|
+
* @param areaId - Area ID to filter by
|
|
22
|
+
* @returns Query builder for chaining
|
|
23
|
+
*/
|
|
24
|
+
byArea(areaId: AreaId): EntitiesQueryBuilder<T>;
|
|
25
|
+
/**
|
|
26
|
+
* Filter by domain
|
|
27
|
+
*
|
|
28
|
+
* @param domain - Domain to filter by (e.g., "light", "sensor")
|
|
29
|
+
* @returns Query builder for chaining
|
|
30
|
+
*/
|
|
31
|
+
byDomain(domain: EntityDomain): EntitiesQueryBuilder<T>;
|
|
32
|
+
/**
|
|
33
|
+
* Filter by device
|
|
34
|
+
*
|
|
35
|
+
* @param deviceId - Device ID to filter by
|
|
36
|
+
* @returns Query builder for chaining
|
|
37
|
+
*/
|
|
38
|
+
byDevice(deviceId: DeviceId): EntitiesQueryBuilder<T>;
|
|
39
|
+
/**
|
|
40
|
+
* Filter by floor
|
|
41
|
+
*
|
|
42
|
+
* @param floorId - Floor ID to filter by
|
|
43
|
+
* @returns Query builder for chaining
|
|
44
|
+
*/
|
|
45
|
+
byFloor(floorId: FloorId): EntitiesQueryBuilder<T>;
|
|
46
|
+
/**
|
|
47
|
+
* Filter by label
|
|
48
|
+
*
|
|
49
|
+
* @param labelId - Label ID to filter by
|
|
50
|
+
* @returns Query builder for chaining
|
|
51
|
+
*/
|
|
52
|
+
byLabel(labelId: LabelId): EntitiesQueryBuilder<T>;
|
|
53
|
+
/**
|
|
54
|
+
* Filter with custom predicate
|
|
55
|
+
*
|
|
56
|
+
* @param predicate - Function to test each entity
|
|
57
|
+
* @returns Query builder for chaining
|
|
58
|
+
*/
|
|
59
|
+
where(predicate: PredicateFunc<EntityView>): EntitiesQueryBuilder<T>;
|
|
60
|
+
/**
|
|
61
|
+
* Search entities by text (searches id, name, friendlyName)
|
|
62
|
+
*
|
|
63
|
+
* @param searchText - Text to search for
|
|
64
|
+
* @returns Query builder for chaining
|
|
65
|
+
*/
|
|
66
|
+
search(searchText: string): EntitiesQueryBuilder<T>;
|
|
67
|
+
/**
|
|
68
|
+
* Sort results
|
|
69
|
+
*
|
|
70
|
+
* @param key - Property key or dot-path (e.g., "name", "attributes.brightness")
|
|
71
|
+
* @param direction - Sort direction ("asc" or "desc")
|
|
72
|
+
* @returns Query builder for chaining
|
|
73
|
+
*/
|
|
74
|
+
orderBy(key: string, direction?: "asc" | "desc"): EntitiesQueryBuilder<T>;
|
|
75
|
+
/**
|
|
76
|
+
* Project to entity IDs only
|
|
77
|
+
*
|
|
78
|
+
* @returns Query builder for entity IDs
|
|
79
|
+
*/
|
|
80
|
+
ids(): EntitiesQueryBuilder<EntityId>;
|
|
81
|
+
/**
|
|
82
|
+
* Pick specific fields
|
|
83
|
+
*
|
|
84
|
+
* @param keys - Array of field names to include
|
|
85
|
+
* @returns Query builder with picked fields
|
|
86
|
+
*/
|
|
87
|
+
pick<K extends keyof EntityView>(keys: K[]): EntitiesQueryBuilder<Pick<EntityView, K>>;
|
|
88
|
+
/**
|
|
89
|
+
* Extract a single field from each entity
|
|
90
|
+
*
|
|
91
|
+
* @param key - Field name to extract
|
|
92
|
+
* @returns Query builder for field values
|
|
93
|
+
*/
|
|
94
|
+
pluck<K extends keyof EntityView>(key: K): EntitiesQueryBuilder<EntityView[K]>;
|
|
95
|
+
/**
|
|
96
|
+
* Map entities to new values
|
|
97
|
+
*
|
|
98
|
+
* @param mapper - Function to transform each entity
|
|
99
|
+
* @returns Query builder for mapped values
|
|
100
|
+
*/
|
|
101
|
+
map<R>(mapper: MapFunc<EntityView, R>): EntitiesQueryBuilder<R>;
|
|
102
|
+
/**
|
|
103
|
+
* Limit the number of results
|
|
104
|
+
*
|
|
105
|
+
* @param limit - Maximum number of results to return
|
|
106
|
+
* @returns Query builder for chaining
|
|
107
|
+
*/
|
|
108
|
+
take(limit: number): EntitiesQueryBuilder<T>;
|
|
109
|
+
/**
|
|
110
|
+
* Skip a number of results (for pagination)
|
|
111
|
+
*
|
|
112
|
+
* @param count - Number of results to skip
|
|
113
|
+
* @returns Query builder for chaining
|
|
114
|
+
*/
|
|
115
|
+
skip(count: number): EntitiesQueryBuilder<T>;
|
|
116
|
+
/**
|
|
117
|
+
* Get distinct values by a key
|
|
118
|
+
*
|
|
119
|
+
* @param key - Field name or dot-path to get distinct values for
|
|
120
|
+
* @returns Query builder for distinct values
|
|
121
|
+
*/
|
|
122
|
+
distinct(key: string): EntitiesQueryBuilder<T>;
|
|
123
|
+
/**
|
|
124
|
+
* Execute query and return results
|
|
125
|
+
*
|
|
126
|
+
* @returns Array of results
|
|
127
|
+
*/
|
|
128
|
+
get(): T[];
|
|
129
|
+
/**
|
|
130
|
+
* Get first result
|
|
131
|
+
*
|
|
132
|
+
* @returns First result or undefined
|
|
133
|
+
*/
|
|
134
|
+
first(): T | undefined;
|
|
135
|
+
/**
|
|
136
|
+
* Subscribe to query results
|
|
137
|
+
*
|
|
138
|
+
* Receives updates when entities matching the query change.
|
|
139
|
+
*
|
|
140
|
+
* @param callback - Function called with results
|
|
141
|
+
* @returns Unsubscribe function
|
|
142
|
+
*/
|
|
143
|
+
subscribe(callback: Callback<T[]>): UnsubscribeFunc;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Query builder interface for areas
|
|
147
|
+
*/
|
|
148
|
+
export interface AreaQueryBuilder {
|
|
149
|
+
/**
|
|
150
|
+
* Filter areas by floor
|
|
151
|
+
*/
|
|
152
|
+
byFloor(floorId: FloorId): AreaQueryBuilder;
|
|
153
|
+
/**
|
|
154
|
+
* Filter areas by label
|
|
155
|
+
*/
|
|
156
|
+
byLabel(labelId: LabelId): AreaQueryBuilder;
|
|
157
|
+
/**
|
|
158
|
+
* Filter areas using a predicate
|
|
159
|
+
*/
|
|
160
|
+
where(predicate: PredicateFunc<AreaView>): AreaQueryBuilder;
|
|
161
|
+
/**
|
|
162
|
+
* Order results by a key
|
|
163
|
+
*/
|
|
164
|
+
orderBy(key: keyof AreaView | string, direction?: "asc" | "desc"): AreaQueryBuilder;
|
|
165
|
+
/**
|
|
166
|
+
* Execute query and get results
|
|
167
|
+
*/
|
|
168
|
+
get(): AreaView[];
|
|
169
|
+
/**
|
|
170
|
+
* Get first result
|
|
171
|
+
*/
|
|
172
|
+
first(): AreaView | undefined;
|
|
173
|
+
/**
|
|
174
|
+
* Subscribe to query results
|
|
175
|
+
*/
|
|
176
|
+
subscribe(callback: Callback<AreaView[]>): UnsubscribeFunc;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Query builder interface for a single entity
|
|
180
|
+
*/
|
|
181
|
+
export interface EntityQueryBuilder {
|
|
182
|
+
/**
|
|
183
|
+
* Get entity view
|
|
184
|
+
*
|
|
185
|
+
* @returns Entity view or undefined
|
|
186
|
+
*/
|
|
187
|
+
get(): EntityView | undefined;
|
|
188
|
+
/**
|
|
189
|
+
* Extract a single field
|
|
190
|
+
*
|
|
191
|
+
* @param key - Field name to extract
|
|
192
|
+
* @returns Field value or undefined
|
|
193
|
+
*/
|
|
194
|
+
pluck<K extends keyof EntityView>(key: K): EntityView[K] | undefined;
|
|
195
|
+
/**
|
|
196
|
+
* Subscribe to entity changes
|
|
197
|
+
*
|
|
198
|
+
* @param callback - Function called with entity view
|
|
199
|
+
* @returns Unsubscribe function
|
|
200
|
+
*/
|
|
201
|
+
subscribe(callback: Callback<EntityView | undefined>): UnsubscribeFunc;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Internal query state (not exported)
|
|
205
|
+
*
|
|
206
|
+
* @internal
|
|
207
|
+
*/
|
|
208
|
+
export interface QueryState {
|
|
209
|
+
/** Index-based filters (use indices for fast lookup) */
|
|
210
|
+
indexFilters: IndexFilter[];
|
|
211
|
+
/** Predicate-based filters (run on each entity) */
|
|
212
|
+
predicateFilters: PredicateFunc<EntityView>[];
|
|
213
|
+
/** Sort functions */
|
|
214
|
+
sorts: SortConfig[];
|
|
215
|
+
/** Projection configuration */
|
|
216
|
+
projection?: ProjectionConfig;
|
|
217
|
+
/** Search text (for text search functionality) */
|
|
218
|
+
searchText?: string;
|
|
219
|
+
/** Limit number of results */
|
|
220
|
+
take?: number;
|
|
221
|
+
/** Skip number of results (for pagination) */
|
|
222
|
+
skip?: number;
|
|
223
|
+
/** Distinct key for deduplication */
|
|
224
|
+
distinct?: string;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Index filter (uses store indices for fast lookup)
|
|
228
|
+
*
|
|
229
|
+
* @internal
|
|
230
|
+
*/
|
|
231
|
+
export interface IndexFilter {
|
|
232
|
+
type: "domain" | "area" | "device" | "floor" | "label";
|
|
233
|
+
value: string;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Sort configuration
|
|
237
|
+
*
|
|
238
|
+
* @internal
|
|
239
|
+
*/
|
|
240
|
+
export interface SortConfig {
|
|
241
|
+
key: string;
|
|
242
|
+
direction: "asc" | "desc";
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Projection configuration
|
|
246
|
+
*
|
|
247
|
+
* @internal
|
|
248
|
+
*/
|
|
249
|
+
export type ProjectionConfig = {
|
|
250
|
+
type: "ids";
|
|
251
|
+
} | {
|
|
252
|
+
type: "pick";
|
|
253
|
+
keys: string[];
|
|
254
|
+
} | {
|
|
255
|
+
type: "pluck";
|
|
256
|
+
key: string;
|
|
257
|
+
} | {
|
|
258
|
+
type: "map";
|
|
259
|
+
mapper: MapFunc<EntityView, any>;
|
|
260
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SolidJS Hooks for Sync-Layer
|
|
3
|
+
*
|
|
4
|
+
* Thin createMemo wrappers over the native SolidJS store.
|
|
5
|
+
* Since the store IS SolidJS (Plan 01 replaced Zustand with createStore),
|
|
6
|
+
* no subscription bridge is needed -- SolidJS auto-tracks fine-grained
|
|
7
|
+
* reactivity through the store proxy.
|
|
8
|
+
*
|
|
9
|
+
* Every hook is just `createMemo(() => state.something)`.
|
|
10
|
+
*
|
|
11
|
+
* @packageDocumentation
|
|
12
|
+
*/
|
|
13
|
+
import type { Accessor } from "solid-js";
|
|
14
|
+
import type { CameraStreamData } from "../camera/types";
|
|
15
|
+
import { callService, toggle, turnOff, turnOn } from "../commands/service";
|
|
16
|
+
import type { GlassHomeState } from "../core/store";
|
|
17
|
+
import type { AreaView, ConnectionState, EntityView, HassEntity } from "../core/types";
|
|
18
|
+
import type { EntityHistoryData } from "../history/types";
|
|
19
|
+
import type { WeatherForecastsData } from "../weather/types";
|
|
20
|
+
/**
|
|
21
|
+
* Get a reactive EntityView for an entity ID.
|
|
22
|
+
*
|
|
23
|
+
* Direct createMemo over store -- zero overhead, fine-grained reactivity.
|
|
24
|
+
* Only re-runs when the specific entity's data changes.
|
|
25
|
+
*/
|
|
26
|
+
export declare function useEntity(entityId: Accessor<string> | string): Accessor<EntityView | undefined>;
|
|
27
|
+
/**
|
|
28
|
+
* Get reactive EntityViews for multiple entity IDs.
|
|
29
|
+
*/
|
|
30
|
+
export declare function useEntities(entityIds: Accessor<string[]>): Accessor<EntityView[]>;
|
|
31
|
+
/**
|
|
32
|
+
* Get raw HassEntity state (without EntityView transformation).
|
|
33
|
+
*/
|
|
34
|
+
export declare function useEntityState(entityId: Accessor<string> | string): Accessor<HassEntity | undefined>;
|
|
35
|
+
/**
|
|
36
|
+
* Get reactive connection status.
|
|
37
|
+
*/
|
|
38
|
+
export declare function useConnection(): {
|
|
39
|
+
status: Accessor<ConnectionState>;
|
|
40
|
+
isConnected: Accessor<boolean>;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Get all service call functions.
|
|
44
|
+
*/
|
|
45
|
+
export declare function useService(): {
|
|
46
|
+
callService: typeof callService;
|
|
47
|
+
turnOn: typeof turnOn;
|
|
48
|
+
turnOff: typeof turnOff;
|
|
49
|
+
toggle: typeof toggle;
|
|
50
|
+
};
|
|
51
|
+
/** Get turnOn command function */
|
|
52
|
+
export declare function useTurnOn(): typeof turnOn;
|
|
53
|
+
/** Get turnOff command function */
|
|
54
|
+
export declare function useTurnOff(): typeof turnOff;
|
|
55
|
+
/** Get toggle command function */
|
|
56
|
+
export declare function useToggle(): typeof toggle;
|
|
57
|
+
/**
|
|
58
|
+
* Get reactive list of all area views.
|
|
59
|
+
*/
|
|
60
|
+
export declare function useAreas(): Accessor<AreaView[]>;
|
|
61
|
+
/**
|
|
62
|
+
* Get a reactive AreaView for a specific area.
|
|
63
|
+
*/
|
|
64
|
+
export declare function useArea(areaId: Accessor<string> | string): Accessor<AreaView | undefined>;
|
|
65
|
+
/**
|
|
66
|
+
* Get reactive entity history data.
|
|
67
|
+
*
|
|
68
|
+
* History data is populated into the store via subscriptions;
|
|
69
|
+
* this hook simply reads it reactively.
|
|
70
|
+
*/
|
|
71
|
+
export declare function useEntityHistory(entityId: Accessor<string> | string): Accessor<EntityHistoryData | undefined>;
|
|
72
|
+
/**
|
|
73
|
+
* Get reactive camera stream data.
|
|
74
|
+
*/
|
|
75
|
+
export declare function useCamera(entityId: Accessor<string> | string): {
|
|
76
|
+
stream: Accessor<CameraStreamData | null>;
|
|
77
|
+
refresh: () => void;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Get reactive weather forecast data.
|
|
81
|
+
*/
|
|
82
|
+
export declare function useForecast(entityId: Accessor<string> | string): Accessor<WeatherForecastsData | undefined>;
|
|
83
|
+
/**
|
|
84
|
+
* Escape hatch for direct store access with a selector.
|
|
85
|
+
*
|
|
86
|
+
* Use when no specific hook exists for your data need.
|
|
87
|
+
*/
|
|
88
|
+
export declare function useStore<T>(selector: (s: GlassHomeState) => T): Accessor<T>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SolidJS Adapter for @glasshome/sync-layer
|
|
3
|
+
*
|
|
4
|
+
* Thin reactive layer over the native SolidJS store.
|
|
5
|
+
* Import from `@glasshome/sync-layer/solid`.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
export { useArea, useAreas, useCamera, useConnection, useEntities, useEntity, useEntityHistory, useEntityState, useForecast, useService, useStore, useToggle, useTurnOff, useTurnOn, } from "./hooks";
|
|
10
|
+
export { allEntityIds, byArea, byDevice, byDomain, byFloor, byLabel, } from "./indices";
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { state } from "../store-B1sbyexX.js";
|
|
2
|
+
import { buildAreaView, callService, getEntityView, toggle, turnOff, turnOn } from "../area-views-B-m8vwce.js";
|
|
3
|
+
import { extractDomain } from "../types-Csog0nqk.js";
|
|
4
|
+
import { createMemo } from "solid-js";
|
|
5
|
+
|
|
6
|
+
//#region src/solid/hooks.ts
|
|
7
|
+
/**
|
|
8
|
+
* Get a reactive EntityView for an entity ID.
|
|
9
|
+
*
|
|
10
|
+
* Direct createMemo over store -- zero overhead, fine-grained reactivity.
|
|
11
|
+
* Only re-runs when the specific entity's data changes.
|
|
12
|
+
*/
|
|
13
|
+
function useEntity(entityId) {
|
|
14
|
+
const getId = typeof entityId === "function" ? entityId : () => entityId;
|
|
15
|
+
return createMemo(() => {
|
|
16
|
+
const id = getId();
|
|
17
|
+
if (!id) return void 0;
|
|
18
|
+
return getEntityView(id);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get reactive EntityViews for multiple entity IDs.
|
|
23
|
+
*/
|
|
24
|
+
function useEntities(entityIds) {
|
|
25
|
+
return createMemo(() => {
|
|
26
|
+
return entityIds().map((id) => getEntityView(id)).filter((v) => v !== void 0);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get raw HassEntity state (without EntityView transformation).
|
|
31
|
+
*/
|
|
32
|
+
function useEntityState(entityId) {
|
|
33
|
+
const getId = typeof entityId === "function" ? entityId : () => entityId;
|
|
34
|
+
return createMemo(() => state.entities[getId()]);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get reactive connection status.
|
|
38
|
+
*/
|
|
39
|
+
function useConnection() {
|
|
40
|
+
const status = createMemo(() => state.connectionState);
|
|
41
|
+
const isConnected = createMemo(() => state.connectionState === "connected");
|
|
42
|
+
return {
|
|
43
|
+
status,
|
|
44
|
+
isConnected
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get all service call functions.
|
|
49
|
+
*/
|
|
50
|
+
function useService() {
|
|
51
|
+
return {
|
|
52
|
+
callService,
|
|
53
|
+
turnOn,
|
|
54
|
+
turnOff,
|
|
55
|
+
toggle
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** Get turnOn command function */
|
|
59
|
+
function useTurnOn() {
|
|
60
|
+
return turnOn;
|
|
61
|
+
}
|
|
62
|
+
/** Get turnOff command function */
|
|
63
|
+
function useTurnOff() {
|
|
64
|
+
return turnOff;
|
|
65
|
+
}
|
|
66
|
+
/** Get toggle command function */
|
|
67
|
+
function useToggle() {
|
|
68
|
+
return toggle;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get reactive list of all area views.
|
|
72
|
+
*/
|
|
73
|
+
function useAreas() {
|
|
74
|
+
return createMemo(() => {
|
|
75
|
+
return Object.keys(state.areas).map((areaId) => {
|
|
76
|
+
try {
|
|
77
|
+
return buildAreaView(areaId);
|
|
78
|
+
} catch {
|
|
79
|
+
return void 0;
|
|
80
|
+
}
|
|
81
|
+
}).filter((v) => v !== void 0);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Get a reactive AreaView for a specific area.
|
|
86
|
+
*/
|
|
87
|
+
function useArea(areaId) {
|
|
88
|
+
const getId = typeof areaId === "function" ? areaId : () => areaId;
|
|
89
|
+
return createMemo(() => {
|
|
90
|
+
const id = getId();
|
|
91
|
+
if (!id || !state.areas[id]) return void 0;
|
|
92
|
+
try {
|
|
93
|
+
return buildAreaView(id);
|
|
94
|
+
} catch {
|
|
95
|
+
return void 0;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get reactive entity history data.
|
|
101
|
+
*
|
|
102
|
+
* History data is populated into the store via subscriptions;
|
|
103
|
+
* this hook simply reads it reactively.
|
|
104
|
+
*/
|
|
105
|
+
function useEntityHistory(entityId) {
|
|
106
|
+
const getId = typeof entityId === "function" ? entityId : () => entityId;
|
|
107
|
+
return createMemo(() => state.history[getId()]);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Get reactive camera stream data.
|
|
111
|
+
*/
|
|
112
|
+
function useCamera(entityId) {
|
|
113
|
+
const getId = typeof entityId === "function" ? entityId : () => entityId;
|
|
114
|
+
return {
|
|
115
|
+
stream: createMemo(() => state.streams[getId()] ?? null),
|
|
116
|
+
refresh: () => {}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get reactive weather forecast data.
|
|
121
|
+
*/
|
|
122
|
+
function useForecast(entityId) {
|
|
123
|
+
const getId = typeof entityId === "function" ? entityId : () => entityId;
|
|
124
|
+
return createMemo(() => state.forecasts[getId()]);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Escape hatch for direct store access with a selector.
|
|
128
|
+
*
|
|
129
|
+
* Use when no specific hook exists for your data need.
|
|
130
|
+
*/
|
|
131
|
+
function useStore(selector) {
|
|
132
|
+
return createMemo(() => selector(state));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
//#endregion
|
|
136
|
+
//#region src/solid/indices.ts
|
|
137
|
+
/**
|
|
138
|
+
* Group items by a key function
|
|
139
|
+
*/
|
|
140
|
+
function groupBy(items, keyFn) {
|
|
141
|
+
const result = {};
|
|
142
|
+
for (const item of items) {
|
|
143
|
+
const key = keyFn(item);
|
|
144
|
+
if (key) (result[key] ??= []).push(item);
|
|
145
|
+
}
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
/** Entity IDs grouped by domain (e.g., "light" -> ["light.living_room", ...]) */
|
|
149
|
+
const byDomain = createMemo(() => groupBy(Object.keys(state.entities), (id) => extractDomain(id)));
|
|
150
|
+
/** Entity IDs grouped by area (via entity registry area_id) */
|
|
151
|
+
const byArea = createMemo(() => groupBy(Object.keys(state.entityRegistry), (id) => state.entityRegistry[id]?.area_id ?? null));
|
|
152
|
+
/** Entity IDs grouped by device (via entity registry device_id) */
|
|
153
|
+
const byDevice = createMemo(() => groupBy(Object.keys(state.entityRegistry), (id) => state.entityRegistry[id]?.device_id ?? null));
|
|
154
|
+
/** Entity IDs grouped by floor (device -> area -> floor chain) */
|
|
155
|
+
const byFloor = createMemo(() => {
|
|
156
|
+
const result = {};
|
|
157
|
+
for (const [entityId, reg] of Object.entries(state.entityRegistry)) if (reg.device_id) {
|
|
158
|
+
const device = state.devices[reg.device_id];
|
|
159
|
+
if (device?.area_id) {
|
|
160
|
+
const area = state.areas[device.area_id];
|
|
161
|
+
if (area?.floor_id) (result[area.floor_id] ??= []).push(entityId);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return result;
|
|
165
|
+
});
|
|
166
|
+
/** Entity IDs grouped by label */
|
|
167
|
+
const byLabel = createMemo(() => {
|
|
168
|
+
const result = {};
|
|
169
|
+
for (const [entityId, reg] of Object.entries(state.entityRegistry)) for (const label of reg.labels ?? []) (result[label] ??= []).push(entityId);
|
|
170
|
+
return result;
|
|
171
|
+
});
|
|
172
|
+
/** All entity IDs currently in the store */
|
|
173
|
+
const allEntityIds = createMemo(() => Object.keys(state.entities));
|
|
174
|
+
|
|
175
|
+
//#endregion
|
|
176
|
+
export { allEntityIds, byArea, byDevice, byDomain, byFloor, byLabel, useArea, useAreas, useCamera, useConnection, useEntities, useEntity, useEntityHistory, useEntityState, useForecast, useService, useStore, useToggle, useTurnOff, useTurnOn };
|