@switchbot/openapi-cli 1.1.0 → 1.2.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.
Files changed (90) hide show
  1. package/README.md +174 -18
  2. package/dist/api/client.d.ts +7 -1
  3. package/dist/api/client.js +44 -8
  4. package/dist/api/client.js.map +1 -1
  5. package/dist/commands/batch.d.ts +2 -0
  6. package/dist/commands/batch.js +252 -0
  7. package/dist/commands/batch.js.map +1 -0
  8. package/dist/commands/cache.d.ts +2 -0
  9. package/dist/commands/cache.js +108 -0
  10. package/dist/commands/cache.js.map +1 -0
  11. package/dist/commands/capabilities.d.ts +2 -0
  12. package/dist/commands/capabilities.js +91 -0
  13. package/dist/commands/capabilities.js.map +1 -0
  14. package/dist/commands/catalog.d.ts +2 -0
  15. package/dist/commands/catalog.js +291 -0
  16. package/dist/commands/catalog.js.map +1 -0
  17. package/dist/commands/config.js +123 -10
  18. package/dist/commands/config.js.map +1 -1
  19. package/dist/commands/devices.js +234 -147
  20. package/dist/commands/devices.js.map +1 -1
  21. package/dist/commands/doctor.d.ts +2 -0
  22. package/dist/commands/doctor.js +147 -0
  23. package/dist/commands/doctor.js.map +1 -0
  24. package/dist/commands/events.d.ts +15 -0
  25. package/dist/commands/events.js +188 -0
  26. package/dist/commands/events.js.map +1 -0
  27. package/dist/commands/explain.d.ts +2 -0
  28. package/dist/commands/explain.js +137 -0
  29. package/dist/commands/explain.js.map +1 -0
  30. package/dist/commands/history.d.ts +2 -0
  31. package/dist/commands/history.js +104 -0
  32. package/dist/commands/history.js.map +1 -0
  33. package/dist/commands/mcp.d.ts +4 -0
  34. package/dist/commands/mcp.js +386 -0
  35. package/dist/commands/mcp.js.map +1 -0
  36. package/dist/commands/plan.d.ts +37 -0
  37. package/dist/commands/plan.js +344 -0
  38. package/dist/commands/plan.js.map +1 -0
  39. package/dist/commands/quota.d.ts +2 -0
  40. package/dist/commands/quota.js +77 -0
  41. package/dist/commands/quota.js.map +1 -0
  42. package/dist/commands/scenes.js +19 -13
  43. package/dist/commands/scenes.js.map +1 -1
  44. package/dist/commands/schema.d.ts +2 -0
  45. package/dist/commands/schema.js +77 -0
  46. package/dist/commands/schema.js.map +1 -0
  47. package/dist/commands/watch.d.ts +2 -0
  48. package/dist/commands/watch.js +161 -0
  49. package/dist/commands/watch.js.map +1 -0
  50. package/dist/commands/webhook.js +37 -22
  51. package/dist/commands/webhook.js.map +1 -1
  52. package/dist/config.d.ts +11 -0
  53. package/dist/config.js +32 -6
  54. package/dist/config.js.map +1 -1
  55. package/dist/devices/cache.d.ts +50 -0
  56. package/dist/devices/cache.js +152 -1
  57. package/dist/devices/cache.js.map +1 -1
  58. package/dist/devices/catalog.d.ts +49 -0
  59. package/dist/devices/catalog.js +362 -92
  60. package/dist/devices/catalog.js.map +1 -1
  61. package/dist/index.js +31 -1
  62. package/dist/index.js.map +1 -1
  63. package/dist/lib/devices.d.ts +144 -0
  64. package/dist/lib/devices.js +329 -0
  65. package/dist/lib/devices.js.map +1 -0
  66. package/dist/lib/scenes.d.ts +7 -0
  67. package/dist/lib/scenes.js +11 -0
  68. package/dist/lib/scenes.js.map +1 -0
  69. package/dist/utils/audit.d.ts +13 -0
  70. package/dist/utils/audit.js +43 -0
  71. package/dist/utils/audit.js.map +1 -0
  72. package/dist/utils/filter.d.ts +45 -0
  73. package/dist/utils/filter.js +96 -0
  74. package/dist/utils/filter.js.map +1 -0
  75. package/dist/utils/flags.d.ts +42 -0
  76. package/dist/utils/flags.js +108 -0
  77. package/dist/utils/flags.js.map +1 -1
  78. package/dist/utils/format.d.ts +9 -0
  79. package/dist/utils/format.js +109 -0
  80. package/dist/utils/format.js.map +1 -0
  81. package/dist/utils/output.d.ts +11 -0
  82. package/dist/utils/output.js +37 -6
  83. package/dist/utils/output.js.map +1 -1
  84. package/dist/utils/quota.d.ts +48 -0
  85. package/dist/utils/quota.js +144 -0
  86. package/dist/utils/quota.js.map +1 -0
  87. package/dist/utils/retry.d.ts +23 -0
  88. package/dist/utils/retry.js +60 -0
  89. package/dist/utils/retry.js.map +1 -0
  90. package/package.json +4 -1
@@ -0,0 +1,161 @@
1
+ import { printJson, isJsonMode, handleError, UsageError } 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
+ const DEFAULT_INTERVAL_MS = 30_000;
6
+ const MIN_INTERVAL_MS = 1_000;
7
+ function diff(prev, next, fields) {
8
+ const out = {};
9
+ const keys = fields ?? Object.keys(next);
10
+ for (const k of keys) {
11
+ const a = prev ? prev[k] : undefined;
12
+ const b = next[k];
13
+ if (JSON.stringify(a) !== JSON.stringify(b)) {
14
+ out[k] = { from: prev ? a : null, to: b };
15
+ }
16
+ }
17
+ return out;
18
+ }
19
+ function formatHumanLine(ev) {
20
+ const when = new Date(ev.t).toLocaleTimeString();
21
+ const head = `[${when}] ${ev.deviceId}${ev.type ? ` (${ev.type})` : ''}`;
22
+ if (ev.error)
23
+ return `${head}: error — ${ev.error}`;
24
+ const keys = Object.keys(ev.changed);
25
+ if (keys.length === 0)
26
+ return `${head}: no changes`;
27
+ const pairs = keys
28
+ .map((k) => {
29
+ const { from, to } = ev.changed[k];
30
+ if (from === null || from === undefined)
31
+ return `${k}=${JSON.stringify(to)}`;
32
+ return `${k}: ${JSON.stringify(from)} → ${JSON.stringify(to)}`;
33
+ })
34
+ .join(', ');
35
+ return `${head} ${pairs}`;
36
+ }
37
+ function sleep(ms, signal) {
38
+ return new Promise((resolve) => {
39
+ const t = setTimeout(() => resolve(), ms);
40
+ const onAbort = () => {
41
+ clearTimeout(t);
42
+ resolve();
43
+ };
44
+ if (signal.aborted) {
45
+ clearTimeout(t);
46
+ resolve();
47
+ }
48
+ else {
49
+ signal.addEventListener('abort', onAbort, { once: true });
50
+ }
51
+ });
52
+ }
53
+ export function registerWatchCommand(devices) {
54
+ devices
55
+ .command('watch')
56
+ .description('Poll device status on an interval and emit field-level changes (JSONL)')
57
+ .argument('<deviceId...>', 'One or more deviceIds to watch')
58
+ .option('--interval <dur>', `Polling interval: "30s", "1m", "500ms", ... (default 30s, min ${MIN_INTERVAL_MS / 1000}s)`, '30s')
59
+ .option('--max <n>', 'Stop after N ticks (default: run until Ctrl-C)')
60
+ .option('--include-unchanged', 'Emit a tick even when no field changed')
61
+ .addHelpText('after', `
62
+ Each poll emits one JSON line per deviceId with the shape:
63
+ { "t": "<ISO>", "tick": <n>, "deviceId": "ID", "type": "Bot",
64
+ "changed": { "power": { "from": "off", "to": "on" } } }
65
+
66
+ The very first poll has "from": null for every field (seed).
67
+
68
+ Examples:
69
+ $ switchbot devices watch ABC123 --interval 10s
70
+ $ switchbot devices watch ABC123 --fields battery,power --interval 1m
71
+ $ switchbot devices watch ABC123 DEF456 --interval 30s --max 10
72
+ $ switchbot devices watch ABC123 --json | jq 'select(.changed.power)'
73
+ `)
74
+ .action(async (deviceIds, options) => {
75
+ try {
76
+ const parsed = parseDurationToMs(options.interval);
77
+ if (parsed === null || parsed < MIN_INTERVAL_MS) {
78
+ throw new UsageError(`Invalid --interval "${options.interval}". Minimum is ${MIN_INTERVAL_MS / 1000}s.`);
79
+ }
80
+ const intervalMs = parsed;
81
+ let maxTicks = null;
82
+ if (options.max !== undefined) {
83
+ const n = Number(options.max);
84
+ if (!Number.isFinite(n) || n < 1) {
85
+ throw new UsageError(`Invalid --max "${options.max}". Must be a positive integer.`);
86
+ }
87
+ maxTicks = Math.floor(n);
88
+ }
89
+ const fields = getFields() ?? null;
90
+ const ac = new AbortController();
91
+ const onSig = () => ac.abort();
92
+ process.on('SIGINT', onSig);
93
+ process.on('SIGTERM', onSig);
94
+ try {
95
+ const prev = new Map();
96
+ let tick = 0;
97
+ while (!ac.signal.aborted) {
98
+ tick++;
99
+ const t = new Date().toISOString();
100
+ // Poll all devices in parallel; one failure per device doesn't stop
101
+ // the others.
102
+ await Promise.all(deviceIds.map(async (id) => {
103
+ const cached = getCachedDevice(id);
104
+ try {
105
+ const body = await fetchDeviceStatus(id);
106
+ const changed = diff(prev.get(id), body, fields);
107
+ prev.set(id, body);
108
+ if (Object.keys(changed).length === 0 && !options.includeUnchanged) {
109
+ return;
110
+ }
111
+ const ev = {
112
+ t,
113
+ tick,
114
+ deviceId: id,
115
+ type: cached?.type,
116
+ changed,
117
+ };
118
+ if (isJsonMode()) {
119
+ // JSONL: one event per line (printJson with newline).
120
+ printJson(ev);
121
+ }
122
+ else {
123
+ console.log(formatHumanLine(ev));
124
+ }
125
+ }
126
+ catch (err) {
127
+ const ev = {
128
+ t,
129
+ tick,
130
+ deviceId: id,
131
+ type: cached?.type,
132
+ changed: {},
133
+ error: err instanceof Error ? err.message : String(err),
134
+ };
135
+ if (isJsonMode()) {
136
+ printJson(ev);
137
+ }
138
+ else {
139
+ console.error(formatHumanLine(ev));
140
+ }
141
+ }
142
+ }));
143
+ if (maxTicks !== null && tick >= maxTicks)
144
+ break;
145
+ await sleep(intervalMs, ac.signal);
146
+ }
147
+ }
148
+ catch (err) {
149
+ handleError(err);
150
+ }
151
+ finally {
152
+ process.off('SIGINT', onSig);
153
+ process.off('SIGTERM', onSig);
154
+ }
155
+ }
156
+ catch (error) {
157
+ handleError(error);
158
+ }
159
+ });
160
+ }
161
+ //# 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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"}
@@ -1,16 +1,16 @@
1
1
  import { createClient } from '../api/client.js';
2
- import { printKeyValue, printJson, isJsonMode, handleError } from '../utils/output.js';
2
+ import { printKeyValue, printJson, isJsonMode, handleError, UsageError } from '../utils/output.js';
3
3
  import chalk from 'chalk';
4
- function assertValidUrl(cmd, url) {
4
+ function assertValidUrl(url) {
5
5
  let parsed;
6
6
  try {
7
7
  parsed = new URL(url);
8
8
  }
9
9
  catch {
10
- cmd.error(`error: invalid URL "${url}" (expected absolute URL, e.g. https://example.com/hook)`, { exitCode: 2, code: 'switchbot.invalidUrl' });
10
+ throw new UsageError(`Invalid URL "${url}" (expected absolute URL, e.g. https://example.com/hook)`);
11
11
  }
12
12
  if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
13
- cmd.error(`error: URL must use http:// or https:// (got "${parsed.protocol}")`, { exitCode: 2, code: 'switchbot.invalidUrl' });
13
+ throw new UsageError(`URL must use http:// or https:// (got "${parsed.protocol}")`);
14
14
  }
15
15
  }
16
16
  export function registerWebhookCommand(program) {
@@ -22,24 +22,29 @@ A webhook lets SwitchBot POST device state-change events to a URL you host.
22
22
  Only one webhook URL can be active per account; "setup" registers it for ALL devices.
23
23
  `);
24
24
  // switchbot webhook setup <url>
25
- const setup = webhook
25
+ webhook
26
26
  .command('setup')
27
27
  .description('Configure the webhook receiver URL (receives events from all devices)')
28
28
  .argument('<url>', 'Absolute http(s):// URL where SwitchBot will POST events')
29
29
  .addHelpText('after', `
30
30
  Example:
31
31
  $ switchbot webhook setup https://example.com/switchbot/events
32
- `);
33
- setup.action(async (url) => {
34
- assertValidUrl(setup, url);
32
+ `)
33
+ .action(async (url) => {
35
34
  try {
35
+ assertValidUrl(url);
36
36
  const client = createClient();
37
37
  await client.post('/v1.1/webhook/setupWebhook', {
38
38
  action: 'setupWebhook',
39
39
  url,
40
40
  deviceList: 'ALL',
41
41
  });
42
- console.log(chalk.green(`✓ Webhook configured: ${url}`));
42
+ if (isJsonMode()) {
43
+ printJson({ ok: true, url });
44
+ }
45
+ else {
46
+ console.log(chalk.green(`✓ Webhook configured: ${url}`));
47
+ }
43
48
  }
44
49
  catch (error) {
45
50
  handleError(error);
@@ -103,7 +108,7 @@ Examples:
103
108
  }
104
109
  });
105
110
  // switchbot webhook update <url> [--enable | --disable]
106
- const update = webhook
111
+ webhook
107
112
  .command('update')
108
113
  .description('Update webhook configuration (enable / disable a registered URL)')
109
114
  .argument('<url>', 'URL of the webhook to update (must already be configured)')
@@ -116,13 +121,13 @@ webhook is re-submitted with no change to its enabled state.
116
121
  Examples:
117
122
  $ switchbot webhook update https://example.com/hook --enable
118
123
  $ switchbot webhook update https://example.com/hook --disable
119
- `);
120
- update.action(async (url, options) => {
121
- if (options.enable && options.disable) {
122
- update.error('error: --enable and --disable are mutually exclusive', { exitCode: 2, code: 'switchbot.conflictingOptions' });
123
- }
124
- assertValidUrl(update, url);
124
+ `)
125
+ .action(async (url, options) => {
125
126
  try {
127
+ if (options.enable && options.disable) {
128
+ throw new UsageError('--enable and --disable are mutually exclusive');
129
+ }
130
+ assertValidUrl(url);
126
131
  const client = createClient();
127
132
  const config = { url };
128
133
  if (options.enable)
@@ -134,30 +139,40 @@ Examples:
134
139
  config,
135
140
  });
136
141
  const statusText = options.enable ? 'enabled' : options.disable ? 'disabled' : 'updated';
137
- console.log(chalk.green(`✓ Webhook ${statusText}: ${url}`));
142
+ if (isJsonMode()) {
143
+ printJson({ ok: true, url, status: statusText });
144
+ }
145
+ else {
146
+ console.log(chalk.green(`✓ Webhook ${statusText}: ${url}`));
147
+ }
138
148
  }
139
149
  catch (error) {
140
150
  handleError(error);
141
151
  }
142
152
  });
143
153
  // switchbot webhook delete <url>
144
- const del = webhook
154
+ webhook
145
155
  .command('delete')
146
156
  .description('Delete webhook configuration')
147
157
  .argument('<url>', 'URL of the webhook to remove')
148
158
  .addHelpText('after', `
149
159
  Example:
150
160
  $ switchbot webhook delete https://example.com/hook
151
- `);
152
- del.action(async (url) => {
153
- assertValidUrl(del, url);
161
+ `)
162
+ .action(async (url) => {
154
163
  try {
164
+ assertValidUrl(url);
155
165
  const client = createClient();
156
166
  await client.post('/v1.1/webhook/deleteWebhook', {
157
167
  action: 'deleteWebhook',
158
168
  url,
159
169
  });
160
- console.log(chalk.green(`✓ Webhook deleted: ${url}`));
170
+ if (isJsonMode()) {
171
+ printJson({ ok: true, url });
172
+ }
173
+ else {
174
+ console.log(chalk.green(`✓ Webhook deleted: ${url}`));
175
+ }
161
176
  }
162
177
  catch (error) {
163
178
  handleError(error);
@@ -1 +1 @@
1
- {"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../src/commands/webhook.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../src/commands/webhook.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -2,6 +2,17 @@ export interface SwitchBotConfig {
2
2
  token: string;
3
3
  secret: string;
4
4
  }
5
+ /**
6
+ * Credential file resolution priority:
7
+ * 1. --config <path> (absolute override — wins over everything)
8
+ * 2. --profile <name> → ~/.switchbot/profiles/<name>.json
9
+ * 3. default → ~/.switchbot/config.json
10
+ *
11
+ * Env SWITCHBOT_TOKEN+SWITCHBOT_SECRET still take priority inside loadConfig.
12
+ */
13
+ export declare function configFilePath(): string;
14
+ export declare function profileFilePath(profile: string): string;
15
+ export declare function listProfiles(): string[];
5
16
  export declare function loadConfig(): SwitchBotConfig;
6
17
  export declare function saveConfig(token: string, secret: string): void;
7
18
  export declare function showConfig(): void;
package/dist/config.js CHANGED
@@ -1,15 +1,38 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import os from 'node:os';
4
- import { getConfigPath } from './utils/flags.js';
5
- function configFilePath() {
4
+ import { getConfigPath, getProfile } from './utils/flags.js';
5
+ /**
6
+ * Credential file resolution priority:
7
+ * 1. --config <path> (absolute override — wins over everything)
8
+ * 2. --profile <name> → ~/.switchbot/profiles/<name>.json
9
+ * 3. default → ~/.switchbot/config.json
10
+ *
11
+ * Env SWITCHBOT_TOKEN+SWITCHBOT_SECRET still take priority inside loadConfig.
12
+ */
13
+ export function configFilePath() {
6
14
  const override = getConfigPath();
7
15
  if (override)
8
16
  return path.resolve(override);
17
+ const profile = getProfile();
18
+ if (profile) {
19
+ return path.join(os.homedir(), '.switchbot', 'profiles', `${profile}.json`);
20
+ }
9
21
  return path.join(os.homedir(), '.switchbot', 'config.json');
10
22
  }
23
+ export function profileFilePath(profile) {
24
+ return path.join(os.homedir(), '.switchbot', 'profiles', `${profile}.json`);
25
+ }
26
+ export function listProfiles() {
27
+ const dir = path.join(os.homedir(), '.switchbot', 'profiles');
28
+ if (!fs.existsSync(dir))
29
+ return [];
30
+ return fs.readdirSync(dir)
31
+ .filter((f) => f.endsWith('.json'))
32
+ .map((f) => f.slice(0, -5))
33
+ .sort();
34
+ }
11
35
  export function loadConfig() {
12
- // Environment variables take priority (useful for CI)
13
36
  const envToken = process.env.SWITCHBOT_TOKEN;
14
37
  const envSecret = process.env.SWITCHBOT_SECRET;
15
38
  if (envToken && envSecret) {
@@ -17,15 +40,18 @@ export function loadConfig() {
17
40
  }
18
41
  const file = configFilePath();
19
42
  if (!fs.existsSync(file)) {
20
- console.error('No credentials configured. Please run: switchbot config set-token <token> <secret>\n' +
21
- 'Or set the SWITCHBOT_TOKEN and SWITCHBOT_SECRET environment variables.');
43
+ const profile = getProfile();
44
+ const hint = profile
45
+ ? `No credentials configured for profile "${profile}". Run: switchbot --profile ${profile} config set-token <token> <secret>`
46
+ : 'No credentials configured. Run: switchbot config set-token <token> <secret>';
47
+ console.error(`${hint}\nOr set SWITCHBOT_TOKEN and SWITCHBOT_SECRET environment variables.`);
22
48
  process.exit(1);
23
49
  }
24
50
  try {
25
51
  const raw = fs.readFileSync(file, 'utf-8');
26
52
  const cfg = JSON.parse(raw);
27
53
  if (!cfg.token || !cfg.secret) {
28
- console.error('Invalid config.json format. Please re-run: switchbot config set-token');
54
+ console.error('Invalid config format. Please re-run: switchbot config set-token');
29
55
  process.exit(1);
30
56
  }
31
57
  return cfg;
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAOjD,SAAS,cAAc;IACrB,MAAM,QAAQ,GAAG,aAAa,EAAE,CAAC;IACjC,IAAI,QAAQ;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5C,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,sDAAsD;IACtD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC7C,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC/C,IAAI,QAAQ,IAAI,SAAS,EAAE,CAAC;QAC1B,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAChD,CAAC;IAED,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;IAC9B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,KAAK,CACX,sFAAsF;YACtF,wEAAwE,CACzE,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,CAAC;QAC/C,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;YAC9B,OAAO,CAAC,KAAK,CAAC,uEAAuE,CAAC,CAAC;YACvF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,uEAAuE,CAAC,CAAC;QACvF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,MAAc;IACtD,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;IAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC;IACD,MAAM,GAAG,GAAoB,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC/C,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC7C,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAE/C,IAAI,QAAQ,IAAI,SAAS,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,WAAW,QAAQ,EAAE,CAAC,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,WAAW,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAChD,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;IAC9B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;QACzC,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,WAAW,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,MAAc;IAChC,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC;IACtC,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/E,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,12 @@ export interface CachedDevice {
2
2
  type: string;
3
3
  name: string;
4
4
  category: 'physical' | 'ir';
5
+ hubDeviceId?: string;
6
+ enableCloudService?: boolean;
7
+ roomID?: string;
8
+ roomName?: string | null;
9
+ familyName?: string;
10
+ controlType?: string;
5
11
  }
6
12
  export interface DeviceCache {
7
13
  lastUpdated: string;
@@ -12,14 +18,58 @@ export interface DeviceListBodyShape {
12
18
  deviceId: string;
13
19
  deviceName: string;
14
20
  deviceType?: string;
21
+ hubDeviceId?: string;
22
+ enableCloudService?: boolean;
23
+ roomID?: string;
24
+ roomName?: string | null;
25
+ familyName?: string;
26
+ controlType?: string;
15
27
  }>;
16
28
  infraredRemoteList: Array<{
17
29
  deviceId: string;
18
30
  deviceName: string;
19
31
  remoteType: string;
32
+ hubDeviceId?: string;
33
+ controlType?: string;
20
34
  }>;
21
35
  }
36
+ /** Force the next loadCache() call to re-read from disk. Used in tests. */
37
+ export declare function resetListCache(): void;
22
38
  export declare function loadCache(): DeviceCache | null;
23
39
  export declare function getCachedDevice(deviceId: string): CachedDevice | null;
24
40
  export declare function updateCacheFromDeviceList(body: DeviceListBodyShape): void;
25
41
  export declare function clearCache(): void;
42
+ /** Age of the on-disk list cache in ms, or null if there is no cache. */
43
+ export declare function listCacheAgeMs(now?: number): number | null;
44
+ /** True when the on-disk list cache is present and younger than `ttlMs`. */
45
+ export declare function isListCacheFresh(ttlMs: number, now?: number): boolean;
46
+ export interface CachedStatus {
47
+ fetchedAt: string;
48
+ body: Record<string, unknown>;
49
+ }
50
+ export interface StatusCache {
51
+ entries: Record<string, CachedStatus>;
52
+ }
53
+ export declare function loadStatusCache(): StatusCache;
54
+ /** Read a status entry; returns null when missing or older than `ttlMs`. */
55
+ export declare function getCachedStatus(deviceId: string, ttlMs: number, now?: number): Record<string, unknown> | null;
56
+ export declare function setCachedStatus(deviceId: string, body: Record<string, unknown>, now?: Date): void;
57
+ export declare function clearStatusCache(): void;
58
+ /** Summary for `switchbot cache show`. */
59
+ export interface CacheSummary {
60
+ list: {
61
+ path: string;
62
+ exists: boolean;
63
+ lastUpdated?: string;
64
+ ageMs?: number;
65
+ deviceCount?: number;
66
+ };
67
+ status: {
68
+ path: string;
69
+ exists: boolean;
70
+ entryCount: number;
71
+ oldestFetchedAt?: string;
72
+ newestFetchedAt?: string;
73
+ };
74
+ }
75
+ export declare function describeCache(now?: number): CacheSummary;