@switchbot/openapi-cli 3.2.0 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/client.d.ts +31 -0
- package/dist/api/client.js +236 -0
- package/dist/api/client.js.map +1 -0
- package/dist/auth.d.ts +1 -0
- package/dist/auth.js +21 -0
- package/dist/auth.js.map +1 -0
- package/dist/commands/agent-bootstrap.d.ts +10 -0
- package/dist/commands/agent-bootstrap.js +200 -0
- package/dist/commands/agent-bootstrap.js.map +1 -0
- package/dist/commands/auth.d.ts +18 -0
- package/dist/commands/auth.js +355 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/batch.d.ts +2 -0
- package/dist/commands/batch.js +414 -0
- package/dist/commands/batch.js.map +1 -0
- package/dist/commands/cache.d.ts +2 -0
- package/dist/commands/cache.js +127 -0
- package/dist/commands/cache.js.map +1 -0
- package/dist/commands/capabilities.d.ts +31 -0
- package/dist/commands/capabilities.js +383 -0
- package/dist/commands/capabilities.js.map +1 -0
- package/dist/commands/catalog.d.ts +2 -0
- package/dist/commands/catalog.js +360 -0
- package/dist/commands/catalog.js.map +1 -0
- package/dist/commands/completion.d.ts +2 -0
- package/dist/commands/completion.js +386 -0
- package/dist/commands/completion.js.map +1 -0
- package/dist/commands/config.d.ts +21 -0
- package/dist/commands/config.js +377 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/daemon.d.ts +2 -0
- package/dist/commands/daemon.js +411 -0
- package/dist/commands/daemon.js.map +1 -0
- package/dist/commands/device-meta.d.ts +2 -0
- package/dist/commands/device-meta.js +160 -0
- package/dist/commands/device-meta.js.map +1 -0
- package/dist/commands/devices.d.ts +2 -0
- package/dist/commands/devices.js +949 -0
- package/dist/commands/devices.js.map +1 -0
- package/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/doctor.js +1016 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/events.d.ts +31 -0
- package/dist/commands/events.js +564 -0
- package/dist/commands/events.js.map +1 -0
- package/dist/commands/expand.d.ts +2 -0
- package/dist/commands/expand.js +131 -0
- package/dist/commands/expand.js.map +1 -0
- package/dist/commands/explain.d.ts +2 -0
- package/dist/commands/explain.js +140 -0
- package/dist/commands/explain.js.map +1 -0
- package/dist/commands/health.d.ts +8 -0
- package/dist/commands/health.js +114 -0
- package/dist/commands/health.js.map +1 -0
- package/dist/commands/history.d.ts +2 -0
- package/dist/commands/history.js +321 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/identity.d.ts +45 -0
- package/dist/commands/identity.js +60 -0
- package/dist/commands/identity.js.map +1 -0
- package/dist/commands/install.d.ts +20 -0
- package/dist/commands/install.js +247 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/mcp.d.ts +14 -0
- package/dist/commands/mcp.js +2018 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/plan.d.ts +51 -0
- package/dist/commands/plan.js +654 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/policy.d.ts +24 -0
- package/dist/commands/policy.js +587 -0
- package/dist/commands/policy.js.map +1 -0
- package/dist/commands/quota.d.ts +2 -0
- package/dist/commands/quota.js +79 -0
- package/dist/commands/quota.js.map +1 -0
- package/dist/commands/rules.d.ts +2 -0
- package/dist/commands/rules.js +876 -0
- package/dist/commands/rules.js.map +1 -0
- package/dist/commands/scenes.d.ts +2 -0
- package/dist/commands/scenes.js +265 -0
- package/dist/commands/scenes.js.map +1 -0
- package/dist/commands/schema.d.ts +2 -0
- package/dist/commands/schema.js +185 -0
- package/dist/commands/schema.js.map +1 -0
- package/dist/commands/status-sync.d.ts +2 -0
- package/dist/commands/status-sync.js +132 -0
- package/dist/commands/status-sync.js.map +1 -0
- package/dist/commands/uninstall.d.ts +20 -0
- package/dist/commands/uninstall.js +238 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/upgrade-check.d.ts +2 -0
- package/dist/commands/upgrade-check.js +107 -0
- package/dist/commands/upgrade-check.js.map +1 -0
- package/dist/commands/watch.d.ts +2 -0
- package/dist/commands/watch.js +195 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/commands/webhook.d.ts +2 -0
- package/dist/commands/webhook.js +183 -0
- package/dist/commands/webhook.js.map +1 -0
- package/dist/config.d.ts +57 -0
- package/dist/config.js +259 -0
- package/dist/config.js.map +1 -0
- package/dist/credentials/backends/file.d.ts +18 -0
- package/dist/credentials/backends/file.js +102 -0
- package/dist/credentials/backends/file.js.map +1 -0
- package/dist/credentials/backends/linux.d.ts +16 -0
- package/dist/credentials/backends/linux.js +130 -0
- package/dist/credentials/backends/linux.js.map +1 -0
- package/dist/credentials/backends/macos.d.ts +18 -0
- package/dist/credentials/backends/macos.js +130 -0
- package/dist/credentials/backends/macos.js.map +1 -0
- package/dist/credentials/backends/windows.d.ts +23 -0
- package/dist/credentials/backends/windows.js +216 -0
- package/dist/credentials/backends/windows.js.map +1 -0
- package/dist/credentials/keychain.d.ts +83 -0
- package/dist/credentials/keychain.js +89 -0
- package/dist/credentials/keychain.js.map +1 -0
- package/dist/credentials/prime.d.ts +32 -0
- package/dist/credentials/prime.js +53 -0
- package/dist/credentials/prime.js.map +1 -0
- package/dist/devices/cache.d.ts +79 -0
- package/dist/devices/cache.js +294 -0
- package/dist/devices/cache.js.map +1 -0
- package/dist/devices/catalog.d.ts +138 -0
- package/dist/devices/catalog.js +768 -0
- package/dist/devices/catalog.js.map +1 -0
- package/dist/devices/device-meta.d.ts +15 -0
- package/dist/devices/device-meta.js +57 -0
- package/dist/devices/device-meta.js.map +1 -0
- package/dist/devices/history-agg.d.ts +37 -0
- package/dist/devices/history-agg.js +139 -0
- package/dist/devices/history-agg.js.map +1 -0
- package/dist/devices/history-query.d.ts +45 -0
- package/dist/devices/history-query.js +182 -0
- package/dist/devices/history-query.js.map +1 -0
- package/dist/devices/param-validator.d.ts +40 -0
- package/dist/devices/param-validator.js +434 -0
- package/dist/devices/param-validator.js.map +1 -0
- package/dist/devices/resources.d.ts +74 -0
- package/dist/devices/resources.js +271 -0
- package/dist/devices/resources.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +170 -56946
- package/dist/index.js.map +1 -0
- package/dist/install/default-steps.d.ts +66 -0
- package/dist/install/default-steps.js +258 -0
- package/dist/install/default-steps.js.map +1 -0
- package/dist/install/preflight.d.ts +60 -0
- package/dist/install/preflight.js +213 -0
- package/dist/install/preflight.js.map +1 -0
- package/dist/install/steps.d.ts +61 -0
- package/dist/install/steps.js +68 -0
- package/dist/install/steps.js.map +1 -0
- package/dist/lib/command-keywords.d.ts +5 -0
- package/dist/lib/command-keywords.js +18 -0
- package/dist/lib/command-keywords.js.map +1 -0
- package/dist/lib/daemon-state.d.ts +24 -0
- package/dist/lib/daemon-state.js +47 -0
- package/dist/lib/daemon-state.js.map +1 -0
- package/dist/lib/destructive-mode.d.ts +2 -0
- package/dist/lib/destructive-mode.js +13 -0
- package/dist/lib/destructive-mode.js.map +1 -0
- package/dist/lib/devices.d.ts +151 -0
- package/dist/lib/devices.js +383 -0
- package/dist/lib/devices.js.map +1 -0
- package/dist/lib/idempotency.d.ts +46 -0
- package/dist/lib/idempotency.js +107 -0
- package/dist/lib/idempotency.js.map +1 -0
- package/dist/lib/plan-store.d.ts +19 -0
- package/dist/lib/plan-store.js +69 -0
- package/dist/lib/plan-store.js.map +1 -0
- package/dist/lib/request-context.d.ts +7 -0
- package/dist/lib/request-context.js +13 -0
- package/dist/lib/request-context.js.map +1 -0
- package/dist/lib/scenes.d.ts +7 -0
- package/dist/lib/scenes.js +11 -0
- package/dist/lib/scenes.js.map +1 -0
- package/dist/logger.d.ts +4 -0
- package/dist/logger.js +17 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp/device-history.d.ts +36 -0
- package/dist/mcp/device-history.js +146 -0
- package/dist/mcp/device-history.js.map +1 -0
- package/dist/mcp/events-subscription.d.ts +45 -0
- package/dist/mcp/events-subscription.js +214 -0
- package/dist/mcp/events-subscription.js.map +1 -0
- package/dist/mqtt/client.d.ts +25 -0
- package/dist/mqtt/client.js +181 -0
- package/dist/mqtt/client.js.map +1 -0
- package/dist/mqtt/credential.d.ts +16 -0
- package/dist/mqtt/credential.js +31 -0
- package/dist/mqtt/credential.js.map +1 -0
- package/dist/policy/add-rule.d.ts +21 -0
- package/dist/policy/add-rule.js +125 -0
- package/dist/policy/add-rule.js.map +1 -0
- package/dist/policy/diff.d.ts +21 -0
- package/dist/policy/diff.js +92 -0
- package/dist/policy/diff.js.map +1 -0
- package/dist/policy/format.d.ts +6 -0
- package/dist/policy/format.js +58 -0
- package/dist/policy/format.js.map +1 -0
- package/dist/policy/load.d.ts +32 -0
- package/dist/policy/load.js +62 -0
- package/dist/policy/load.js.map +1 -0
- package/dist/policy/migrate.d.ts +21 -0
- package/dist/policy/migrate.js +68 -0
- package/dist/policy/migrate.js.map +1 -0
- package/dist/policy/schema.d.ts +5 -0
- package/dist/policy/schema.js +19 -0
- package/dist/policy/schema.js.map +1 -0
- package/dist/policy/validate.d.ts +19 -0
- package/dist/policy/validate.js +263 -0
- package/dist/policy/validate.js.map +1 -0
- package/dist/rules/action.d.ts +65 -0
- package/dist/rules/action.js +217 -0
- package/dist/rules/action.js.map +1 -0
- package/dist/rules/audit-query.d.ts +51 -0
- package/dist/rules/audit-query.js +90 -0
- package/dist/rules/audit-query.js.map +1 -0
- package/dist/rules/conflict-analyzer.d.ts +57 -0
- package/dist/rules/conflict-analyzer.js +215 -0
- package/dist/rules/conflict-analyzer.js.map +1 -0
- package/dist/rules/cron-scheduler.d.ts +62 -0
- package/dist/rules/cron-scheduler.js +187 -0
- package/dist/rules/cron-scheduler.js.map +1 -0
- package/dist/rules/destructive.d.ts +20 -0
- package/dist/rules/destructive.js +53 -0
- package/dist/rules/destructive.js.map +1 -0
- package/dist/rules/engine.d.ts +193 -0
- package/dist/rules/engine.js +758 -0
- package/dist/rules/engine.js.map +1 -0
- package/dist/rules/matcher.d.ts +56 -0
- package/dist/rules/matcher.js +231 -0
- package/dist/rules/matcher.js.map +1 -0
- package/dist/rules/pid-file.d.ts +43 -0
- package/dist/rules/pid-file.js +96 -0
- package/dist/rules/pid-file.js.map +1 -0
- package/dist/rules/quiet-hours.d.ts +26 -0
- package/dist/rules/quiet-hours.js +46 -0
- package/dist/rules/quiet-hours.js.map +1 -0
- package/dist/rules/suggest.d.ts +20 -0
- package/dist/rules/suggest.js +96 -0
- package/dist/rules/suggest.js.map +1 -0
- package/dist/rules/throttle.d.ts +61 -0
- package/dist/rules/throttle.js +117 -0
- package/dist/rules/throttle.js.map +1 -0
- package/dist/rules/types.d.ts +117 -0
- package/dist/rules/types.js +35 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/rules/webhook-listener.d.ts +63 -0
- package/dist/rules/webhook-listener.js +224 -0
- package/dist/rules/webhook-listener.js.map +1 -0
- package/dist/rules/webhook-token.d.ts +50 -0
- package/dist/rules/webhook-token.js +91 -0
- package/dist/rules/webhook-token.js.map +1 -0
- package/dist/schema/field-aliases.d.ts +34 -0
- package/dist/schema/field-aliases.js +132 -0
- package/dist/schema/field-aliases.js.map +1 -0
- package/dist/sinks/dispatcher.d.ts +7 -0
- package/dist/sinks/dispatcher.js +13 -0
- package/dist/sinks/dispatcher.js.map +1 -0
- package/dist/sinks/file.d.ts +6 -0
- package/dist/sinks/file.js +20 -0
- package/dist/sinks/file.js.map +1 -0
- package/dist/sinks/format.d.ts +20 -0
- package/dist/sinks/format.js +57 -0
- package/dist/sinks/format.js.map +1 -0
- package/dist/sinks/homeassistant.d.ts +18 -0
- package/dist/sinks/homeassistant.js +45 -0
- package/dist/sinks/homeassistant.js.map +1 -0
- package/dist/sinks/openclaw.d.ts +13 -0
- package/dist/sinks/openclaw.js +34 -0
- package/dist/sinks/openclaw.js.map +1 -0
- package/dist/sinks/stdout.d.ts +4 -0
- package/dist/sinks/stdout.js +6 -0
- package/dist/sinks/stdout.js.map +1 -0
- package/dist/sinks/telegram.d.ts +11 -0
- package/dist/sinks/telegram.js +29 -0
- package/dist/sinks/telegram.js.map +1 -0
- package/dist/sinks/types.d.ts +13 -0
- package/dist/sinks/types.js +2 -0
- package/dist/sinks/types.js.map +1 -0
- package/dist/sinks/webhook.d.ts +6 -0
- package/dist/sinks/webhook.js +23 -0
- package/dist/sinks/webhook.js.map +1 -0
- package/dist/status-sync/manager.d.ts +48 -0
- package/dist/status-sync/manager.js +269 -0
- package/dist/status-sync/manager.js.map +1 -0
- package/dist/utils/arg-parsers.d.ts +16 -0
- package/dist/utils/arg-parsers.js +67 -0
- package/dist/utils/arg-parsers.js.map +1 -0
- package/dist/utils/audit.d.ts +69 -0
- package/dist/utils/audit.js +122 -0
- package/dist/utils/audit.js.map +1 -0
- package/dist/utils/filter.d.ts +81 -0
- package/dist/utils/filter.js +190 -0
- package/dist/utils/filter.js.map +1 -0
- package/dist/utils/flags.d.ts +72 -0
- package/dist/utils/flags.js +187 -0
- package/dist/utils/flags.js.map +1 -0
- package/dist/utils/format.d.ts +9 -0
- package/dist/utils/format.js +118 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/health.d.ts +48 -0
- package/dist/utils/health.js +102 -0
- package/dist/utils/health.js.map +1 -0
- package/dist/utils/help-json.d.ts +39 -0
- package/dist/utils/help-json.js +55 -0
- package/dist/utils/help-json.js.map +1 -0
- package/dist/utils/name-resolver.d.ts +26 -0
- package/dist/utils/name-resolver.js +138 -0
- package/dist/utils/name-resolver.js.map +1 -0
- package/dist/utils/output.d.ts +73 -0
- package/dist/utils/output.js +405 -0
- package/dist/utils/output.js.map +1 -0
- package/dist/utils/quota.d.ts +61 -0
- package/dist/utils/quota.js +228 -0
- package/dist/utils/quota.js.map +1 -0
- package/dist/utils/redact.d.ts +23 -0
- package/dist/utils/redact.js +69 -0
- package/dist/utils/redact.js.map +1 -0
- package/dist/utils/retry.d.ts +72 -0
- package/dist/utils/retry.js +141 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/string.d.ts +2 -0
- package/dist/utils/string.js +23 -0
- package/dist/utils/string.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -0
- package/package.json +2 -2
package/dist/config.js
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import { getConfigPath } from './utils/flags.js';
|
|
5
|
+
import { getActiveProfile } from './lib/request-context.js';
|
|
6
|
+
import { emitJsonError, isJsonMode } from './utils/output.js';
|
|
7
|
+
import { getPrimedCredentials } from './credentials/prime.js';
|
|
8
|
+
function sanitizeOptionalString(v) {
|
|
9
|
+
if (typeof v !== 'string')
|
|
10
|
+
return undefined;
|
|
11
|
+
const trimmed = v.trim();
|
|
12
|
+
return trimmed ? trimmed : undefined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Credential file resolution priority:
|
|
16
|
+
* 1. --config <path> (absolute override — wins over everything)
|
|
17
|
+
* 2. active profile (ALS request context, else --profile flag) → ~/.switchbot/profiles/<name>.json
|
|
18
|
+
* 3. default → ~/.switchbot/config.json
|
|
19
|
+
*
|
|
20
|
+
* Env SWITCHBOT_TOKEN+SWITCHBOT_SECRET still take priority inside loadConfig.
|
|
21
|
+
*/
|
|
22
|
+
export function configFilePath() {
|
|
23
|
+
const override = getConfigPath();
|
|
24
|
+
if (override)
|
|
25
|
+
return path.resolve(override);
|
|
26
|
+
const profile = getActiveProfile();
|
|
27
|
+
if (profile) {
|
|
28
|
+
return path.join(os.homedir(), '.switchbot', 'profiles', `${profile}.json`);
|
|
29
|
+
}
|
|
30
|
+
return path.join(os.homedir(), '.switchbot', 'config.json');
|
|
31
|
+
}
|
|
32
|
+
export function profileFilePath(profile) {
|
|
33
|
+
return path.join(os.homedir(), '.switchbot', 'profiles', `${profile}.json`);
|
|
34
|
+
}
|
|
35
|
+
export function listProfiles() {
|
|
36
|
+
const dir = path.join(os.homedir(), '.switchbot', 'profiles');
|
|
37
|
+
if (!fs.existsSync(dir))
|
|
38
|
+
return [];
|
|
39
|
+
return fs.readdirSync(dir)
|
|
40
|
+
.filter((f) => f.endsWith('.json'))
|
|
41
|
+
.map((f) => f.slice(0, -5))
|
|
42
|
+
.sort();
|
|
43
|
+
}
|
|
44
|
+
export function loadConfig() {
|
|
45
|
+
const envToken = process.env.SWITCHBOT_TOKEN;
|
|
46
|
+
const envSecret = process.env.SWITCHBOT_SECRET;
|
|
47
|
+
if (envToken && envSecret) {
|
|
48
|
+
return { token: envToken, secret: envSecret };
|
|
49
|
+
}
|
|
50
|
+
// After env, try the OS keychain (via the priming cache populated at
|
|
51
|
+
// command start). When --config is passed we skip the keychain so the
|
|
52
|
+
// override remains authoritative.
|
|
53
|
+
if (!getConfigPath()) {
|
|
54
|
+
const primed = getPrimedCredentials(getActiveProfile() ?? 'default');
|
|
55
|
+
if (primed)
|
|
56
|
+
return primed;
|
|
57
|
+
}
|
|
58
|
+
const file = configFilePath();
|
|
59
|
+
if (!fs.existsSync(file)) {
|
|
60
|
+
const profile = getActiveProfile();
|
|
61
|
+
const hint = profile
|
|
62
|
+
? `No credentials configured for profile "${profile}". Run: switchbot --profile ${profile} config set-token <token> <secret>`
|
|
63
|
+
: 'No credentials configured. Run: switchbot config set-token <token> <secret>';
|
|
64
|
+
const msg = `${hint}\nOr set SWITCHBOT_TOKEN and SWITCHBOT_SECRET environment variables.`;
|
|
65
|
+
if (isJsonMode()) {
|
|
66
|
+
emitJsonError({ code: 1, kind: 'runtime', message: hint });
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
console.error(msg);
|
|
70
|
+
}
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const raw = fs.readFileSync(file, 'utf-8');
|
|
75
|
+
const cfg = JSON.parse(raw);
|
|
76
|
+
if (!cfg.token || !cfg.secret) {
|
|
77
|
+
if (isJsonMode()) {
|
|
78
|
+
emitJsonError({ code: 1, kind: 'runtime', message: 'Invalid config format. Please re-run: switchbot config set-token' });
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
console.error('Invalid config format. Please re-run: switchbot config set-token');
|
|
82
|
+
}
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
return cfg;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
if (isJsonMode()) {
|
|
89
|
+
emitJsonError({ code: 1, kind: 'runtime', message: 'Failed to read config file. Please re-run: switchbot config set-token' });
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
console.error('Failed to read config file. Please re-run: switchbot config set-token');
|
|
93
|
+
}
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Like loadConfig but returns null instead of exiting. Use this in code paths
|
|
99
|
+
* that want graceful degradation (e.g. optional MQTT init in `mcp serve`).
|
|
100
|
+
*/
|
|
101
|
+
export function tryLoadConfig() {
|
|
102
|
+
const envToken = process.env.SWITCHBOT_TOKEN;
|
|
103
|
+
const envSecret = process.env.SWITCHBOT_SECRET;
|
|
104
|
+
if (envToken && envSecret)
|
|
105
|
+
return { token: envToken, secret: envSecret };
|
|
106
|
+
if (!getConfigPath()) {
|
|
107
|
+
const primed = getPrimedCredentials(getActiveProfile() ?? 'default');
|
|
108
|
+
if (primed)
|
|
109
|
+
return primed;
|
|
110
|
+
}
|
|
111
|
+
const file = configFilePath();
|
|
112
|
+
if (!fs.existsSync(file))
|
|
113
|
+
return null;
|
|
114
|
+
try {
|
|
115
|
+
const raw = fs.readFileSync(file, 'utf-8');
|
|
116
|
+
const cfg = JSON.parse(raw);
|
|
117
|
+
if (!cfg.token || !cfg.secret)
|
|
118
|
+
return null;
|
|
119
|
+
return cfg;
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
export function saveConfig(token, secret, extras) {
|
|
126
|
+
const file = configFilePath();
|
|
127
|
+
const dir = path.dirname(file);
|
|
128
|
+
if (!fs.existsSync(dir)) {
|
|
129
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
130
|
+
}
|
|
131
|
+
// Merge with existing file so label/limits/defaults aren't dropped when the
|
|
132
|
+
// user just rotates the token.
|
|
133
|
+
let existing = {};
|
|
134
|
+
if (fs.existsSync(file)) {
|
|
135
|
+
try {
|
|
136
|
+
existing = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
existing = {};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const cfg = {
|
|
143
|
+
token,
|
|
144
|
+
secret,
|
|
145
|
+
...(existing.label ? { label: existing.label } : {}),
|
|
146
|
+
...(existing.description ? { description: existing.description } : {}),
|
|
147
|
+
...(existing.limits ? { limits: existing.limits } : {}),
|
|
148
|
+
...(existing.defaults ? { defaults: existing.defaults } : {}),
|
|
149
|
+
};
|
|
150
|
+
if (extras) {
|
|
151
|
+
const label = sanitizeOptionalString(extras.label);
|
|
152
|
+
const description = sanitizeOptionalString(extras.description);
|
|
153
|
+
if (label !== undefined)
|
|
154
|
+
cfg.label = label;
|
|
155
|
+
if (description !== undefined)
|
|
156
|
+
cfg.description = description;
|
|
157
|
+
if (extras.limits)
|
|
158
|
+
cfg.limits = { ...(cfg.limits ?? {}), ...extras.limits };
|
|
159
|
+
if (extras.defaults)
|
|
160
|
+
cfg.defaults = { ...(cfg.defaults ?? {}), ...extras.defaults };
|
|
161
|
+
}
|
|
162
|
+
fs.writeFileSync(file, JSON.stringify(cfg, null, 2), { mode: 0o600 });
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Read a profile's metadata (label / description / limits / defaults) without
|
|
166
|
+
* exposing the token/secret. Returns null when the file is missing or invalid.
|
|
167
|
+
*/
|
|
168
|
+
export function readProfileMeta(profile) {
|
|
169
|
+
const file = profile
|
|
170
|
+
? profileFilePath(profile)
|
|
171
|
+
: path.join(os.homedir(), '.switchbot', 'config.json');
|
|
172
|
+
if (!fs.existsSync(file))
|
|
173
|
+
return null;
|
|
174
|
+
try {
|
|
175
|
+
const raw = fs.readFileSync(file, 'utf-8');
|
|
176
|
+
const cfg = JSON.parse(raw);
|
|
177
|
+
return {
|
|
178
|
+
label: cfg.label,
|
|
179
|
+
description: cfg.description,
|
|
180
|
+
limits: cfg.limits,
|
|
181
|
+
defaults: cfg.defaults,
|
|
182
|
+
path: file,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
export function showConfig() {
|
|
190
|
+
const summary = getConfigSummary();
|
|
191
|
+
if (summary.source === 'env') {
|
|
192
|
+
console.log('Credential source: environment variables');
|
|
193
|
+
console.log(`token : ${summary.token ?? ''}`);
|
|
194
|
+
console.log(`secret: ${summary.secret ?? ''}`);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (summary.source === 'none') {
|
|
198
|
+
console.log('No credentials configured');
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (summary.source === 'invalid') {
|
|
202
|
+
console.error('Failed to read config file');
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
console.log(`Credential source: ${summary.path}`);
|
|
206
|
+
if (summary.label)
|
|
207
|
+
console.log(`label : ${summary.label}`);
|
|
208
|
+
if (summary.description)
|
|
209
|
+
console.log(`desc : ${summary.description}`);
|
|
210
|
+
console.log(`token : ${summary.token ?? ''}`);
|
|
211
|
+
console.log(`secret: ${summary.secret ?? ''}`);
|
|
212
|
+
if (summary.dailyCap)
|
|
213
|
+
console.log(`limits: dailyCap=${summary.dailyCap}`);
|
|
214
|
+
if (summary.defaultFlags?.length)
|
|
215
|
+
console.log(`defaults: ${summary.defaultFlags.join(' ')}`);
|
|
216
|
+
}
|
|
217
|
+
export function getConfigSummary() {
|
|
218
|
+
const envToken = process.env.SWITCHBOT_TOKEN;
|
|
219
|
+
const envSecret = process.env.SWITCHBOT_SECRET;
|
|
220
|
+
if (envToken && envSecret) {
|
|
221
|
+
return {
|
|
222
|
+
source: 'env',
|
|
223
|
+
token: maskCredential(envToken),
|
|
224
|
+
secret: maskSecret(envSecret),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
const file = configFilePath();
|
|
228
|
+
if (!fs.existsSync(file)) {
|
|
229
|
+
return { source: 'none' };
|
|
230
|
+
}
|
|
231
|
+
try {
|
|
232
|
+
const raw = fs.readFileSync(file, 'utf-8');
|
|
233
|
+
const cfg = JSON.parse(raw);
|
|
234
|
+
return {
|
|
235
|
+
source: 'file',
|
|
236
|
+
path: file,
|
|
237
|
+
label: cfg.label,
|
|
238
|
+
description: cfg.description,
|
|
239
|
+
token: maskCredential(cfg.token),
|
|
240
|
+
secret: maskSecret(cfg.secret),
|
|
241
|
+
dailyCap: cfg.limits?.dailyCap,
|
|
242
|
+
defaultFlags: cfg.defaults?.flags,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
return { source: 'invalid', path: file };
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function maskCredential(token) {
|
|
250
|
+
if (token.length <= 8)
|
|
251
|
+
return '*'.repeat(Math.max(4, token.length));
|
|
252
|
+
return token.slice(0, 4) + '*'.repeat(token.length - 8) + token.slice(-4);
|
|
253
|
+
}
|
|
254
|
+
function maskSecret(secret) {
|
|
255
|
+
if (secret.length <= 4)
|
|
256
|
+
return '****';
|
|
257
|
+
return secret.slice(0, 2) + '*'.repeat(secret.length - 4) + secret.slice(-2);
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-backed credential store.
|
|
3
|
+
*
|
|
4
|
+
* Reads/writes the same `~/.switchbot/config.json` shape the CLI has
|
|
5
|
+
* used since v1.0, so a fresh install on a machine without a keychain
|
|
6
|
+
* still works and legacy users can migrate in-place via
|
|
7
|
+
* `switchbot auth keychain migrate` without data loss.
|
|
8
|
+
*
|
|
9
|
+
* Profile layout (inherited from `src/config.ts`):
|
|
10
|
+
* - default profile → `~/.switchbot/config.json`
|
|
11
|
+
* - named profile → `~/.switchbot/profiles/<name>.json`
|
|
12
|
+
*
|
|
13
|
+
* This backend only owns the `token` and `secret` fields — label /
|
|
14
|
+
* description / limits / defaults are preserved on write by merging
|
|
15
|
+
* with the existing JSON, keeping parity with `saveConfig()`.
|
|
16
|
+
*/
|
|
17
|
+
import { CredentialStore } from '../keychain.js';
|
|
18
|
+
export declare function createFileBackend(): CredentialStore;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-backed credential store.
|
|
3
|
+
*
|
|
4
|
+
* Reads/writes the same `~/.switchbot/config.json` shape the CLI has
|
|
5
|
+
* used since v1.0, so a fresh install on a machine without a keychain
|
|
6
|
+
* still works and legacy users can migrate in-place via
|
|
7
|
+
* `switchbot auth keychain migrate` without data loss.
|
|
8
|
+
*
|
|
9
|
+
* Profile layout (inherited from `src/config.ts`):
|
|
10
|
+
* - default profile → `~/.switchbot/config.json`
|
|
11
|
+
* - named profile → `~/.switchbot/profiles/<name>.json`
|
|
12
|
+
*
|
|
13
|
+
* This backend only owns the `token` and `secret` fields — label /
|
|
14
|
+
* description / limits / defaults are preserved on write by merging
|
|
15
|
+
* with the existing JSON, keeping parity with `saveConfig()`.
|
|
16
|
+
*/
|
|
17
|
+
import fs from 'node:fs';
|
|
18
|
+
import os from 'node:os';
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
import { KeychainError, } from '../keychain.js';
|
|
21
|
+
function profilePath(profile) {
|
|
22
|
+
if (profile === 'default') {
|
|
23
|
+
return path.join(os.homedir(), '.switchbot', 'config.json');
|
|
24
|
+
}
|
|
25
|
+
return path.join(os.homedir(), '.switchbot', 'profiles', `${profile}.json`);
|
|
26
|
+
}
|
|
27
|
+
function readJson(file) {
|
|
28
|
+
if (!fs.existsSync(file))
|
|
29
|
+
return null;
|
|
30
|
+
try {
|
|
31
|
+
const raw = fs.readFileSync(file, 'utf-8');
|
|
32
|
+
const parsed = JSON.parse(raw);
|
|
33
|
+
return parsed && typeof parsed === 'object' ? parsed : null;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export function createFileBackend() {
|
|
40
|
+
return {
|
|
41
|
+
name: 'file',
|
|
42
|
+
async get(profile) {
|
|
43
|
+
const file = profilePath(profile);
|
|
44
|
+
const data = readJson(file);
|
|
45
|
+
if (!data)
|
|
46
|
+
return null;
|
|
47
|
+
const token = typeof data.token === 'string' ? data.token : '';
|
|
48
|
+
const secret = typeof data.secret === 'string' ? data.secret : '';
|
|
49
|
+
if (!token || !secret)
|
|
50
|
+
return null;
|
|
51
|
+
return { token, secret };
|
|
52
|
+
},
|
|
53
|
+
async set(profile, creds) {
|
|
54
|
+
const file = profilePath(profile);
|
|
55
|
+
const dir = path.dirname(file);
|
|
56
|
+
try {
|
|
57
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
58
|
+
const existing = readJson(file) ?? {};
|
|
59
|
+
const next = { ...existing, token: creds.token, secret: creds.secret };
|
|
60
|
+
fs.writeFileSync(file, JSON.stringify(next, null, 2), { mode: 0o600 });
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
64
|
+
throw new KeychainError('file', 'set', msg);
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
async delete(profile) {
|
|
68
|
+
const file = profilePath(profile);
|
|
69
|
+
try {
|
|
70
|
+
if (!fs.existsSync(file))
|
|
71
|
+
return;
|
|
72
|
+
const existing = readJson(file);
|
|
73
|
+
if (existing) {
|
|
74
|
+
delete existing.token;
|
|
75
|
+
delete existing.secret;
|
|
76
|
+
if (Object.keys(existing).length === 0) {
|
|
77
|
+
fs.unlinkSync(file);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
fs.writeFileSync(file, JSON.stringify(existing, null, 2), { mode: 0o600 });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
fs.unlinkSync(file);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
89
|
+
throw new KeychainError('file', 'delete', msg);
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
describe() {
|
|
93
|
+
return {
|
|
94
|
+
backend: 'File (~/.switchbot/)',
|
|
95
|
+
tag: 'file',
|
|
96
|
+
writable: true,
|
|
97
|
+
notes: 'Last-resort fallback; credentials stored in a 0600 JSON file.',
|
|
98
|
+
};
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.js","sourceRoot":"","sources":["../../../src/credentials/backends/file.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linux libsecret backend.
|
|
3
|
+
*
|
|
4
|
+
* Shells out to `secret-tool(1)` — the libsecret CLI shipped by most
|
|
5
|
+
* distros when GNOME Keyring or KWallet is available. We intentionally
|
|
6
|
+
* avoid a native binding so `npm install` doesn't drag in a build
|
|
7
|
+
* toolchain on minimal CI images.
|
|
8
|
+
*
|
|
9
|
+
* On a fresh Linux box without secret-tool installed (or without a
|
|
10
|
+
* secret service daemon running), `linuxAvailable()` returns false and
|
|
11
|
+
* `selectCredentialStore()` falls back to the file backend. We do NOT
|
|
12
|
+
* try to `apt install libsecret-tools` on the user's behalf.
|
|
13
|
+
*/
|
|
14
|
+
import { CredentialStore } from '../keychain.js';
|
|
15
|
+
export declare function linuxAvailable(): Promise<boolean>;
|
|
16
|
+
export declare function createLinuxBackend(): CredentialStore;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linux libsecret backend.
|
|
3
|
+
*
|
|
4
|
+
* Shells out to `secret-tool(1)` — the libsecret CLI shipped by most
|
|
5
|
+
* distros when GNOME Keyring or KWallet is available. We intentionally
|
|
6
|
+
* avoid a native binding so `npm install` doesn't drag in a build
|
|
7
|
+
* toolchain on minimal CI images.
|
|
8
|
+
*
|
|
9
|
+
* On a fresh Linux box without secret-tool installed (or without a
|
|
10
|
+
* secret service daemon running), `linuxAvailable()` returns false and
|
|
11
|
+
* `selectCredentialStore()` falls back to the file backend. We do NOT
|
|
12
|
+
* try to `apt install libsecret-tools` on the user's behalf.
|
|
13
|
+
*/
|
|
14
|
+
import { spawn } from 'node:child_process';
|
|
15
|
+
import { accountFor, CREDENTIAL_SERVICE, KeychainError, } from '../keychain.js';
|
|
16
|
+
function run(cmd, args, stdin) {
|
|
17
|
+
return new Promise((resolve) => {
|
|
18
|
+
const proc = spawn(cmd, args, { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
19
|
+
let stdout = '';
|
|
20
|
+
let stderr = '';
|
|
21
|
+
proc.stdout.on('data', (buf) => {
|
|
22
|
+
stdout += buf.toString('utf-8');
|
|
23
|
+
});
|
|
24
|
+
proc.stderr.on('data', (buf) => {
|
|
25
|
+
stderr += buf.toString('utf-8');
|
|
26
|
+
});
|
|
27
|
+
proc.on('error', () => resolve({ code: 127, stdout, stderr }));
|
|
28
|
+
proc.on('close', (code) => resolve({ code: code ?? 0, stdout, stderr }));
|
|
29
|
+
if (stdin !== undefined) {
|
|
30
|
+
proc.stdin.write(stdin);
|
|
31
|
+
}
|
|
32
|
+
proc.stdin.end();
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export async function linuxAvailable() {
|
|
36
|
+
if (process.platform !== 'linux')
|
|
37
|
+
return false;
|
|
38
|
+
const which = await run('which', ['secret-tool']);
|
|
39
|
+
if (which.code !== 0 || which.stdout.trim().length === 0)
|
|
40
|
+
return false;
|
|
41
|
+
// Probe the secret service is actually running. `secret-tool search`
|
|
42
|
+
// with a bogus attribute returns 0 on miss but 1 when the D-Bus
|
|
43
|
+
// service isn't reachable — so we use the exit code to distinguish.
|
|
44
|
+
const probe = await run('secret-tool', ['search', 'service', CREDENTIAL_SERVICE]);
|
|
45
|
+
return probe.code === 0 || probe.code === 1;
|
|
46
|
+
}
|
|
47
|
+
async function readField(profile, field) {
|
|
48
|
+
const account = accountFor(profile, field);
|
|
49
|
+
const res = await run('secret-tool', [
|
|
50
|
+
'lookup',
|
|
51
|
+
'service', CREDENTIAL_SERVICE,
|
|
52
|
+
'account', account,
|
|
53
|
+
]);
|
|
54
|
+
if (res.code !== 0)
|
|
55
|
+
return null;
|
|
56
|
+
const value = res.stdout.replace(/\n$/, '');
|
|
57
|
+
return value.length > 0 ? value : null;
|
|
58
|
+
}
|
|
59
|
+
async function writeField(profile, field, value) {
|
|
60
|
+
const account = accountFor(profile, field);
|
|
61
|
+
const label = `SwitchBot CLI (${account})`;
|
|
62
|
+
// `secret-tool store` reads the password from stdin.
|
|
63
|
+
const res = await run('secret-tool', ['store', '--label', label, 'service', CREDENTIAL_SERVICE, 'account', account], value);
|
|
64
|
+
if (res.code !== 0) {
|
|
65
|
+
throw new KeychainError('secret-service', 'set', `secret-tool exit ${res.code}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function deleteField(profile, field) {
|
|
69
|
+
const account = accountFor(profile, field);
|
|
70
|
+
const res = await run('secret-tool', [
|
|
71
|
+
'clear',
|
|
72
|
+
'service', CREDENTIAL_SERVICE,
|
|
73
|
+
'account', account,
|
|
74
|
+
]);
|
|
75
|
+
// secret-tool returns 0 even when nothing matched, so we tolerate
|
|
76
|
+
// both 0 and the "nothing to clear" path transparently.
|
|
77
|
+
if (res.code !== 0) {
|
|
78
|
+
throw new KeychainError('secret-service', 'delete', `secret-tool exit ${res.code}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async function restoreField(profile, field, value) {
|
|
82
|
+
try {
|
|
83
|
+
if (value === null) {
|
|
84
|
+
await deleteField(profile, field);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
await writeField(profile, field, value);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Best effort only. The original write error is the actionable failure.
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export function createLinuxBackend() {
|
|
94
|
+
return {
|
|
95
|
+
name: 'secret-service',
|
|
96
|
+
async get(profile) {
|
|
97
|
+
const token = await readField(profile, 'token');
|
|
98
|
+
const secret = await readField(profile, 'secret');
|
|
99
|
+
if (!token || !secret)
|
|
100
|
+
return null;
|
|
101
|
+
return { token, secret };
|
|
102
|
+
},
|
|
103
|
+
async set(profile, creds) {
|
|
104
|
+
const previousToken = await readField(profile, 'token');
|
|
105
|
+
const previousSecret = await readField(profile, 'secret');
|
|
106
|
+
try {
|
|
107
|
+
await writeField(profile, 'token', creds.token);
|
|
108
|
+
await writeField(profile, 'secret', creds.secret);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
await restoreField(profile, 'token', previousToken);
|
|
112
|
+
await restoreField(profile, 'secret', previousSecret);
|
|
113
|
+
throw err;
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
async delete(profile) {
|
|
117
|
+
await deleteField(profile, 'token');
|
|
118
|
+
await deleteField(profile, 'secret');
|
|
119
|
+
},
|
|
120
|
+
describe() {
|
|
121
|
+
return {
|
|
122
|
+
backend: 'Secret Service (libsecret)',
|
|
123
|
+
tag: 'secret-service',
|
|
124
|
+
writable: true,
|
|
125
|
+
notes: `Stored under service "${CREDENTIAL_SERVICE}" via secret-tool.`,
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=linux.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linux.js","sourceRoot":"","sources":["../../../src/credentials/backends/linux.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* macOS Keychain backend.
|
|
3
|
+
*
|
|
4
|
+
* Wraps the built-in `security(1)` CLI so `npm install` stays free of
|
|
5
|
+
* native compile steps. Service name is shared with the Linux and
|
|
6
|
+
* Windows backends (`com.openclaw.switchbot`), so a user migrating a
|
|
7
|
+
* config between machines sees the same lookup shape.
|
|
8
|
+
*
|
|
9
|
+
* Errors never leak credential material — `add-generic-password`
|
|
10
|
+
* receives the password via `-w <value>` on argv, which is visible in
|
|
11
|
+
* `ps` to the current user but not persisted anywhere, and any stderr
|
|
12
|
+
* we surface back up is bounded to the library's own messages
|
|
13
|
+
* (`password not found`, `could not be added`, etc.) rather than our
|
|
14
|
+
* input values.
|
|
15
|
+
*/
|
|
16
|
+
import { CredentialStore } from '../keychain.js';
|
|
17
|
+
export declare function macOsAvailable(): Promise<boolean>;
|
|
18
|
+
export declare function createMacOsBackend(): CredentialStore;
|