matterbridge-lg-thinq-plugin 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/.claude/CLAUDE.md +43 -0
- package/.claude/agents/compiler.md +91 -0
- package/.claude/agents/direct-executor.md +98 -0
- package/.claude/agents/documenter.md +78 -0
- package/.claude/agents/finalizer.md +233 -0
- package/.claude/agents/implementer.md +112 -0
- package/.claude/agents/investigator.md +100 -0
- package/.claude/agents/release-manager.md +203 -0
- package/.claude/agents/reviewer.md +131 -0
- package/.claude/agents/technical-architect.md +403 -0
- package/.claude/agents/test-writer.md +159 -0
- package/.claude/agents/wiki-manager.md +147 -0
- package/.claude/instructions/agent-prompts.md +90 -0
- package/.claude/instructions/shared-rules.md +11 -0
- package/.claude/instructions/team-orchestrator-policy.md +165 -0
- package/.claude/memory.md +186 -0
- package/.claude/output-styles/engineer-manager.md +38 -0
- package/.claude/settings.json +40 -0
- package/.claude/settings.local.json +30 -0
- package/.claude/skills/load-policy/SKILL.md +13 -0
- package/.claude/skills/ref-idea/SKILL.md +44 -0
- package/.claude/skills/status-of/SKILL.md +38 -0
- package/.claude/skills/workspace-console/SKILL.md +49 -0
- package/.claude/statusline-command.sh +130 -0
- package/.claude/statusline.md +53 -0
- package/.claude/templates/approval-packet.template.html +171 -0
- package/.claude/templates/reference-workspaces.md +16 -0
- package/.claude/tools/cli-runner-server.cjs +220 -0
- package/.claude/tools/discord-send-server.cjs +188 -0
- package/.claude/tools/github-release-server.cjs +181 -0
- package/.claude/tools/glob-grep-server.cjs +267 -0
- package/.claude/tools/read-log-server.cjs +175 -0
- package/.github/codeql/codeql-config.yml +14 -0
- package/.github/workflows/build.yml +54 -0
- package/.github/workflows/codeql.yml +59 -0
- package/.github/workflows/coverage.yml +70 -0
- package/.github/workflows/publish.yml +103 -0
- package/.mcp.json +34 -0
- package/CHANGELOG.md +195 -0
- package/LICENSE +21 -0
- package/dist/cli/commands/devices.js +52 -0
- package/dist/cli/commands/energy.js +122 -0
- package/dist/cli/commands/login.js +54 -0
- package/dist/cli/help.js +50 -0
- package/dist/cli/main.js +56 -0
- package/dist/cli/session.js +13 -0
- package/dist/cli/types.js +1 -0
- package/dist/cli/utils.js +29 -0
- package/dist/cli.js +2 -0
- package/dist/constants/index.js +1 -0
- package/dist/core/domain/entities/ThinqDevice.js +43 -0
- package/dist/core/domain/value-objects/AirConditionerCapabilities.js +22 -0
- package/dist/core/domain/value-objects/ThinqFilterState.js +35 -0
- package/dist/core/domain/value-objects/ThinqSnapshot.js +125 -0
- package/dist/errors/AuthenticationError.js +26 -0
- package/dist/errors/BaseError.js +23 -0
- package/dist/errors/index.js +2 -0
- package/dist/model/LgThinkqPluginPlatformConfig.js +23 -0
- package/dist/model/LgThinqPluginPlatformConfig.js +23 -0
- package/dist/module.js +212 -0
- package/dist/platform/deviceRegistry.js +26 -0
- package/dist/platform/platformConfigManager.js +89 -0
- package/dist/platform/platformState.js +9 -0
- package/dist/platform/thinq/thinqAirConditionerCommandHandlers.js +190 -0
- package/dist/platform/thinq/thinqAirConditionerEndpointFactory.js +53 -0
- package/dist/platform/thinq/thinqAirConditionerFilterResetCommandHandler.js +54 -0
- package/dist/platform/thinq/thinqAirConditionerFilterStateSync.js +19 -0
- package/dist/platform/thinq/thinqAirConditionerStateSync.js +205 -0
- package/dist/platform/thinq/thinqDeviceConfigReconciler.js +26 -0
- package/dist/platform/thinq/thinqDeviceConfigurator.js +124 -0
- package/dist/platform/thinq/thinqDeviceDiscovery.js +33 -0
- package/dist/platform/thinq/thinqWasherCommandHandlers.js +54 -0
- package/dist/platform/thinq/thinqWasherEndpointFactory.js +6 -0
- package/dist/platform/thinq/thinqWasherStateSync.js +31 -0
- package/dist/platform/thinq/thinqWasherStopCommandResolver.js +38 -0
- package/dist/services/authentication/AccountAuthStrategy.js +135 -0
- package/dist/services/authentication/AuthContext.js +1 -0
- package/dist/services/authentication/AuthenticationCoordinator.js +29 -0
- package/dist/services/authentication/IAuthStrategy.js +1 -0
- package/dist/services/authentication/TokenAuthStrategy.js +27 -0
- package/dist/services/authentication/UserDataRepository.js +32 -0
- package/dist/services/thinq/gateway.js +61 -0
- package/dist/services/thinq/mqtt/mqttCertificate.js +63 -0
- package/dist/services/thinq/mqtt/mqttConnectionEvents.js +37 -0
- package/dist/services/thinq/mqtt/mqttKeyRepository.js +33 -0
- package/dist/services/thinq/mqtt/mqttRetry.js +25 -0
- package/dist/services/thinq/mqtt/thinqMqttListener.js +97 -0
- package/dist/services/thinq/serviceContainer.js +73 -0
- package/dist/services/thinq/session.js +48 -0
- package/dist/services/thinq/thinqApiClient.js +258 -0
- package/dist/services/thinq/thinqDeviceService.js +75 -0
- package/dist/services/thinq/thinqFilterMonitoringService.js +40 -0
- package/dist/settings.js +9 -0
- package/dist/tests/helpers/testUtils.js +87 -0
- package/dist/utils/mask.js +39 -0
- package/docs/README_CLI.md +166 -0
- package/eslint.config.js +194 -0
- package/matterbridge-lg-thinq-plugin.config.json +27 -0
- package/matterbridge-lg-thinq-plugin.schema.json +520 -0
- package/package.json +107 -0
- package/prettier.config.js +49 -0
- package/scripts/parse-junit-failures.mjs +45 -0
- package/scripts/parse-tsc-failures.mjs +48 -0
- package/scripts/run-build-local-summary.mjs +29 -0
- package/scripts/run-format-summary.mjs +36 -0
- package/scripts/run-lint-fix-summary.mjs +38 -0
- package/scripts/run-precommit-summary.mjs +94 -0
- package/src/cli/commands/devices.ts +67 -0
- package/src/cli/commands/energy.ts +160 -0
- package/src/cli/commands/login.ts +74 -0
- package/src/cli/help.ts +53 -0
- package/src/cli/main.ts +66 -0
- package/src/cli/session.ts +15 -0
- package/src/cli/types.ts +10 -0
- package/src/cli/utils.ts +30 -0
- package/src/cli.ts +3 -0
- package/src/constants/index.ts +8 -0
- package/src/core/domain/entities/ThinqDevice.test.ts +224 -0
- package/src/core/domain/entities/ThinqDevice.ts +74 -0
- package/src/core/domain/value-objects/AirConditionerCapabilities.ts +50 -0
- package/src/core/domain/value-objects/ThinqFilterState.ts +50 -0
- package/src/core/domain/value-objects/ThinqSnapshot.ts +162 -0
- package/src/errors/AuthenticationError.ts +37 -0
- package/src/errors/BaseError.ts +38 -0
- package/src/errors/index.ts +24 -0
- package/src/model/LgThinqPluginPlatformConfig.ts +94 -0
- package/src/module.ts +298 -0
- package/src/platform/deviceRegistry.ts +58 -0
- package/src/platform/platformConfigManager.ts +133 -0
- package/src/platform/platformState.ts +16 -0
- package/src/platform/thinq/thinqAirConditionerCommandHandlers.ts +291 -0
- package/src/platform/thinq/thinqAirConditionerEndpointFactory.ts +145 -0
- package/src/platform/thinq/thinqAirConditionerFilterResetCommandHandler.ts +96 -0
- package/src/platform/thinq/thinqAirConditionerFilterStateSync.ts +42 -0
- package/src/platform/thinq/thinqAirConditionerStateSync.ts +343 -0
- package/src/platform/thinq/thinqDeviceConfigReconciler.ts +42 -0
- package/src/platform/thinq/thinqDeviceConfigurator.test.ts +90 -0
- package/src/platform/thinq/thinqDeviceConfigurator.ts +191 -0
- package/src/platform/thinq/thinqDeviceDiscovery.test.ts +173 -0
- package/src/platform/thinq/thinqDeviceDiscovery.ts +51 -0
- package/src/platform/thinq/thinqWasherCommandHandlers.ts +120 -0
- package/src/platform/thinq/thinqWasherEndpointFactory.ts +37 -0
- package/src/platform/thinq/thinqWasherStateSync.ts +60 -0
- package/src/platform/thinq/thinqWasherStopCommandResolver.ts +62 -0
- package/src/services/authentication/AccountAuthStrategy.test.ts +358 -0
- package/src/services/authentication/AccountAuthStrategy.ts +209 -0
- package/src/services/authentication/AuthContext.ts +19 -0
- package/src/services/authentication/AuthenticationCoordinator.test.ts +217 -0
- package/src/services/authentication/AuthenticationCoordinator.ts +59 -0
- package/src/services/authentication/IAuthStrategy.ts +10 -0
- package/src/services/authentication/TokenAuthStrategy.test.ts +167 -0
- package/src/services/authentication/TokenAuthStrategy.ts +40 -0
- package/src/services/authentication/UserDataRepository.test.ts +149 -0
- package/src/services/authentication/UserDataRepository.ts +46 -0
- package/src/services/thinq/gateway.ts +86 -0
- package/src/services/thinq/mqtt/mqttCertificate.test.ts +344 -0
- package/src/services/thinq/mqtt/mqttCertificate.ts +102 -0
- package/src/services/thinq/mqtt/mqttConnectionEvents.test.ts +276 -0
- package/src/services/thinq/mqtt/mqttConnectionEvents.ts +76 -0
- package/src/services/thinq/mqtt/mqttKeyRepository.test.ts +164 -0
- package/src/services/thinq/mqtt/mqttKeyRepository.ts +43 -0
- package/src/services/thinq/mqtt/mqttRetry.test.ts +239 -0
- package/src/services/thinq/mqtt/mqttRetry.ts +43 -0
- package/src/services/thinq/mqtt/thinqMqttListener.test.ts +349 -0
- package/src/services/thinq/mqtt/thinqMqttListener.ts +120 -0
- package/src/services/thinq/serviceContainer.test.ts +203 -0
- package/src/services/thinq/serviceContainer.ts +105 -0
- package/src/services/thinq/session.test.ts +287 -0
- package/src/services/thinq/session.ts +69 -0
- package/src/services/thinq/thinqApiClient.test.ts +702 -0
- package/src/services/thinq/thinqApiClient.ts +418 -0
- package/src/services/thinq/thinqDeviceService.test.ts +415 -0
- package/src/services/thinq/thinqDeviceService.ts +101 -0
- package/src/services/thinq/thinqFilterMonitoringService.test.ts +264 -0
- package/src/services/thinq/thinqFilterMonitoringService.ts +53 -0
- package/src/settings.ts +18 -0
- package/src/tests/cli/commands/devices.test.ts +293 -0
- package/src/tests/cli/commands/login.test.ts +240 -0
- package/src/tests/cli/help.test.ts +46 -0
- package/src/tests/cli/main.test.ts +214 -0
- package/src/tests/cli/session.test.ts +198 -0
- package/src/tests/cli/utils.test.ts +194 -0
- package/src/tests/core/domain/value-objects/AirConditionerCapabilities.test.ts +685 -0
- package/src/tests/core/domain/value-objects/ThinqFilterState.test.ts +210 -0
- package/src/tests/core/domain/value-objects/ThinqSnapshot.test.ts +1035 -0
- package/src/tests/helpers/testUtils.ts +118 -0
- package/src/tests/model/LgThinqPluginPlatformConfig.test.ts +81 -0
- package/src/tests/platform/deviceRegistry.test.ts +177 -0
- package/src/tests/platform/platformConfigManager.test.ts +790 -0
- package/src/tests/platform/platformState.test.ts +41 -0
- package/src/tests/platform/thinq/thinqAirConditionerCommandHandlers.test.ts +879 -0
- package/src/tests/platform/thinq/thinqAirConditionerEndpointFactory.test.ts +993 -0
- package/src/tests/platform/thinq/thinqAirConditionerFilterResetCommandHandler.test.ts +508 -0
- package/src/tests/platform/thinq/thinqAirConditionerFilterStateSync.test.ts +212 -0
- package/src/tests/platform/thinq/thinqAirConditionerStateSync.test.ts +1586 -0
- package/src/tests/platform/thinq/thinqDeviceConfigReconciler.test.ts +269 -0
- package/src/tests/platform/thinq/thinqDeviceConfigurator.test.ts +492 -0
- package/src/tests/platform/thinq/thinqWasherCommandHandlers.test.ts +594 -0
- package/src/tests/platform/thinq/thinqWasherEndpointFactory.test.ts +84 -0
- package/src/tests/platform/thinq/thinqWasherStateSync.test.ts +373 -0
- package/src/tests/platform/thinq/thinqWasherStopCommandResolver.test.ts +392 -0
- package/src/tests/settings.test.ts +33 -0
- package/src/utils/mask.ts +50 -0
- package/tsconfig.base.json +25 -0
- package/tsconfig.json +9 -0
- package/tsconfig.production.json +13 -0
- package/tsconfig.vitest.json +5 -0
- package/vite.config.ts +43 -0
- package/wiki/memory-archive.md +12 -0
- package/wiki/reference-workspaces.md +23 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
export function createMockLogger() {
|
|
3
|
+
return {
|
|
4
|
+
debug: vi.fn(),
|
|
5
|
+
info: vi.fn(),
|
|
6
|
+
notice: vi.fn(),
|
|
7
|
+
warn: vi.fn(),
|
|
8
|
+
error: vi.fn(),
|
|
9
|
+
fatal: vi.fn(),
|
|
10
|
+
setMaxListeners: vi.fn(),
|
|
11
|
+
getMaxListeners: vi.fn(),
|
|
12
|
+
addListener: vi.fn(),
|
|
13
|
+
on: vi.fn(),
|
|
14
|
+
once: vi.fn(),
|
|
15
|
+
removeListener: vi.fn(),
|
|
16
|
+
off: vi.fn(),
|
|
17
|
+
removeAllListeners: vi.fn(),
|
|
18
|
+
listeners: vi.fn(),
|
|
19
|
+
rawListeners: vi.fn(),
|
|
20
|
+
emit: vi.fn(),
|
|
21
|
+
listenerCount: vi.fn(),
|
|
22
|
+
prependListener: vi.fn(),
|
|
23
|
+
prependOnceListener: vi.fn(),
|
|
24
|
+
eventNames: vi.fn(),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export function asPartial(partial) {
|
|
28
|
+
return partial;
|
|
29
|
+
}
|
|
30
|
+
export function buildGatewayResponse(overrides) {
|
|
31
|
+
return {
|
|
32
|
+
empTermsUri: 'https://emp-terms.lgecloud.com',
|
|
33
|
+
empSpxUri: 'https://emp-spx.lgecloud.com',
|
|
34
|
+
thinq2Uri: 'https://aic-service.lgecloud.com',
|
|
35
|
+
thinq1Uri: 'https://v1aic-service.lgecloud.com',
|
|
36
|
+
countryCode: 'US',
|
|
37
|
+
languageCode: 'en',
|
|
38
|
+
...overrides,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export function buildThinqDeviceData(overrides) {
|
|
42
|
+
return {
|
|
43
|
+
deviceId: '12345678-1234-1234-1234-123456789012',
|
|
44
|
+
alias: 'Living Room AC',
|
|
45
|
+
modelJsonUri: 'https://example.com/model.json',
|
|
46
|
+
deviceType: 401,
|
|
47
|
+
modelName: 'DualCool Plus',
|
|
48
|
+
manufacture: {
|
|
49
|
+
macAddress: '00:00:00:00:00:00',
|
|
50
|
+
salesModel: 'AC123',
|
|
51
|
+
serialNo: 'SN12345',
|
|
52
|
+
manufactureModel: 'AC123-MANU',
|
|
53
|
+
},
|
|
54
|
+
modemInfo: {
|
|
55
|
+
appVersion: '1.0',
|
|
56
|
+
modelName: 'AC123',
|
|
57
|
+
},
|
|
58
|
+
snapshot: {
|
|
59
|
+
online: true,
|
|
60
|
+
'airState.operation': 1,
|
|
61
|
+
'airState.tempState.current': 24,
|
|
62
|
+
'airState.tempState.target': 22,
|
|
63
|
+
'airState.opMode': 0,
|
|
64
|
+
'airState.windStrength': 2,
|
|
65
|
+
},
|
|
66
|
+
platformType: 'THINQ',
|
|
67
|
+
online: true,
|
|
68
|
+
...overrides,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export function createMockNodePersist() {
|
|
72
|
+
return {
|
|
73
|
+
getItem: vi.fn(),
|
|
74
|
+
setItem: vi.fn(),
|
|
75
|
+
removeItem: vi.fn(),
|
|
76
|
+
clear: vi.fn(),
|
|
77
|
+
keys: vi.fn(),
|
|
78
|
+
length: vi.fn(),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export function setReadOnlyProperty(obj, key, value) {
|
|
82
|
+
Object.defineProperty(obj, key, {
|
|
83
|
+
value,
|
|
84
|
+
writable: false,
|
|
85
|
+
configurable: true,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export function maskSecret(value, visibleChars = 4) {
|
|
2
|
+
if (!value) {
|
|
3
|
+
return '';
|
|
4
|
+
}
|
|
5
|
+
if (value.length <= visibleChars) {
|
|
6
|
+
return '*'.repeat(value.length);
|
|
7
|
+
}
|
|
8
|
+
return '*'.repeat(value.length - visibleChars) + value.slice(-visibleChars);
|
|
9
|
+
}
|
|
10
|
+
const SENSITIVE_FIELD_NAMES = new Set([
|
|
11
|
+
'refresh_token',
|
|
12
|
+
'refreshtoken',
|
|
13
|
+
'access_token',
|
|
14
|
+
'accesstoken',
|
|
15
|
+
'password',
|
|
16
|
+
'client_secret',
|
|
17
|
+
'clientsecret',
|
|
18
|
+
'secret',
|
|
19
|
+
'x-emp-token',
|
|
20
|
+
'authorization',
|
|
21
|
+
]);
|
|
22
|
+
export function maskSensitiveFields(source) {
|
|
23
|
+
if (!source) {
|
|
24
|
+
return source;
|
|
25
|
+
}
|
|
26
|
+
const result = {};
|
|
27
|
+
for (const [key, value] of Object.entries(source)) {
|
|
28
|
+
if (SENSITIVE_FIELD_NAMES.has(key.toLowerCase())) {
|
|
29
|
+
result[key] = typeof value === 'string' ? maskSecret(value) : value;
|
|
30
|
+
}
|
|
31
|
+
else if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
32
|
+
result[key] = maskSensitiveFields(value);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
result[key] = value;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# ThinQ CLI Login Helper
|
|
2
|
+
|
|
3
|
+
A standalone command-line tool for authenticating with LG ThinQ, saving your session, and listing discovered devices for use with the Matterbridge LG ThinQ plugin.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
Build the project first:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm run build:local
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This compiles TypeScript and generates the CLI binary at `dist/cli.js`.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
Run the CLI with:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm run cli -- --command <command> [options]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Commands
|
|
24
|
+
|
|
25
|
+
| Command | Options | Description |
|
|
26
|
+
| --------- | ----------------------------------- | ---------------------------------------------------- |
|
|
27
|
+
| `login` | `--type`, `--country`, `--language` | Authenticate and save session |
|
|
28
|
+
| `devices` | | List all discovered ThinQ devices (requires `login`) |
|
|
29
|
+
| `help` | | Show help message |
|
|
30
|
+
|
|
31
|
+
## Login Command
|
|
32
|
+
|
|
33
|
+
The `login` command guides you through authentication and saves your credentials to a local session file.
|
|
34
|
+
|
|
35
|
+
### Options
|
|
36
|
+
|
|
37
|
+
- `--type`: Authentication method (default: `account`)
|
|
38
|
+
- `account`: Username/password authentication
|
|
39
|
+
- `token`: Refresh token authentication
|
|
40
|
+
- `--country`: Country code (default: `US`) — must match your LG ThinQ account region
|
|
41
|
+
- `--language`: Language code (default: `en-US`)
|
|
42
|
+
- `--debug`: Enable debug logging
|
|
43
|
+
|
|
44
|
+
### Examples
|
|
45
|
+
|
|
46
|
+
#### Account-based authentication (default):
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm run cli -- --command login
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
You will be prompted for:
|
|
53
|
+
|
|
54
|
+
- Username (email)
|
|
55
|
+
- Password
|
|
56
|
+
|
|
57
|
+
#### Account-based authentication with specific region:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npm run cli -- --command login --type account --country KR --language ko-KR
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
#### Token-based authentication:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm run cli -- --command login --type token
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
You will be prompted for:
|
|
70
|
+
|
|
71
|
+
- Refresh token
|
|
72
|
+
|
|
73
|
+
### Example Session Output
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
Login successful. Session saved to .cli-session.json
|
|
77
|
+
Session Summary:
|
|
78
|
+
Login Type: account
|
|
79
|
+
Country: US
|
|
80
|
+
Language: en-US
|
|
81
|
+
Access Token: ****XXXX
|
|
82
|
+
Refresh Token: ****XXXX
|
|
83
|
+
Expires At: 2026-09-08T23:59:59.000Z
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Note: All tokens are masked in the output for security.
|
|
87
|
+
|
|
88
|
+
## Devices Command
|
|
89
|
+
|
|
90
|
+
The `devices` command lists all ThinQ devices discovered in your account, using the session saved by a prior `login` command.
|
|
91
|
+
|
|
92
|
+
### Options
|
|
93
|
+
|
|
94
|
+
- `--debug`: Enable debug logging
|
|
95
|
+
|
|
96
|
+
### Prerequisites
|
|
97
|
+
|
|
98
|
+
You must run `--command login` successfully first. If no session file is found, the command prints an error and exits.
|
|
99
|
+
|
|
100
|
+
### Example
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npm run cli -- --command devices
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Example Output
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
Found 2 device(s):
|
|
110
|
+
|
|
111
|
+
1. Living Room AC
|
|
112
|
+
Device ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890
|
|
113
|
+
Type: AC
|
|
114
|
+
Platform Type: thinq2
|
|
115
|
+
Model Name: RAC-1234
|
|
116
|
+
Online: true
|
|
117
|
+
|
|
118
|
+
2. Kitchen Fridge
|
|
119
|
+
Device ID: b2c3d4e5-f6a7-8901-bcde-f12345678901
|
|
120
|
+
Type: REFRIGERATOR
|
|
121
|
+
Platform Type: thinq2
|
|
122
|
+
Model Name: LRF-5678
|
|
123
|
+
Online: false
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Session File
|
|
127
|
+
|
|
128
|
+
After successful login, your session is saved to `.cli-session.json` in your working directory:
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"loginType": "account",
|
|
133
|
+
"country": "US",
|
|
134
|
+
"language": "en-US",
|
|
135
|
+
"userData": {
|
|
136
|
+
"accessToken": "...",
|
|
137
|
+
"refreshToken": "...",
|
|
138
|
+
"expiresAtEpochSeconds": 1234567890,
|
|
139
|
+
"country": "US",
|
|
140
|
+
"language": "en-US"
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**⚠️ Important:** This file contains authentication credentials. Keep it secure and do NOT commit it to version control (it is in `.gitignore` by default).
|
|
146
|
+
|
|
147
|
+
## Notes
|
|
148
|
+
|
|
149
|
+
### Supported Authentication Methods
|
|
150
|
+
|
|
151
|
+
- **Account (username/password):** Uses LG's standard account login flow
|
|
152
|
+
- **Refresh token:** For previously-saved tokens; skips the full login chain
|
|
153
|
+
|
|
154
|
+
### Browser-Based SSO
|
|
155
|
+
|
|
156
|
+
Third-party SSO (Google, Apple, Facebook, Amazon) is not yet supported in this CLI tool. If your account uses only these methods, you will need to use the Matterbridge web UI or manually obtain a refresh token.
|
|
157
|
+
|
|
158
|
+
### Device Control
|
|
159
|
+
|
|
160
|
+
This CLI supports authentication (`login`) and device discovery/listing (`devices`). Device control is not yet available and is handled by the full Matterbridge runtime instead.
|
|
161
|
+
|
|
162
|
+
### Credentials Security
|
|
163
|
+
|
|
164
|
+
- Passwords are **never printed** to the console or stored anywhere (only the token is saved).
|
|
165
|
+
- All displayed tokens are automatically masked for security.
|
|
166
|
+
- Input credentials are read interactively via the terminal, not from command-line arguments, to avoid exposure in shell history.
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import url from 'node:url';
|
|
3
|
+
|
|
4
|
+
import js from '@eslint/js';
|
|
5
|
+
import json from '@eslint/json';
|
|
6
|
+
import markdown from '@eslint/markdown';
|
|
7
|
+
import vitest from '@vitest/eslint-plugin';
|
|
8
|
+
import { defineConfig } from 'eslint/config';
|
|
9
|
+
import n from 'eslint-plugin-n';
|
|
10
|
+
import prettier from 'eslint-plugin-prettier/recommended';
|
|
11
|
+
import pluginSimpleImportSort from 'eslint-plugin-simple-import-sort';
|
|
12
|
+
import tseslint from 'typescript-eslint';
|
|
13
|
+
|
|
14
|
+
const sourceFiles = ['**/*.{js,mjs,cjs,ts,mts,cts}'];
|
|
15
|
+
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
|
|
16
|
+
|
|
17
|
+
export default defineConfig([
|
|
18
|
+
{
|
|
19
|
+
name: 'Global Ignores',
|
|
20
|
+
ignores: [
|
|
21
|
+
'dist/',
|
|
22
|
+
'build/',
|
|
23
|
+
'node_modules/',
|
|
24
|
+
'coverage/',
|
|
25
|
+
'report/',
|
|
26
|
+
'.claude/',
|
|
27
|
+
'vite.config.ts',
|
|
28
|
+
'docs/**/*',
|
|
29
|
+
'workspace/*',
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
{ ...js.configs.recommended, files: sourceFiles },
|
|
33
|
+
...tseslint.configs.stylistic.map((config) => ({ ...config, files: sourceFiles })),
|
|
34
|
+
...tseslint.configs.strictTypeChecked.map((config) => ({ ...config, files: sourceFiles })),
|
|
35
|
+
{ ...n.configs['flat/recommended-script'], files: sourceFiles },
|
|
36
|
+
prettier,
|
|
37
|
+
{
|
|
38
|
+
name: 'JavaScript & TypeScript Source Files',
|
|
39
|
+
files: sourceFiles,
|
|
40
|
+
languageOptions: {
|
|
41
|
+
sourceType: 'module',
|
|
42
|
+
ecmaVersion: 'latest',
|
|
43
|
+
},
|
|
44
|
+
linterOptions: {
|
|
45
|
+
reportUnusedDisableDirectives: 'error', // Report unused eslint-disable directives
|
|
46
|
+
reportUnusedInlineConfigs: 'error', // Report unused eslint-disable-line directives
|
|
47
|
+
},
|
|
48
|
+
plugins: {
|
|
49
|
+
js,
|
|
50
|
+
n,
|
|
51
|
+
'simple-import-sort': pluginSimpleImportSort,
|
|
52
|
+
},
|
|
53
|
+
extends: ['js/recommended'],
|
|
54
|
+
rules: {
|
|
55
|
+
'no-console': 'warn', // Warn on console usage
|
|
56
|
+
'no-undef': 'off',
|
|
57
|
+
'spaced-comment': ['error', 'always'], // Require space after comment markers. Deprecated, but we still want to enforce it cause it's not handled by Prettier
|
|
58
|
+
'@typescript-eslint/no-unused-vars': [
|
|
59
|
+
'error',
|
|
60
|
+
{
|
|
61
|
+
'args': 'none',
|
|
62
|
+
'varsIgnorePattern': '^_',
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
'no-unused-vars': 'warn', // Use the base rule for unused variables
|
|
66
|
+
'simple-import-sort/imports': ['warn'],
|
|
67
|
+
'simple-import-sort/exports': ['warn'],
|
|
68
|
+
'n/prefer-node-protocol': 'error', // Prefer using 'node:' protocol for built-in modules
|
|
69
|
+
'n/no-unsupported-features/node-builtins': ['error', { ignores: ['fetch'] }],
|
|
70
|
+
'n/no-extraneous-import': 'off', // Allow imports from node_modules
|
|
71
|
+
'n/no-unpublished-import': 'off', // Allow imports from unpublished packages
|
|
72
|
+
'n/no-missing-import': 'off', // Allow subpath imports from peer dependencies
|
|
73
|
+
'prettier/prettier': 'warn', // Use Prettier for formatting
|
|
74
|
+
'@typescript-eslint/no-unnecessary-condition': 'off',
|
|
75
|
+
'@typescript-eslint/restrict-template-expressions': 'off',
|
|
76
|
+
'@typescript-eslint/no-unsafe-assignment': 'off',
|
|
77
|
+
'@typescript-eslint/no-unsafe-member-access': 'off',
|
|
78
|
+
'@typescript-eslint/no-unsafe-call': 'off',
|
|
79
|
+
'@typescript-eslint/no-unsafe-return': 'off',
|
|
80
|
+
'@typescript-eslint/no-unsafe-argument': 'off',
|
|
81
|
+
'@typescript-eslint/unbound-method': 'off',
|
|
82
|
+
'@typescript-eslint/no-floating-promises': 'off',
|
|
83
|
+
'@typescript-eslint/require-await': 'off',
|
|
84
|
+
'@typescript-eslint/no-misused-promises': 'off',
|
|
85
|
+
'@typescript-eslint/no-unsafe-enum-comparison': 'off',
|
|
86
|
+
'@typescript-eslint/no-useless-default-assignment': 'off',
|
|
87
|
+
'@typescript-eslint/no-misused-spread': 'off',
|
|
88
|
+
'@typescript-eslint/no-confusing-void-expression': 'off',
|
|
89
|
+
'@typescript-eslint/no-redundant-type-constituents': 'off',
|
|
90
|
+
'@typescript-eslint/no-deprecated': 'off',
|
|
91
|
+
'@typescript-eslint/restrict-plus-operands': 'off',
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: 'JavaScript Source Files',
|
|
96
|
+
files: ['**/*.{js,mjs,cjs}'],
|
|
97
|
+
extends: [tseslint.configs.disableTypeChecked],
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: 'TypeScript Source Files',
|
|
101
|
+
files: ['**/*.ts'],
|
|
102
|
+
ignores: ['**/tests/**/*.ts'],
|
|
103
|
+
languageOptions: {
|
|
104
|
+
ecmaVersion: 'latest',
|
|
105
|
+
sourceType: 'module',
|
|
106
|
+
parser: tseslint.parser,
|
|
107
|
+
parserOptions: {
|
|
108
|
+
tsconfigRootDir: __dirname,
|
|
109
|
+
project: './tsconfig.json',
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
rules: {
|
|
113
|
+
'no-redeclare': 'off', // Disable no-redeclare for TypeScript files since TypeScript already checks for redeclarations
|
|
114
|
+
'no-undef': 'off', // Disable no-undef for TypeScript files since TypeScript already checks for undefined variables
|
|
115
|
+
'no-unused-vars': 'off', // Disable base rule for unused variables and use the TypeScript-specific rule instead
|
|
116
|
+
'@typescript-eslint/no-unused-vars': [
|
|
117
|
+
'error',
|
|
118
|
+
{
|
|
119
|
+
vars: 'all',
|
|
120
|
+
args: 'none',
|
|
121
|
+
ignoreRestSiblings: true,
|
|
122
|
+
varsIgnorePattern: '^_', // Ignore unused variables starting with _
|
|
123
|
+
caughtErrorsIgnorePattern: '^_', // Ignore unused caught errors starting with _
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
name: 'Vitest Test Files',
|
|
130
|
+
files: ['**/tests/**/*.ts'],
|
|
131
|
+
languageOptions: {
|
|
132
|
+
sourceType: 'module',
|
|
133
|
+
ecmaVersion: 'latest',
|
|
134
|
+
parser: tseslint.parser,
|
|
135
|
+
parserOptions: {
|
|
136
|
+
tsconfigRootDir: __dirname,
|
|
137
|
+
project: './tsconfig.vitest.json',
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
plugins: { vitest },
|
|
141
|
+
rules: {
|
|
142
|
+
'no-unused-vars': 'off', // Disable base rule for unused variables in test files
|
|
143
|
+
'@typescript-eslint/no-unused-vars': 'off', // Disable TypeScript rule for unused variables in test files
|
|
144
|
+
'@typescript-eslint/no-explicit-any': 'off', // Allow 'any' type in test files
|
|
145
|
+
'@typescript-eslint/no-empty-function': 'off', // Allow empty functions in test files
|
|
146
|
+
'@typescript-eslint/no-floating-promises': 'off', // Allow floating promises in tests
|
|
147
|
+
'@typescript-eslint/require-await': 'off', // Allow async without await in tests
|
|
148
|
+
'@typescript-eslint/no-deprecated': 'off', // Allow testing deprecated methods
|
|
149
|
+
|
|
150
|
+
'@typescript-eslint/no-confusing-void-expression': 'off',
|
|
151
|
+
'@typescript-eslint/no-unnecessary-type-assertion': 'off',
|
|
152
|
+
'@typescript-eslint/use-unknown-in-catch-callback-variable': 'off',
|
|
153
|
+
'@typescript-eslint/no-misused-spread': 'off',
|
|
154
|
+
'@typescript-eslint/no-unnecessary-type-parameters': 'off',
|
|
155
|
+
'@typescript-eslint/no-unnecessary-type-arguments': 'off',
|
|
156
|
+
|
|
157
|
+
...vitest.configs.recommended.rules,
|
|
158
|
+
'vitest/valid-expect': 'off',
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: 'CLI file',
|
|
163
|
+
files: ['src/cli.ts', 'src/cli/**'],
|
|
164
|
+
rules: {
|
|
165
|
+
'no-console': 'off',
|
|
166
|
+
'n/no-process-exit': 'off',
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: 'JSON Files',
|
|
171
|
+
files: ['**/*.json'],
|
|
172
|
+
ignores: ['**/devcontainer.json'],
|
|
173
|
+
plugins: { json },
|
|
174
|
+
language: 'json/json',
|
|
175
|
+
rules: {
|
|
176
|
+
'json/no-duplicate-keys': 'error',
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
name: 'JSONC files',
|
|
181
|
+
files: ['**/devcontainer.json', '**/*.jsonc'],
|
|
182
|
+
plugins: { json },
|
|
183
|
+
language: 'json/jsonc',
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: 'Markdown Files',
|
|
187
|
+
files: ['**/*.md'],
|
|
188
|
+
plugins: { markdown },
|
|
189
|
+
language: 'markdown/commonmark',
|
|
190
|
+
rules: {
|
|
191
|
+
'markdown/no-html': 'off', // Allow HTML in Markdown files
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
]);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "matterbridge-lg-thinq-plugin",
|
|
3
|
+
"type": "DynamicPlatform",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"thinq": {
|
|
6
|
+
"loginType": "account",
|
|
7
|
+
"username": "",
|
|
8
|
+
"password": "",
|
|
9
|
+
"refreshToken": "",
|
|
10
|
+
"country": "US",
|
|
11
|
+
"language": "en-US",
|
|
12
|
+
"refreshIntervalSeconds": 60,
|
|
13
|
+
"filterMonitoringIntervalSeconds": 3600,
|
|
14
|
+
"devices": []
|
|
15
|
+
},
|
|
16
|
+
"webos": {
|
|
17
|
+
"devices": []
|
|
18
|
+
},
|
|
19
|
+
"advancedFeature": {
|
|
20
|
+
"settings": {
|
|
21
|
+
"debug": true,
|
|
22
|
+
"clearStorageOnStartup": false,
|
|
23
|
+
"forceAuthentication": false,
|
|
24
|
+
"unregisterOnShutdown": false
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|