@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
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { printJson, isJsonMode, handleError, UsageError, emitStreamHeader } from '../utils/output.js';
|
|
2
|
+
import { fetchDeviceStatus } from '../lib/devices.js';
|
|
3
|
+
import { getCachedDevice } from '../devices/cache.js';
|
|
4
|
+
import { parseDurationToMs, getFields } from '../utils/flags.js';
|
|
5
|
+
import { intArg, durationArg, stringArg } from '../utils/arg-parsers.js';
|
|
6
|
+
import { createClient } from '../api/client.js';
|
|
7
|
+
import { resolveDeviceId } from '../utils/name-resolver.js';
|
|
8
|
+
import { resolveFieldList, listAllCanonical } from '../schema/field-aliases.js';
|
|
9
|
+
const DEFAULT_INTERVAL_MS = 30_000;
|
|
10
|
+
const MIN_INTERVAL_MS = 1_000;
|
|
11
|
+
function diff(prev, next, fields) {
|
|
12
|
+
const out = {};
|
|
13
|
+
const keys = fields ?? Object.keys(next);
|
|
14
|
+
for (const k of keys) {
|
|
15
|
+
const a = prev ? prev[k] : undefined;
|
|
16
|
+
const b = next[k];
|
|
17
|
+
if (JSON.stringify(a) !== JSON.stringify(b)) {
|
|
18
|
+
out[k] = { from: prev ? a : null, to: b };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
function formatHumanLine(ev) {
|
|
24
|
+
const when = new Date(ev.t).toLocaleTimeString();
|
|
25
|
+
const head = `[${when}] ${ev.deviceId}${ev.type ? ` (${ev.type})` : ''}`;
|
|
26
|
+
if (ev.error)
|
|
27
|
+
return `${head}: error — ${ev.error}`;
|
|
28
|
+
const keys = Object.keys(ev.changed);
|
|
29
|
+
if (keys.length === 0)
|
|
30
|
+
return `${head}: no changes`;
|
|
31
|
+
const pairs = keys
|
|
32
|
+
.map((k) => {
|
|
33
|
+
const { from, to } = ev.changed[k];
|
|
34
|
+
if (from === null || from === undefined)
|
|
35
|
+
return `${k}=${JSON.stringify(to)}`;
|
|
36
|
+
return `${k}: ${JSON.stringify(from)} → ${JSON.stringify(to)}`;
|
|
37
|
+
})
|
|
38
|
+
.join(', ');
|
|
39
|
+
return `${head} ${pairs}`;
|
|
40
|
+
}
|
|
41
|
+
function sleep(ms, signal) {
|
|
42
|
+
return new Promise((resolve) => {
|
|
43
|
+
const t = setTimeout(() => resolve(), ms);
|
|
44
|
+
const onAbort = () => {
|
|
45
|
+
clearTimeout(t);
|
|
46
|
+
resolve();
|
|
47
|
+
};
|
|
48
|
+
if (signal.aborted) {
|
|
49
|
+
clearTimeout(t);
|
|
50
|
+
resolve();
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
export function registerWatchCommand(devices) {
|
|
58
|
+
devices
|
|
59
|
+
.command('watch')
|
|
60
|
+
.description('Poll device status on an interval and emit field-level changes (JSONL)')
|
|
61
|
+
.argument('[deviceId...]', 'One or more deviceIds to watch (or use --name for one device)')
|
|
62
|
+
.option('--name <query>', 'Resolve one device by fuzzy name (combined with any positional IDs)', stringArg('--name'))
|
|
63
|
+
.option('--interval <dur>', `Polling interval: "30s", "1m", "500ms", ... (default 30s, min ${MIN_INTERVAL_MS / 1000}s)`, durationArg('--interval'), '30s')
|
|
64
|
+
.option('--max <n>', 'Stop after N ticks (default: run until Ctrl-C)', intArg('--max', { min: 1 }))
|
|
65
|
+
.option('--for <dur>', 'Stop after elapsed time (e.g. "5m", "30s"). Combines with --max: first limit wins.', durationArg('--for'))
|
|
66
|
+
.option('--include-unchanged', 'Emit a tick even when no field changed')
|
|
67
|
+
.addHelpText('after', `
|
|
68
|
+
Each poll emits one JSON line per deviceId with the shape:
|
|
69
|
+
{ "t": "<ISO>", "tick": <n>, "deviceId": "ID", "type": "Bot",
|
|
70
|
+
"changed": { "power": { "from": "off", "to": "on" } } }
|
|
71
|
+
|
|
72
|
+
The very first poll has "from": null for every field (seed).
|
|
73
|
+
|
|
74
|
+
Examples:
|
|
75
|
+
$ switchbot devices watch ABC123 --interval 10s
|
|
76
|
+
$ switchbot devices watch ABC123 --fields battery,power --interval 1m
|
|
77
|
+
$ switchbot devices watch ABC123 DEF456 --interval 30s --max 10
|
|
78
|
+
$ switchbot devices watch ABC123 --json | jq 'select(.changed.power)'
|
|
79
|
+
$ switchbot devices watch --name "Living Room AC" --interval 10s
|
|
80
|
+
`)
|
|
81
|
+
.action(async (deviceIds, options) => {
|
|
82
|
+
try {
|
|
83
|
+
const allIds = [...deviceIds];
|
|
84
|
+
if (options.name) {
|
|
85
|
+
const resolved = resolveDeviceId(undefined, options.name);
|
|
86
|
+
if (!allIds.includes(resolved))
|
|
87
|
+
allIds.push(resolved);
|
|
88
|
+
}
|
|
89
|
+
if (allIds.length === 0)
|
|
90
|
+
throw new UsageError('Provide at least one deviceId argument or --name.');
|
|
91
|
+
const parsed = parseDurationToMs(options.interval);
|
|
92
|
+
if (parsed === null || parsed < MIN_INTERVAL_MS) {
|
|
93
|
+
throw new UsageError(`Invalid --interval "${options.interval}". Minimum is ${MIN_INTERVAL_MS / 1000}s.`);
|
|
94
|
+
}
|
|
95
|
+
const intervalMs = parsed;
|
|
96
|
+
let maxTicks = null;
|
|
97
|
+
if (options.max !== undefined) {
|
|
98
|
+
const n = Number(options.max);
|
|
99
|
+
if (!Number.isFinite(n) || n < 1) {
|
|
100
|
+
throw new UsageError(`Invalid --max "${options.max}". Must be a positive integer.`);
|
|
101
|
+
}
|
|
102
|
+
maxTicks = Math.floor(n);
|
|
103
|
+
}
|
|
104
|
+
const forMs = options.for ? parseDurationToMs(options.for) : null;
|
|
105
|
+
const rawFields = getFields() ?? null;
|
|
106
|
+
// Resolve aliases upfront against the static canonical registry.
|
|
107
|
+
// Validating here lets UsageError exit the command before any
|
|
108
|
+
// polling starts, and keeps mid-loop error handling free of
|
|
109
|
+
// "misuse" concerns. Unknown fields that are not registered as
|
|
110
|
+
// aliases but happen to match an API key pass through unchanged.
|
|
111
|
+
const fields = rawFields
|
|
112
|
+
? resolveFieldList(rawFields, listAllCanonical())
|
|
113
|
+
: null;
|
|
114
|
+
const ac = new AbortController();
|
|
115
|
+
const onSig = () => ac.abort();
|
|
116
|
+
process.on('SIGINT', onSig);
|
|
117
|
+
process.on('SIGTERM', onSig);
|
|
118
|
+
const forTimer = forMs !== null && forMs > 0
|
|
119
|
+
? setTimeout(() => ac.abort(), forMs)
|
|
120
|
+
: null;
|
|
121
|
+
// P7: streaming JSON contract — first line under --json is the
|
|
122
|
+
// stream header so consumers can route by eventKind/cadence.
|
|
123
|
+
if (isJsonMode())
|
|
124
|
+
emitStreamHeader({ eventKind: 'tick', cadence: 'poll' });
|
|
125
|
+
try {
|
|
126
|
+
const prev = new Map();
|
|
127
|
+
const client = createClient();
|
|
128
|
+
let tick = 0;
|
|
129
|
+
while (!ac.signal.aborted) {
|
|
130
|
+
tick++;
|
|
131
|
+
const t = new Date().toISOString();
|
|
132
|
+
// Poll all devices in parallel; one failure per device doesn't stop
|
|
133
|
+
// the others.
|
|
134
|
+
await Promise.all(allIds.map(async (id) => {
|
|
135
|
+
const cached = getCachedDevice(id);
|
|
136
|
+
try {
|
|
137
|
+
const body = await fetchDeviceStatus(id, client);
|
|
138
|
+
const changed = diff(prev.get(id), body, fields);
|
|
139
|
+
prev.set(id, body);
|
|
140
|
+
if (Object.keys(changed).length === 0 && !options.includeUnchanged) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const ev = {
|
|
144
|
+
t,
|
|
145
|
+
tick,
|
|
146
|
+
deviceId: id,
|
|
147
|
+
type: cached?.type,
|
|
148
|
+
changed,
|
|
149
|
+
};
|
|
150
|
+
if (isJsonMode()) {
|
|
151
|
+
// JSONL: one event per line (printJson with newline).
|
|
152
|
+
printJson(ev);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
console.log(formatHumanLine(ev));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
const ev = {
|
|
160
|
+
t,
|
|
161
|
+
tick,
|
|
162
|
+
deviceId: id,
|
|
163
|
+
type: cached?.type,
|
|
164
|
+
changed: {},
|
|
165
|
+
error: err instanceof Error ? err.message : String(err),
|
|
166
|
+
};
|
|
167
|
+
if (isJsonMode()) {
|
|
168
|
+
printJson(ev);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
console.error(formatHumanLine(ev));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}));
|
|
175
|
+
if (maxTicks !== null && tick >= maxTicks)
|
|
176
|
+
break;
|
|
177
|
+
await sleep(intervalMs, ac.signal);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
handleError(err);
|
|
182
|
+
}
|
|
183
|
+
finally {
|
|
184
|
+
if (forTimer)
|
|
185
|
+
clearTimeout(forTimer);
|
|
186
|
+
process.off('SIGINT', onSig);
|
|
187
|
+
process.off('SIGTERM', onSig);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
handleError(error);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=watch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { stringArg } from '../utils/arg-parsers.js';
|
|
2
|
+
import { createClient } from '../api/client.js';
|
|
3
|
+
import { printKeyValue, printJson, isJsonMode, handleError, UsageError } from '../utils/output.js';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
function assertValidUrl(url) {
|
|
6
|
+
let parsed;
|
|
7
|
+
try {
|
|
8
|
+
parsed = new URL(url);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
throw new UsageError(`Invalid URL "${url}" (expected absolute URL, e.g. https://example.com/hook)`);
|
|
12
|
+
}
|
|
13
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
14
|
+
throw new UsageError(`URL must use http:// or https:// (got "${parsed.protocol}")`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function registerWebhookCommand(program) {
|
|
18
|
+
const webhook = program
|
|
19
|
+
.command('webhook')
|
|
20
|
+
.description('Manage SwitchBot Webhook configuration')
|
|
21
|
+
.addHelpText('after', `
|
|
22
|
+
A webhook lets SwitchBot POST device state-change events to a URL you host.
|
|
23
|
+
Only one webhook URL can be active per account; "setup" registers it for ALL devices.
|
|
24
|
+
`);
|
|
25
|
+
// switchbot webhook setup <url>
|
|
26
|
+
webhook
|
|
27
|
+
.command('setup')
|
|
28
|
+
.description('Configure the webhook receiver URL (receives events from all devices)')
|
|
29
|
+
.argument('<url>', 'Absolute http(s):// URL where SwitchBot will POST events')
|
|
30
|
+
.addHelpText('after', `
|
|
31
|
+
Example:
|
|
32
|
+
$ switchbot webhook setup https://example.com/switchbot/events
|
|
33
|
+
`)
|
|
34
|
+
.action(async (url) => {
|
|
35
|
+
try {
|
|
36
|
+
assertValidUrl(url);
|
|
37
|
+
const client = createClient();
|
|
38
|
+
await client.post('/v1.1/webhook/setupWebhook', {
|
|
39
|
+
action: 'setupWebhook',
|
|
40
|
+
url,
|
|
41
|
+
deviceList: 'ALL',
|
|
42
|
+
});
|
|
43
|
+
if (isJsonMode()) {
|
|
44
|
+
printJson({ ok: true, url });
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.log(chalk.green(`✓ Webhook configured: ${url}`));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
handleError(error);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
// switchbot webhook query [--details <url>]
|
|
55
|
+
webhook
|
|
56
|
+
.command('query')
|
|
57
|
+
.description('Query webhook configuration')
|
|
58
|
+
.option('--details <url>', 'Query detailed configuration (enable/deviceList/timestamps) for a specific URL', stringArg('--details'))
|
|
59
|
+
.addHelpText('after', `
|
|
60
|
+
Without --details, lists all configured webhook URLs.
|
|
61
|
+
With --details, prints enable/deviceList/createTime/lastUpdateTime for the given URL.
|
|
62
|
+
|
|
63
|
+
Examples:
|
|
64
|
+
$ switchbot webhook query
|
|
65
|
+
$ switchbot webhook query --details https://example.com/hook
|
|
66
|
+
$ switchbot webhook query --json
|
|
67
|
+
`)
|
|
68
|
+
.action(async (options) => {
|
|
69
|
+
try {
|
|
70
|
+
const client = createClient();
|
|
71
|
+
if (options.details) {
|
|
72
|
+
const res = await client.post('/v1.1/webhook/queryWebhook', { action: 'queryDetails', urls: [options.details] });
|
|
73
|
+
if (isJsonMode()) {
|
|
74
|
+
printJson(res.data.body);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const details = res.data.body;
|
|
78
|
+
if (!details || details.length === 0) {
|
|
79
|
+
console.log('No webhook configuration found for this URL');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
for (const d of details) {
|
|
83
|
+
printKeyValue({
|
|
84
|
+
url: d.url,
|
|
85
|
+
enable: d.enable,
|
|
86
|
+
deviceList: d.deviceList,
|
|
87
|
+
createTime: new Date(d.createTime).toLocaleString(),
|
|
88
|
+
lastUpdateTime: new Date(d.lastUpdateTime).toLocaleString(),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const res = await client.post('/v1.1/webhook/queryWebhook', { action: 'queryUrl' });
|
|
94
|
+
if (isJsonMode()) {
|
|
95
|
+
printJson(res.data.body);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const urls = res.data.body.urls ?? [];
|
|
99
|
+
if (urls.length === 0) {
|
|
100
|
+
console.log('No webhooks configured');
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
console.log('Configured Webhook URLs:');
|
|
104
|
+
urls.forEach((u) => console.log(` ${chalk.cyan(u)}`));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
handleError(error);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
// switchbot webhook update <url> [--enable | --disable]
|
|
112
|
+
webhook
|
|
113
|
+
.command('update')
|
|
114
|
+
.description('Update webhook configuration (enable / disable a registered URL)')
|
|
115
|
+
.argument('<url>', 'URL of the webhook to update (must already be configured)')
|
|
116
|
+
.option('--enable', 'Enable the webhook')
|
|
117
|
+
.option('--disable', 'Disable the webhook')
|
|
118
|
+
.addHelpText('after', `
|
|
119
|
+
--enable and --disable are mutually exclusive. If neither is provided, the
|
|
120
|
+
webhook is re-submitted with no change to its enabled state.
|
|
121
|
+
|
|
122
|
+
Examples:
|
|
123
|
+
$ switchbot webhook update https://example.com/hook --enable
|
|
124
|
+
$ switchbot webhook update https://example.com/hook --disable
|
|
125
|
+
`)
|
|
126
|
+
.action(async (url, options) => {
|
|
127
|
+
try {
|
|
128
|
+
if (options.enable && options.disable) {
|
|
129
|
+
throw new UsageError('--enable and --disable are mutually exclusive');
|
|
130
|
+
}
|
|
131
|
+
assertValidUrl(url);
|
|
132
|
+
const client = createClient();
|
|
133
|
+
const config = { url };
|
|
134
|
+
if (options.enable)
|
|
135
|
+
config.enable = true;
|
|
136
|
+
if (options.disable)
|
|
137
|
+
config.enable = false;
|
|
138
|
+
await client.post('/v1.1/webhook/updateWebhook', {
|
|
139
|
+
action: 'updateWebhook',
|
|
140
|
+
config,
|
|
141
|
+
});
|
|
142
|
+
const statusText = options.enable ? 'enabled' : options.disable ? 'disabled' : 'updated';
|
|
143
|
+
if (isJsonMode()) {
|
|
144
|
+
printJson({ ok: true, url, status: statusText });
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
console.log(chalk.green(`✓ Webhook ${statusText}: ${url}`));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
handleError(error);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
// switchbot webhook delete <url>
|
|
155
|
+
webhook
|
|
156
|
+
.command('delete')
|
|
157
|
+
.description('Delete webhook configuration')
|
|
158
|
+
.argument('<url>', 'URL of the webhook to remove')
|
|
159
|
+
.addHelpText('after', `
|
|
160
|
+
Example:
|
|
161
|
+
$ switchbot webhook delete https://example.com/hook
|
|
162
|
+
`)
|
|
163
|
+
.action(async (url) => {
|
|
164
|
+
try {
|
|
165
|
+
assertValidUrl(url);
|
|
166
|
+
const client = createClient();
|
|
167
|
+
await client.post('/v1.1/webhook/deleteWebhook', {
|
|
168
|
+
action: 'deleteWebhook',
|
|
169
|
+
url,
|
|
170
|
+
});
|
|
171
|
+
if (isJsonMode()) {
|
|
172
|
+
printJson({ ok: true, url });
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
console.log(chalk.green(`✓ Webhook deleted: ${url}`));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
handleError(error);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=webhook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../src/commands/webhook.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export interface SwitchBotConfig {
|
|
2
|
+
token: string;
|
|
3
|
+
secret: string;
|
|
4
|
+
label?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
limits?: {
|
|
7
|
+
dailyCap?: number;
|
|
8
|
+
};
|
|
9
|
+
defaults?: {
|
|
10
|
+
flags?: string[];
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export interface ConfigSummary {
|
|
14
|
+
source: 'env' | 'file' | 'none' | 'invalid';
|
|
15
|
+
path?: string;
|
|
16
|
+
token?: string;
|
|
17
|
+
secret?: string;
|
|
18
|
+
label?: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
dailyCap?: number;
|
|
21
|
+
defaultFlags?: string[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Credential file resolution priority:
|
|
25
|
+
* 1. --config <path> (absolute override — wins over everything)
|
|
26
|
+
* 2. active profile (ALS request context, else --profile flag) → ~/.switchbot/profiles/<name>.json
|
|
27
|
+
* 3. default → ~/.switchbot/config.json
|
|
28
|
+
*
|
|
29
|
+
* Env SWITCHBOT_TOKEN+SWITCHBOT_SECRET still take priority inside loadConfig.
|
|
30
|
+
*/
|
|
31
|
+
export declare function configFilePath(): string;
|
|
32
|
+
export declare function profileFilePath(profile: string): string;
|
|
33
|
+
export declare function listProfiles(): string[];
|
|
34
|
+
export declare function loadConfig(): SwitchBotConfig;
|
|
35
|
+
/**
|
|
36
|
+
* Like loadConfig but returns null instead of exiting. Use this in code paths
|
|
37
|
+
* that want graceful degradation (e.g. optional MQTT init in `mcp serve`).
|
|
38
|
+
*/
|
|
39
|
+
export declare function tryLoadConfig(): SwitchBotConfig | null;
|
|
40
|
+
export declare function saveConfig(token: string, secret: string, extras?: Partial<SwitchBotConfig>): void;
|
|
41
|
+
/**
|
|
42
|
+
* Read a profile's metadata (label / description / limits / defaults) without
|
|
43
|
+
* exposing the token/secret. Returns null when the file is missing or invalid.
|
|
44
|
+
*/
|
|
45
|
+
export declare function readProfileMeta(profile?: string): {
|
|
46
|
+
label?: string;
|
|
47
|
+
description?: string;
|
|
48
|
+
limits?: {
|
|
49
|
+
dailyCap?: number;
|
|
50
|
+
};
|
|
51
|
+
defaults?: {
|
|
52
|
+
flags?: string[];
|
|
53
|
+
};
|
|
54
|
+
path: string;
|
|
55
|
+
} | null;
|
|
56
|
+
export declare function showConfig(): void;
|
|
57
|
+
export declare function getConfigSummary(): ConfigSummary;
|