@glasshome/sync-layer 0.4.0 → 0.6.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.
@@ -1,73 +0,0 @@
1
- /**
2
- * Base types and interfaces for mock behavior handlers
3
- *
4
- * This file defines the contract that all domain behavior handlers must implement.
5
- * Each domain handler simulates how Home Assistant would change entity states
6
- * in response to service calls.
7
- */
8
- import type { Domain, ServiceCall, ServiceName } from "@glasshome/ha-types";
9
- import type { HassEntity } from "../../core/types";
10
- /**
11
- * Context from a service call or state change
12
- * Matches HA's context structure
13
- */
14
- export interface ServiceContext {
15
- id: string;
16
- parent_id: string | null;
17
- user_id: string | null;
18
- }
19
- /**
20
- * Result of a behavior handler processing a service call
21
- */
22
- export interface BehaviorResult {
23
- /** Updated entity state (null if no change) */
24
- stateUpdate: Partial<HassEntity> | null;
25
- /** Optional error to throw */
26
- error?: {
27
- code: string;
28
- message: string;
29
- };
30
- /** Optional additional actions (for multi-step behaviors) */
31
- additionalActions?: Array<{
32
- delay: number;
33
- update: Partial<HassEntity>;
34
- }>;
35
- }
36
- /**
37
- * Domain behavior handler interface
38
- *
39
- * Each domain (light, switch, cover, etc.) implements this interface
40
- * to define how it reacts to service calls.
41
- *
42
- * Uses strongly-typed Domain and ServiceName from @glasshome/ha-types.
43
- */
44
- export interface DomainBehavior<D extends Domain = Domain> {
45
- /** Domain this handler manages (e.g., "light", "switch") */
46
- readonly domain: D;
47
- /**
48
- * Handle a service call for an entity in this domain
49
- *
50
- * @param entity - Current entity state
51
- * @param service - Service name (e.g., "turn_on", "set_temperature")
52
- * @param serviceData - Service call data/parameters
53
- * @param context - Service call context
54
- * @returns Behavior result with state updates
55
- */
56
- handleService(entity: HassEntity, service: ServiceName<D>, serviceData: ServiceCall<D, ServiceName<D>> | undefined, context: ServiceContext): BehaviorResult;
57
- }
58
- /**
59
- * Helper to create a simple state update result
60
- */
61
- export declare function simpleStateUpdate(update: Partial<HassEntity>): BehaviorResult;
62
- /**
63
- * Helper to create a no-change result
64
- */
65
- export declare function noChange(): BehaviorResult;
66
- /**
67
- * Helper to create an error result
68
- */
69
- export declare function behaviorError(code: string, message: string): BehaviorResult;
70
- /**
71
- * Helper to merge attributes safely
72
- */
73
- export declare function mergeAttributes(current: Record<string, unknown>, updates: Record<string, unknown>): Record<string, unknown>;
@@ -1,22 +0,0 @@
1
- /**
2
- * Climate domain behavior handler
3
- *
4
- * Simulates Home Assistant's climate entity behavior for:
5
- * - set_temperature: Set target temperature
6
- * - set_hvac_mode: Change HVAC mode (heat, cool, auto, etc.)
7
- * - set_preset_mode: Change preset (eco, comfort, etc.)
8
- * - set_fan_mode: Change fan mode
9
- * - set_humidity: Set target humidity
10
- * - turn_on: Turn on to last mode (or heat)
11
- * - turn_off: Turn off
12
- *
13
- * Uses strongly-typed ClimateService from @glasshome/ha-types.
14
- */
15
- import type { ServiceCall, ServiceName } from "@glasshome/ha-types";
16
- import type { HassEntity } from "../../core/types";
17
- import type { BehaviorResult, DomainBehavior, ServiceContext } from "./base";
18
- export declare class ClimateBehavior implements DomainBehavior<"climate"> {
19
- readonly domain: "climate";
20
- handleService(entity: HassEntity, service: ServiceName<"climate">, serviceData: ServiceCall<"climate", ServiceName<"climate">> | undefined, _context: ServiceContext): BehaviorResult;
21
- private handleSetTemperature;
22
- }
@@ -1,22 +0,0 @@
1
- /**
2
- * Cover domain behavior handler
3
- *
4
- * Simulates Home Assistant's cover entity behavior for:
5
- * - open_cover: Open cover fully
6
- * - close_cover: Close cover fully
7
- * - stop_cover: Stop cover movement
8
- * - set_cover_position: Set to specific position
9
- * - open_cover_tilt: Open tilt fully
10
- * - close_cover_tilt: Close tilt fully
11
- * - set_cover_tilt_position: Set tilt to specific position
12
- * - toggle: Toggle open/closed
13
- *
14
- * Uses strongly-typed CoverService from @glasshome/ha-types.
15
- */
16
- import type { ServiceCall, ServiceName } from "@glasshome/ha-types";
17
- import type { HassEntity } from "../../core/types";
18
- import type { BehaviorResult, DomainBehavior, ServiceContext } from "./base";
19
- export declare class CoverBehavior implements DomainBehavior<"cover"> {
20
- readonly domain: "cover";
21
- handleService(entity: HassEntity, service: ServiceName<"cover">, serviceData: ServiceCall<"cover", ServiceName<"cover">> | undefined, _context: ServiceContext): BehaviorResult;
22
- }
@@ -1,11 +0,0 @@
1
- /**
2
- * Mock Behaviors - Export all behavior handlers and utilities
3
- */
4
- export * from "./base";
5
- export { ClimateBehavior } from "./climate";
6
- export { CoverBehavior } from "./cover";
7
- export { LightBehavior } from "./light";
8
- export { LockBehavior } from "./lock";
9
- export { MediaPlayerBehavior } from "./media_player";
10
- export * from "./registry";
11
- export { SwitchBehavior } from "./switch";
@@ -1,20 +0,0 @@
1
- /**
2
- * Light domain behavior handler
3
- *
4
- * Simulates Home Assistant's light entity behavior for:
5
- * - turn_on: Turn on with optional brightness, color, etc.
6
- * - turn_off: Turn off with optional transition
7
- * - toggle: Toggle state
8
- *
9
- * Uses strongly-typed LightService and ServiceCall from @glasshome/ha-types.
10
- */
11
- import type { ServiceCall, ServiceName } from "@glasshome/ha-types";
12
- import type { HassEntity } from "../../core/types";
13
- import type { BehaviorResult, DomainBehavior, ServiceContext } from "./base";
14
- export declare class LightBehavior implements DomainBehavior<"light"> {
15
- readonly domain: "light";
16
- handleService(entity: HassEntity, service: ServiceName<"light">, serviceData: ServiceCall<"light", ServiceName<"light">> | undefined, _context: ServiceContext): BehaviorResult;
17
- private handleTurnOn;
18
- private handleTurnOff;
19
- private handleToggle;
20
- }
@@ -1,20 +0,0 @@
1
- /**
2
- * Lock domain behavior handler
3
- *
4
- * Simulates Home Assistant's lock entity behavior for:
5
- * - lock: Lock the lock
6
- * - unlock: Unlock the lock
7
- * - open: Open the lock (unlocks and opens door)
8
- *
9
- * Uses strongly-typed LockService from @glasshome/ha-types.
10
- */
11
- import type { ServiceCall, ServiceName } from "@glasshome/ha-types";
12
- import type { HassEntity } from "../../core/types";
13
- import type { BehaviorResult, DomainBehavior, ServiceContext } from "./base";
14
- export declare class LockBehavior implements DomainBehavior<"lock"> {
15
- readonly domain: "lock";
16
- handleService(entity: HassEntity, service: ServiceName<"lock">, _serviceData: ServiceCall<"lock", ServiceName<"lock">> | undefined, _context: ServiceContext): BehaviorResult;
17
- private handleLock;
18
- private handleUnlock;
19
- private handleOpen;
20
- }
@@ -1,42 +0,0 @@
1
- /**
2
- * Media Player domain behavior handler
3
- *
4
- * Simulates Home Assistant's media player entity behavior for:
5
- * - media_play: Start playback
6
- * - media_pause: Pause playback
7
- * - media_play_pause: Toggle play/pause
8
- * - media_stop: Stop playback
9
- * - media_next_track: Skip to next track
10
- * - media_previous_track: Skip to previous track
11
- * - media_seek: Seek to position
12
- * - volume_up: Increase volume
13
- * - volume_down: Decrease volume
14
- * - set_volume_level: Set volume level
15
- * - mute_volume: Mute/unmute
16
- * - turn_on: Turn on media player
17
- * - turn_off: Turn off media player
18
- * - toggle: Toggle power
19
- *
20
- * Uses strongly-typed MediaPlayerService from @glasshome/ha-types.
21
- */
22
- import type { ServiceCall, ServiceName } from "@glasshome/ha-types";
23
- import type { HassEntity } from "../../core/types";
24
- import type { BehaviorResult, DomainBehavior, ServiceContext } from "./base";
25
- export declare class MediaPlayerBehavior implements DomainBehavior<"media_player"> {
26
- readonly domain: "media_player";
27
- handleService(entity: HassEntity, service: ServiceName<"media_player">, serviceData: ServiceCall<"media_player", ServiceName<"media_player">> | undefined, _context: ServiceContext): BehaviorResult;
28
- private handlePlay;
29
- private handlePause;
30
- private handlePlayPause;
31
- private handleStop;
32
- private handleNextTrack;
33
- private handlePreviousTrack;
34
- private handleSeek;
35
- private handleVolumeUp;
36
- private handleVolumeDown;
37
- private handleSetVolumeLevel;
38
- private handleMuteVolume;
39
- private handleTurnOn;
40
- private handleTurnOff;
41
- private handleToggle;
42
- }
@@ -1,55 +0,0 @@
1
- /**
2
- * Behavior Registry
3
- *
4
- * Manages and provides access to all domain behavior handlers.
5
- * Automatically discovers and registers handlers.
6
- */
7
- import type { DomainBehavior } from "./base";
8
- /**
9
- * Central registry of all domain behavior handlers
10
- */
11
- export declare class BehaviorRegistry {
12
- private handlers;
13
- constructor();
14
- /**
15
- * Register all built-in domain handlers
16
- */
17
- private registerDefaultHandlers;
18
- /**
19
- * Register a domain behavior handler
20
- */
21
- register(handler: DomainBehavior): void;
22
- /**
23
- * Get handler for a specific domain
24
- */
25
- getHandler(domain: string): DomainBehavior | undefined;
26
- /**
27
- * Check if a domain has a registered handler
28
- */
29
- hasHandler(domain: string): boolean;
30
- /**
31
- * Get all registered domains
32
- */
33
- getRegisteredDomains(): string[];
34
- /**
35
- * Clear all handlers (useful for testing)
36
- */
37
- clear(): void;
38
- /**
39
- * Reset to default handlers
40
- */
41
- reset(): void;
42
- }
43
- /**
44
- * Global behavior registry instance
45
- */
46
- export declare const behaviorRegistry: BehaviorRegistry;
47
- /**
48
- * Get behavior handler for a domain
49
- */
50
- export declare function getBehaviorHandler(domain: string): DomainBehavior | undefined;
51
- /**
52
- * Register a custom behavior handler
53
- * Useful for tests or custom mock scenarios
54
- */
55
- export declare function registerBehaviorHandler(handler: DomainBehavior): void;
@@ -1,17 +0,0 @@
1
- /**
2
- * Switch domain behavior handler
3
- *
4
- * Simulates Home Assistant's switch entity behavior for:
5
- * - turn_on: Turn on switch
6
- * - turn_off: Turn off switch
7
- * - toggle: Toggle state
8
- *
9
- * Uses strongly-typed SwitchService from @glasshome/ha-types.
10
- */
11
- import type { ServiceCall, ServiceName } from "@glasshome/ha-types";
12
- import type { HassEntity } from "../../core/types";
13
- import type { BehaviorResult, DomainBehavior, ServiceContext } from "./base";
14
- export declare class SwitchBehavior implements DomainBehavior<"switch"> {
15
- readonly domain: "switch";
16
- handleService(entity: HassEntity, service: ServiceName<"switch">, _serviceData: ServiceCall<"switch", ServiceName<"switch">> | undefined, _context: ServiceContext): BehaviorResult;
17
- }
@@ -1,196 +0,0 @@
1
- /**
2
- * Mock Home Assistant connection
3
- *
4
- * Provides a mock implementation for testing without a real HA instance.
5
- *
6
- * @packageDocumentation
7
- */
8
- import type { EntityRegistryEntry, HassConfig, HAEvent } from "@glasshome/ha-types";
9
- import type { SyncLayerConnection } from "../connection/types";
10
- import type { HassEntity } from "../core/types";
11
- import type { AreaRegistryEntry, DeviceRegistryEntry, Fixtures } from "./types";
12
- /**
13
- * Mock WebSocket connection for testing
14
- *
15
- * Simulates a Home Assistant WebSocket connection without requiring
16
- * a real backend.
17
- *
18
- * MockConnection does NOT manipulate the store directly.
19
- * SyncLayer loads fixtures via `getFixtures()` and manages state itself.
20
- */
21
- export declare class MockConnection implements SyncLayerConnection {
22
- private connected;
23
- authState: "pending" | "authenticated" | "failed";
24
- private messageHandlers;
25
- private eventSubscriptions;
26
- private subscriptions;
27
- private latency;
28
- private fixtures;
29
- private mockVersion;
30
- private messageIdCounter;
31
- private autoReact;
32
- private reactionDelay;
33
- private configOverride;
34
- serviceCalls: Array<{
35
- domain: string;
36
- service: string;
37
- serviceData?: Record<string, any>;
38
- target?: any;
39
- timestamp: number;
40
- }>;
41
- sentCommands: Array<{
42
- type: string;
43
- data?: any;
44
- timestamp: number;
45
- }>;
46
- constructor(fixtures: Fixtures, latency?: number, options?: {
47
- /** Enable automatic state reactions to service calls (default: true) */
48
- autoReact?: boolean;
49
- /** Delay before emitting entity update events after service calls in ms (default: 0) */
50
- reactionDelay?: number;
51
- /** Override fields of the get_config response (unit_system, language, currency, etc.) */
52
- config?: Partial<HassConfig>;
53
- });
54
- /** Replace the core config and fire core_config_updated (simulates HA Region change). */
55
- setConfig(config: Partial<HassConfig>): void;
56
- /**
57
- * Get connected state
58
- */
59
- get connected$(): boolean;
60
- /**
61
- * Simulate connection - sends auth_required per WebSocket spec
62
- */
63
- connect(): Promise<void>;
64
- /**
65
- * Register message handler for auth and other server messages
66
- */
67
- addEventListener(handler: (message: any) => void): () => void;
68
- /**
69
- * Handle authentication message (from client)
70
- */
71
- authenticate(_accessToken: string): Promise<void>;
72
- /**
73
- * Send auth_required message (server-initiated)
74
- */
75
- private sendAuthRequired;
76
- /**
77
- * Simulate disconnection
78
- */
79
- disconnect(): void;
80
- /**
81
- * Close connection (alias for disconnect for compatibility)
82
- */
83
- close(): void;
84
- /**
85
- * Send a message (mock implementation)
86
- */
87
- sendMessage(message: any): Promise<void>;
88
- /**
89
- * Call a service (mock implementation)
90
- */
91
- callService(domain: string, service: string, serviceData?: Record<string, any>, target?: any): Promise<any>;
92
- /**
93
- * Send a message and wait for response - returns proper WebSocket result format
94
- */
95
- sendMessagePromise<T>(message: any): Promise<T>;
96
- /**
97
- * Handle different message types and return appropriate data
98
- */
99
- private handleMessage;
100
- /**
101
- * Subscribe to events
102
- */
103
- subscribeEvents(callback: (event: any) => void, eventType?: string): Promise<() => void>;
104
- /**
105
- * Subscribe to WebSocket messages
106
- *
107
- * Used for subscribing to command responses like history/stream
108
- *
109
- * @param callback - Callback function for messages
110
- * @param message - Message to subscribe to
111
- * @returns Promise resolving to unsubscribe function
112
- */
113
- subscribeMessage<T>(callback: (message: T) => void, message: {
114
- type: string;
115
- [key: string]: unknown;
116
- }): Promise<() => Promise<void>>;
117
- /**
118
- * Simulate state change
119
- */
120
- setState(entityId: string, updates: Partial<HassEntity>): void;
121
- /**
122
- * Simulate entity registry update
123
- */
124
- updateEntityRegistry(entityId: string, updates: Partial<EntityRegistryEntry>): void;
125
- /**
126
- * Simulate area registry update
127
- */
128
- updateAreaRegistry(areaId: string, updates: Partial<AreaRegistryEntry>): void;
129
- /**
130
- * Simulate device registry update
131
- */
132
- updateDeviceRegistry(deviceId: string, updates: Partial<DeviceRegistryEntry>): void;
133
- /**
134
- * Emit custom event - sends proper WebSocket event messages to subscriptions
135
- */
136
- emitEvent(event: HAEvent<any>): void;
137
- /**
138
- * Handle subscribe_events command
139
- */
140
- private handleSubscribeEvents;
141
- /**
142
- * Handle unsubscribe_events command
143
- */
144
- private handleUnsubscribeEvents;
145
- /**
146
- * Get current fixtures
147
- *
148
- * SyncLayer calls this to load fixtures into its store.
149
- */
150
- getFixtures(): Fixtures;
151
- /**
152
- * Load new fixtures
153
- */
154
- loadFixtures(fixtures: Partial<Fixtures>): void;
155
- /**
156
- * Clear tracking data
157
- */
158
- clearTracking(): void;
159
- /**
160
- * Get last service call
161
- */
162
- getLastServiceCall(): (typeof this.serviceCalls)[number] | undefined;
163
- /**
164
- * Get last command
165
- */
166
- getLastCommand(): (typeof this.sentCommands)[number] | undefined;
167
- private delay;
168
- private sendResponse;
169
- private handleEntityUpdate;
170
- private handleServiceCall;
171
- /**
172
- * Handle automatic reactions to service calls using behavior handlers
173
- */
174
- private handleServiceReaction;
175
- /**
176
- * Resolve target entities from service call target
177
- */
178
- private resolveTargetEntities;
179
- /**
180
- * Set state with custom context (internal use)
181
- */
182
- private setStateWithContext;
183
- /**
184
- * Enable/disable automatic reactions
185
- */
186
- setAutoReact(enabled: boolean): void;
187
- /**
188
- * Set reaction delay (useful for testing timing)
189
- */
190
- setReactionDelay(delay: number): void;
191
- private generateId;
192
- }
193
- /**
194
- * Export types
195
- */
196
- export type { Fixtures };
@@ -1,87 +0,0 @@
1
- /**
2
- * Testing types
3
- *
4
- * Type definitions for testing utilities and mocks.
5
- *
6
- * @packageDocumentation
7
- */
8
- import type { AreaEntry, DeviceEntry, EntityRegistryEntry } from "@glasshome/ha-types";
9
- import type { HassEntity } from "../core/types";
10
- import type { EntityHistoryState } from "../history/types";
11
- import type { WeatherForecast } from "../weather/types";
12
- /**
13
- * Area registry entry
14
- *
15
- * @alias AreaEntry
16
- * @note AreaEntry uses 'id' field, not 'area_id'
17
- */
18
- export type AreaRegistryEntry = AreaEntry;
19
- /**
20
- * Device registry entry
21
- *
22
- * @alias DeviceEntry
23
- */
24
- export type DeviceRegistryEntry = DeviceEntry;
25
- /**
26
- * Floor registry entry
27
- */
28
- export interface FloorRegistryEntry {
29
- floor_id: string;
30
- name: string;
31
- level: number;
32
- icon: string | null;
33
- aliases: string[];
34
- created_at: string;
35
- modified_at: string;
36
- }
37
- /**
38
- * Label registry entry
39
- */
40
- export interface LabelRegistryEntry {
41
- label_id: string;
42
- name: string;
43
- color: string | null;
44
- icon: string | null;
45
- description: string | null;
46
- created_at: string;
47
- modified_at: string;
48
- }
49
- /**
50
- * Fixture data for testing
51
- */
52
- export interface Fixtures {
53
- /** Entity states */
54
- entities: Record<string, HassEntity>;
55
- /** Entity registry */
56
- entityRegistry: EntityRegistryEntry[];
57
- /** Device registry */
58
- deviceRegistry: DeviceRegistryEntry[];
59
- /** Area registry */
60
- areaRegistry: AreaRegistryEntry[];
61
- /** Floor registry */
62
- floorRegistry: FloorRegistryEntry[];
63
- /** Label registry */
64
- labelRegistry: LabelRegistryEntry[];
65
- /** History data for entities (entityId -> history states array) */
66
- history?: Record<string, EntityHistoryState[]>;
67
- /** Weather forecasts data (entityId -> forecastType -> forecast array) */
68
- forecasts?: Record<string, Record<string, WeatherForecast[]>>;
69
- }
70
- /**
71
- * Options for simulating state changes
72
- */
73
- export interface StateChangeOptions {
74
- /** Delay before emitting (ms) */
75
- delay?: number;
76
- /** Only update specific attributes */
77
- attributesOnly?: boolean;
78
- }
79
- /**
80
- * Options for simulating registry updates
81
- */
82
- export interface RegistryUpdateOptions {
83
- /** Delay before emitting (ms) */
84
- delay?: number;
85
- /** Emit event immediately */
86
- immediate?: boolean;
87
- }