@switchbot/openapi-cli 3.2.1 → 3.3.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 (332) hide show
  1. package/README.md +3 -1
  2. package/dist/index.js +57419 -170
  3. package/package.json +9 -5
  4. package/dist/api/client.d.ts +0 -31
  5. package/dist/api/client.js +0 -236
  6. package/dist/api/client.js.map +0 -1
  7. package/dist/auth.d.ts +0 -1
  8. package/dist/auth.js +0 -21
  9. package/dist/auth.js.map +0 -1
  10. package/dist/commands/agent-bootstrap.d.ts +0 -10
  11. package/dist/commands/agent-bootstrap.js +0 -200
  12. package/dist/commands/agent-bootstrap.js.map +0 -1
  13. package/dist/commands/auth.d.ts +0 -18
  14. package/dist/commands/auth.js +0 -355
  15. package/dist/commands/auth.js.map +0 -1
  16. package/dist/commands/batch.d.ts +0 -2
  17. package/dist/commands/batch.js +0 -414
  18. package/dist/commands/batch.js.map +0 -1
  19. package/dist/commands/cache.d.ts +0 -2
  20. package/dist/commands/cache.js +0 -127
  21. package/dist/commands/cache.js.map +0 -1
  22. package/dist/commands/capabilities.d.ts +0 -31
  23. package/dist/commands/capabilities.js +0 -383
  24. package/dist/commands/capabilities.js.map +0 -1
  25. package/dist/commands/catalog.d.ts +0 -2
  26. package/dist/commands/catalog.js +0 -360
  27. package/dist/commands/catalog.js.map +0 -1
  28. package/dist/commands/completion.d.ts +0 -2
  29. package/dist/commands/completion.js +0 -386
  30. package/dist/commands/completion.js.map +0 -1
  31. package/dist/commands/config.d.ts +0 -21
  32. package/dist/commands/config.js +0 -377
  33. package/dist/commands/config.js.map +0 -1
  34. package/dist/commands/daemon.d.ts +0 -2
  35. package/dist/commands/daemon.js +0 -411
  36. package/dist/commands/daemon.js.map +0 -1
  37. package/dist/commands/device-meta.d.ts +0 -2
  38. package/dist/commands/device-meta.js +0 -160
  39. package/dist/commands/device-meta.js.map +0 -1
  40. package/dist/commands/devices.d.ts +0 -2
  41. package/dist/commands/devices.js +0 -949
  42. package/dist/commands/devices.js.map +0 -1
  43. package/dist/commands/doctor.d.ts +0 -3
  44. package/dist/commands/doctor.js +0 -1016
  45. package/dist/commands/doctor.js.map +0 -1
  46. package/dist/commands/events.d.ts +0 -31
  47. package/dist/commands/events.js +0 -564
  48. package/dist/commands/events.js.map +0 -1
  49. package/dist/commands/expand.d.ts +0 -2
  50. package/dist/commands/expand.js +0 -131
  51. package/dist/commands/expand.js.map +0 -1
  52. package/dist/commands/explain.d.ts +0 -2
  53. package/dist/commands/explain.js +0 -140
  54. package/dist/commands/explain.js.map +0 -1
  55. package/dist/commands/health.d.ts +0 -8
  56. package/dist/commands/health.js +0 -114
  57. package/dist/commands/health.js.map +0 -1
  58. package/dist/commands/history.d.ts +0 -2
  59. package/dist/commands/history.js +0 -321
  60. package/dist/commands/history.js.map +0 -1
  61. package/dist/commands/identity.d.ts +0 -45
  62. package/dist/commands/identity.js +0 -60
  63. package/dist/commands/identity.js.map +0 -1
  64. package/dist/commands/install.d.ts +0 -20
  65. package/dist/commands/install.js +0 -247
  66. package/dist/commands/install.js.map +0 -1
  67. package/dist/commands/mcp.d.ts +0 -14
  68. package/dist/commands/mcp.js +0 -2018
  69. package/dist/commands/mcp.js.map +0 -1
  70. package/dist/commands/plan.d.ts +0 -51
  71. package/dist/commands/plan.js +0 -654
  72. package/dist/commands/plan.js.map +0 -1
  73. package/dist/commands/policy.d.ts +0 -24
  74. package/dist/commands/policy.js +0 -587
  75. package/dist/commands/policy.js.map +0 -1
  76. package/dist/commands/quota.d.ts +0 -2
  77. package/dist/commands/quota.js +0 -79
  78. package/dist/commands/quota.js.map +0 -1
  79. package/dist/commands/rules.d.ts +0 -2
  80. package/dist/commands/rules.js +0 -876
  81. package/dist/commands/rules.js.map +0 -1
  82. package/dist/commands/scenes.d.ts +0 -2
  83. package/dist/commands/scenes.js +0 -265
  84. package/dist/commands/scenes.js.map +0 -1
  85. package/dist/commands/schema.d.ts +0 -2
  86. package/dist/commands/schema.js +0 -185
  87. package/dist/commands/schema.js.map +0 -1
  88. package/dist/commands/status-sync.d.ts +0 -2
  89. package/dist/commands/status-sync.js +0 -132
  90. package/dist/commands/status-sync.js.map +0 -1
  91. package/dist/commands/uninstall.d.ts +0 -20
  92. package/dist/commands/uninstall.js +0 -238
  93. package/dist/commands/uninstall.js.map +0 -1
  94. package/dist/commands/upgrade-check.d.ts +0 -2
  95. package/dist/commands/upgrade-check.js +0 -107
  96. package/dist/commands/upgrade-check.js.map +0 -1
  97. package/dist/commands/watch.d.ts +0 -2
  98. package/dist/commands/watch.js +0 -195
  99. package/dist/commands/watch.js.map +0 -1
  100. package/dist/commands/webhook.d.ts +0 -2
  101. package/dist/commands/webhook.js +0 -183
  102. package/dist/commands/webhook.js.map +0 -1
  103. package/dist/config.d.ts +0 -57
  104. package/dist/config.js +0 -259
  105. package/dist/config.js.map +0 -1
  106. package/dist/credentials/backends/file.d.ts +0 -18
  107. package/dist/credentials/backends/file.js +0 -102
  108. package/dist/credentials/backends/file.js.map +0 -1
  109. package/dist/credentials/backends/linux.d.ts +0 -16
  110. package/dist/credentials/backends/linux.js +0 -130
  111. package/dist/credentials/backends/linux.js.map +0 -1
  112. package/dist/credentials/backends/macos.d.ts +0 -18
  113. package/dist/credentials/backends/macos.js +0 -130
  114. package/dist/credentials/backends/macos.js.map +0 -1
  115. package/dist/credentials/backends/windows.d.ts +0 -23
  116. package/dist/credentials/backends/windows.js +0 -216
  117. package/dist/credentials/backends/windows.js.map +0 -1
  118. package/dist/credentials/keychain.d.ts +0 -83
  119. package/dist/credentials/keychain.js +0 -89
  120. package/dist/credentials/keychain.js.map +0 -1
  121. package/dist/credentials/prime.d.ts +0 -32
  122. package/dist/credentials/prime.js +0 -53
  123. package/dist/credentials/prime.js.map +0 -1
  124. package/dist/devices/cache.d.ts +0 -79
  125. package/dist/devices/cache.js +0 -294
  126. package/dist/devices/cache.js.map +0 -1
  127. package/dist/devices/catalog.d.ts +0 -138
  128. package/dist/devices/catalog.js +0 -768
  129. package/dist/devices/catalog.js.map +0 -1
  130. package/dist/devices/device-meta.d.ts +0 -15
  131. package/dist/devices/device-meta.js +0 -57
  132. package/dist/devices/device-meta.js.map +0 -1
  133. package/dist/devices/history-agg.d.ts +0 -37
  134. package/dist/devices/history-agg.js +0 -139
  135. package/dist/devices/history-agg.js.map +0 -1
  136. package/dist/devices/history-query.d.ts +0 -45
  137. package/dist/devices/history-query.js +0 -182
  138. package/dist/devices/history-query.js.map +0 -1
  139. package/dist/devices/param-validator.d.ts +0 -40
  140. package/dist/devices/param-validator.js +0 -434
  141. package/dist/devices/param-validator.js.map +0 -1
  142. package/dist/devices/resources.d.ts +0 -74
  143. package/dist/devices/resources.js +0 -271
  144. package/dist/devices/resources.js.map +0 -1
  145. package/dist/index.d.ts +0 -1
  146. package/dist/index.js.map +0 -1
  147. package/dist/install/default-steps.d.ts +0 -66
  148. package/dist/install/default-steps.js +0 -258
  149. package/dist/install/default-steps.js.map +0 -1
  150. package/dist/install/preflight.d.ts +0 -60
  151. package/dist/install/preflight.js +0 -213
  152. package/dist/install/preflight.js.map +0 -1
  153. package/dist/install/steps.d.ts +0 -61
  154. package/dist/install/steps.js +0 -68
  155. package/dist/install/steps.js.map +0 -1
  156. package/dist/lib/command-keywords.d.ts +0 -5
  157. package/dist/lib/command-keywords.js +0 -18
  158. package/dist/lib/command-keywords.js.map +0 -1
  159. package/dist/lib/daemon-state.d.ts +0 -24
  160. package/dist/lib/daemon-state.js +0 -47
  161. package/dist/lib/daemon-state.js.map +0 -1
  162. package/dist/lib/destructive-mode.d.ts +0 -2
  163. package/dist/lib/destructive-mode.js +0 -13
  164. package/dist/lib/destructive-mode.js.map +0 -1
  165. package/dist/lib/devices.d.ts +0 -151
  166. package/dist/lib/devices.js +0 -383
  167. package/dist/lib/devices.js.map +0 -1
  168. package/dist/lib/idempotency.d.ts +0 -46
  169. package/dist/lib/idempotency.js +0 -107
  170. package/dist/lib/idempotency.js.map +0 -1
  171. package/dist/lib/plan-store.d.ts +0 -19
  172. package/dist/lib/plan-store.js +0 -69
  173. package/dist/lib/plan-store.js.map +0 -1
  174. package/dist/lib/request-context.d.ts +0 -7
  175. package/dist/lib/request-context.js +0 -13
  176. package/dist/lib/request-context.js.map +0 -1
  177. package/dist/lib/scenes.d.ts +0 -7
  178. package/dist/lib/scenes.js +0 -11
  179. package/dist/lib/scenes.js.map +0 -1
  180. package/dist/logger.d.ts +0 -4
  181. package/dist/logger.js +0 -17
  182. package/dist/logger.js.map +0 -1
  183. package/dist/mcp/device-history.d.ts +0 -36
  184. package/dist/mcp/device-history.js +0 -146
  185. package/dist/mcp/device-history.js.map +0 -1
  186. package/dist/mcp/events-subscription.d.ts +0 -45
  187. package/dist/mcp/events-subscription.js +0 -214
  188. package/dist/mcp/events-subscription.js.map +0 -1
  189. package/dist/mqtt/client.d.ts +0 -25
  190. package/dist/mqtt/client.js +0 -181
  191. package/dist/mqtt/client.js.map +0 -1
  192. package/dist/mqtt/credential.d.ts +0 -16
  193. package/dist/mqtt/credential.js +0 -31
  194. package/dist/mqtt/credential.js.map +0 -1
  195. package/dist/policy/add-rule.d.ts +0 -21
  196. package/dist/policy/add-rule.js +0 -125
  197. package/dist/policy/add-rule.js.map +0 -1
  198. package/dist/policy/diff.d.ts +0 -21
  199. package/dist/policy/diff.js +0 -92
  200. package/dist/policy/diff.js.map +0 -1
  201. package/dist/policy/format.d.ts +0 -6
  202. package/dist/policy/format.js +0 -58
  203. package/dist/policy/format.js.map +0 -1
  204. package/dist/policy/load.d.ts +0 -32
  205. package/dist/policy/load.js +0 -62
  206. package/dist/policy/load.js.map +0 -1
  207. package/dist/policy/migrate.d.ts +0 -21
  208. package/dist/policy/migrate.js +0 -68
  209. package/dist/policy/migrate.js.map +0 -1
  210. package/dist/policy/schema.d.ts +0 -5
  211. package/dist/policy/schema.js +0 -19
  212. package/dist/policy/schema.js.map +0 -1
  213. package/dist/policy/validate.d.ts +0 -19
  214. package/dist/policy/validate.js +0 -263
  215. package/dist/policy/validate.js.map +0 -1
  216. package/dist/rules/action.d.ts +0 -65
  217. package/dist/rules/action.js +0 -217
  218. package/dist/rules/action.js.map +0 -1
  219. package/dist/rules/audit-query.d.ts +0 -51
  220. package/dist/rules/audit-query.js +0 -90
  221. package/dist/rules/audit-query.js.map +0 -1
  222. package/dist/rules/conflict-analyzer.d.ts +0 -57
  223. package/dist/rules/conflict-analyzer.js +0 -215
  224. package/dist/rules/conflict-analyzer.js.map +0 -1
  225. package/dist/rules/cron-scheduler.d.ts +0 -62
  226. package/dist/rules/cron-scheduler.js +0 -187
  227. package/dist/rules/cron-scheduler.js.map +0 -1
  228. package/dist/rules/destructive.d.ts +0 -20
  229. package/dist/rules/destructive.js +0 -53
  230. package/dist/rules/destructive.js.map +0 -1
  231. package/dist/rules/engine.d.ts +0 -193
  232. package/dist/rules/engine.js +0 -758
  233. package/dist/rules/engine.js.map +0 -1
  234. package/dist/rules/matcher.d.ts +0 -56
  235. package/dist/rules/matcher.js +0 -231
  236. package/dist/rules/matcher.js.map +0 -1
  237. package/dist/rules/pid-file.d.ts +0 -43
  238. package/dist/rules/pid-file.js +0 -96
  239. package/dist/rules/pid-file.js.map +0 -1
  240. package/dist/rules/quiet-hours.d.ts +0 -26
  241. package/dist/rules/quiet-hours.js +0 -46
  242. package/dist/rules/quiet-hours.js.map +0 -1
  243. package/dist/rules/suggest.d.ts +0 -20
  244. package/dist/rules/suggest.js +0 -96
  245. package/dist/rules/suggest.js.map +0 -1
  246. package/dist/rules/throttle.d.ts +0 -61
  247. package/dist/rules/throttle.js +0 -117
  248. package/dist/rules/throttle.js.map +0 -1
  249. package/dist/rules/types.d.ts +0 -117
  250. package/dist/rules/types.js +0 -35
  251. package/dist/rules/types.js.map +0 -1
  252. package/dist/rules/webhook-listener.d.ts +0 -63
  253. package/dist/rules/webhook-listener.js +0 -224
  254. package/dist/rules/webhook-listener.js.map +0 -1
  255. package/dist/rules/webhook-token.d.ts +0 -50
  256. package/dist/rules/webhook-token.js +0 -91
  257. package/dist/rules/webhook-token.js.map +0 -1
  258. package/dist/schema/field-aliases.d.ts +0 -34
  259. package/dist/schema/field-aliases.js +0 -132
  260. package/dist/schema/field-aliases.js.map +0 -1
  261. package/dist/sinks/dispatcher.d.ts +0 -7
  262. package/dist/sinks/dispatcher.js +0 -13
  263. package/dist/sinks/dispatcher.js.map +0 -1
  264. package/dist/sinks/file.d.ts +0 -6
  265. package/dist/sinks/file.js +0 -20
  266. package/dist/sinks/file.js.map +0 -1
  267. package/dist/sinks/format.d.ts +0 -20
  268. package/dist/sinks/format.js +0 -57
  269. package/dist/sinks/format.js.map +0 -1
  270. package/dist/sinks/homeassistant.d.ts +0 -18
  271. package/dist/sinks/homeassistant.js +0 -45
  272. package/dist/sinks/homeassistant.js.map +0 -1
  273. package/dist/sinks/openclaw.d.ts +0 -13
  274. package/dist/sinks/openclaw.js +0 -34
  275. package/dist/sinks/openclaw.js.map +0 -1
  276. package/dist/sinks/stdout.d.ts +0 -4
  277. package/dist/sinks/stdout.js +0 -6
  278. package/dist/sinks/stdout.js.map +0 -1
  279. package/dist/sinks/telegram.d.ts +0 -11
  280. package/dist/sinks/telegram.js +0 -29
  281. package/dist/sinks/telegram.js.map +0 -1
  282. package/dist/sinks/types.d.ts +0 -13
  283. package/dist/sinks/types.js +0 -2
  284. package/dist/sinks/types.js.map +0 -1
  285. package/dist/sinks/webhook.d.ts +0 -6
  286. package/dist/sinks/webhook.js +0 -23
  287. package/dist/sinks/webhook.js.map +0 -1
  288. package/dist/status-sync/manager.d.ts +0 -48
  289. package/dist/status-sync/manager.js +0 -269
  290. package/dist/status-sync/manager.js.map +0 -1
  291. package/dist/utils/arg-parsers.d.ts +0 -16
  292. package/dist/utils/arg-parsers.js +0 -67
  293. package/dist/utils/arg-parsers.js.map +0 -1
  294. package/dist/utils/audit.d.ts +0 -69
  295. package/dist/utils/audit.js +0 -122
  296. package/dist/utils/audit.js.map +0 -1
  297. package/dist/utils/filter.d.ts +0 -81
  298. package/dist/utils/filter.js +0 -190
  299. package/dist/utils/filter.js.map +0 -1
  300. package/dist/utils/flags.d.ts +0 -72
  301. package/dist/utils/flags.js +0 -187
  302. package/dist/utils/flags.js.map +0 -1
  303. package/dist/utils/format.d.ts +0 -9
  304. package/dist/utils/format.js +0 -118
  305. package/dist/utils/format.js.map +0 -1
  306. package/dist/utils/health.d.ts +0 -48
  307. package/dist/utils/health.js +0 -102
  308. package/dist/utils/health.js.map +0 -1
  309. package/dist/utils/help-json.d.ts +0 -39
  310. package/dist/utils/help-json.js +0 -55
  311. package/dist/utils/help-json.js.map +0 -1
  312. package/dist/utils/name-resolver.d.ts +0 -26
  313. package/dist/utils/name-resolver.js +0 -138
  314. package/dist/utils/name-resolver.js.map +0 -1
  315. package/dist/utils/output.d.ts +0 -73
  316. package/dist/utils/output.js +0 -405
  317. package/dist/utils/output.js.map +0 -1
  318. package/dist/utils/quota.d.ts +0 -61
  319. package/dist/utils/quota.js +0 -228
  320. package/dist/utils/quota.js.map +0 -1
  321. package/dist/utils/redact.d.ts +0 -23
  322. package/dist/utils/redact.js +0 -69
  323. package/dist/utils/redact.js.map +0 -1
  324. package/dist/utils/retry.d.ts +0 -72
  325. package/dist/utils/retry.js +0 -141
  326. package/dist/utils/retry.js.map +0 -1
  327. package/dist/utils/string.d.ts +0 -2
  328. package/dist/utils/string.js +0 -23
  329. package/dist/utils/string.js.map +0 -1
  330. package/dist/version.d.ts +0 -2
  331. package/dist/version.js +0 -5
  332. package/dist/version.js.map +0 -1
@@ -1,96 +0,0 @@
1
- import { stringify as yamlStringify } from 'yaml';
2
- import { COMMAND_KEYWORDS } from '../lib/command-keywords.js';
3
- const TRIGGER_KEYWORDS = [
4
- { pattern: /\bmotion\b|\bdetect/i, trigger: 'mqtt', event: 'motion.detected' },
5
- { pattern: /\bdoor\b|\bcontact\b|\bopen.*sensor/i, trigger: 'mqtt', event: 'contact.opened' },
6
- { pattern: /\bbutton\b|\bpress/i, trigger: 'mqtt', event: 'button.pressed' },
7
- { pattern: /\bwebhook\b|\bhttp\b|\bifttt\b/i, trigger: 'webhook' },
8
- { pattern: /\bevery\b|\bdaily\b|\bmorning\b|\bnight\b|\bevening\b|\b\d{1,2}\s*[ap]m\b/i, trigger: 'cron' },
9
- ];
10
- function inferTrigger(intent) {
11
- for (const t of TRIGGER_KEYWORDS) {
12
- if (t.pattern.test(intent))
13
- return { trigger: t.trigger, event: t.event };
14
- }
15
- return { trigger: 'mqtt', event: 'device.shadow' };
16
- }
17
- function inferSchedule(intent, warnings) {
18
- const amMatch = /\b(\d{1,2})\s*am\b/i.exec(intent);
19
- if (amMatch)
20
- return `0 ${parseInt(amMatch[1], 10)} * * *`;
21
- const pmMatch = /\b(\d{1,2})\s*pm\b/i.exec(intent);
22
- if (pmMatch)
23
- return `0 ${parseInt(pmMatch[1], 10) + 12} * * *`;
24
- if (/\bevery\s*hour/i.test(intent))
25
- return '0 * * * *';
26
- if (/\bnight\b|\bevening\b/i.test(intent))
27
- return '0 22 * * *';
28
- if (/\bmorning\b/i.test(intent))
29
- return '0 8 * * *';
30
- warnings.push(`Could not infer cron schedule from intent "${intent}" — defaulted to "0 8 * * *". Edit the generated rule to set the correct schedule.`);
31
- return '0 8 * * *';
32
- }
33
- function inferCommand(intent, warnings) {
34
- for (const k of COMMAND_KEYWORDS) {
35
- if (k.pattern.test(intent))
36
- return k.command;
37
- }
38
- warnings.push(`Could not infer command from intent "${intent}" — defaulted to "turnOn". Edit the generated rule to set the correct command.`);
39
- return 'turnOn';
40
- }
41
- export function suggestRule(opts) {
42
- const warnings = [];
43
- // Resolve trigger
44
- let triggerSource = opts.trigger;
45
- let inferredEvent;
46
- if (!triggerSource) {
47
- const inferred = inferTrigger(opts.intent);
48
- triggerSource = inferred.trigger;
49
- inferredEvent = inferred.event;
50
- if (inferredEvent === 'device.shadow') {
51
- warnings.push(`Could not infer trigger type from intent "${opts.intent}" — defaulted to mqtt/device.shadow. Set --trigger and --event explicitly.`);
52
- }
53
- }
54
- // Build the when block
55
- let when;
56
- if (triggerSource === 'mqtt') {
57
- const event = opts.event ?? inferredEvent ?? 'device.shadow';
58
- const mqttTrigger = { source: 'mqtt', event };
59
- if (opts.devices && opts.devices.length > 0) {
60
- const sensorDevice = opts.devices[0];
61
- mqttTrigger.device = sensorDevice.name ?? sensorDevice.id;
62
- }
63
- when = mqttTrigger;
64
- }
65
- else if (triggerSource === 'cron') {
66
- const schedule = opts.schedule ?? inferSchedule(opts.intent, warnings);
67
- const cronTrigger = { source: 'cron', schedule };
68
- if (opts.days && opts.days.length > 0)
69
- cronTrigger.days = opts.days;
70
- when = cronTrigger;
71
- }
72
- else {
73
- when = { source: 'webhook', path: opts.webhookPath ?? '/action' };
74
- }
75
- // Build then[] — one action per device (skip the sensor device for mqtt)
76
- const command = inferCommand(opts.intent, warnings);
77
- const actionDevices = triggerSource === 'mqtt' && opts.devices && opts.devices.length > 1
78
- ? opts.devices.slice(1)
79
- : (opts.devices ?? []);
80
- const then = actionDevices.length > 0
81
- ? actionDevices.map((d) => ({
82
- command: `devices command <id> ${command}`,
83
- device: d.id,
84
- }))
85
- : [{ command: `devices command <id> ${command}` }];
86
- const rule = {
87
- name: opts.intent,
88
- when,
89
- then,
90
- dry_run: true,
91
- ...(triggerSource === 'mqtt' ? { throttle: { max_per: '10m' } } : {}),
92
- };
93
- const ruleYaml = yamlStringify(rule, { lineWidth: 0 });
94
- return { rule, ruleYaml, warnings };
95
- }
96
- //# sourceMappingURL=suggest.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"suggest.js","sourceRoot":"","sources":["../../src/rules/suggest.ts"],"names":[],"mappings":"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"}
@@ -1,61 +0,0 @@
1
- /**
2
- * Throttle gate — per-rule, optionally keyed by deviceId.
3
- *
4
- * Semantics:
5
- * - `max_per: "10m"` → a rule may fire at most once every 10 minutes
6
- * per (rule, deviceId) pair.
7
- * - `dedupe_window: "5s"` → suppress fires whose key already fired
8
- * within the window (collapses rapid sensor bursts into one action).
9
- * - Fires that would violate the window are **suppressed** (not
10
- * queued) and surface as `{ allowed: false, reason: 'throttled' }`.
11
- * - When a rule has no `throttle` block, `ThrottleGate.check` returns
12
- * `{ allowed: true }` immediately.
13
- *
14
- * The gate is in-memory only. Re-reads between processes (or after
15
- * SIGHUP reload) start with a clean slate — a deliberate choice,
16
- * because persisting throttle state would lock the engine into a
17
- * schema that changes every time we add a trigger type.
18
- */
19
- export declare function parseMaxPerMs(expr: string): number;
20
- export interface ThrottleCheckResult {
21
- allowed: boolean;
22
- /** Timestamp of the last fire that occupies the window, if any. */
23
- lastFiredAt?: number;
24
- /** When the window will reopen. */
25
- nextAllowedAt?: number;
26
- /** Whether this was blocked by the dedupe_window (vs max_per). */
27
- dedupedBy?: 'dedupe_window' | 'max_per' | 'cooldown' | 'maxFiringsPerHour';
28
- }
29
- export interface MaxFiringsCheckResult {
30
- allowed: boolean;
31
- count: number;
32
- max: number;
33
- }
34
- export declare class ThrottleGate {
35
- private lastFireAt;
36
- /** Sliding-window fire-time log for count-based maxFiringsPerHour. */
37
- private fireTimes;
38
- private keyOf;
39
- /**
40
- * Does **not** record the fire. Call `record()` after the action
41
- * actually runs so that dry-run / throttled paths don't bump the
42
- * window.
43
- */
44
- check(ruleName: string, windowMs: number | null, now: number, deviceId?: string, dedupeWindowMs?: number | null): ThrottleCheckResult;
45
- record(ruleName: string, now: number, deviceId?: string): void;
46
- /** Count-based check: has the rule fired >= maxCount times in the last windowMs? */
47
- checkMaxFirings(ruleName: string, maxCount: number, windowMs: number, now: number, deviceId?: string): MaxFiringsCheckResult;
48
- /** Record a count-based fire (call alongside record()). */
49
- recordFire(ruleName: string, now: number, deviceId?: string): void;
50
- /** Drop everything — used by engine.reload when a rule is removed. */
51
- forget(ruleName: string): void;
52
- /**
53
- * Drop every window whose rule name isn't in the given set — used by
54
- * `engine.reload` after a policy swap. Entries for names that survive
55
- * the reload are preserved so unchanged rules don't get a free
56
- * one-fire amnesty.
57
- */
58
- retainOnly(ruleNames: Set<string>): void;
59
- /** Test helper — exposes the underlying size. */
60
- size(): number;
61
- }
@@ -1,117 +0,0 @@
1
- /**
2
- * Throttle gate — per-rule, optionally keyed by deviceId.
3
- *
4
- * Semantics:
5
- * - `max_per: "10m"` → a rule may fire at most once every 10 minutes
6
- * per (rule, deviceId) pair.
7
- * - `dedupe_window: "5s"` → suppress fires whose key already fired
8
- * within the window (collapses rapid sensor bursts into one action).
9
- * - Fires that would violate the window are **suppressed** (not
10
- * queued) and surface as `{ allowed: false, reason: 'throttled' }`.
11
- * - When a rule has no `throttle` block, `ThrottleGate.check` returns
12
- * `{ allowed: true }` immediately.
13
- *
14
- * The gate is in-memory only. Re-reads between processes (or after
15
- * SIGHUP reload) start with a clean slate — a deliberate choice,
16
- * because persisting throttle state would lock the engine into a
17
- * schema that changes every time we add a trigger type.
18
- */
19
- const DURATION_RE = /^(\d+)([smh])$/;
20
- export function parseMaxPerMs(expr) {
21
- const m = DURATION_RE.exec(expr.trim());
22
- if (!m)
23
- throw new Error(`Invalid throttle.max_per: "${expr}"`);
24
- const n = Number(m[1]);
25
- const unit = m[2];
26
- const unitMs = unit === 's' ? 1_000 : unit === 'm' ? 60_000 : 3_600_000;
27
- return n * unitMs;
28
- }
29
- export class ThrottleGate {
30
- lastFireAt = new Map();
31
- /** Sliding-window fire-time log for count-based maxFiringsPerHour. */
32
- fireTimes = new Map();
33
- keyOf(ruleName, deviceId) {
34
- return deviceId ? `${ruleName}::${deviceId}` : ruleName;
35
- }
36
- /**
37
- * Does **not** record the fire. Call `record()` after the action
38
- * actually runs so that dry-run / throttled paths don't bump the
39
- * window.
40
- */
41
- check(ruleName, windowMs, now, deviceId, dedupeWindowMs) {
42
- const key = this.keyOf(ruleName, deviceId);
43
- const last = this.lastFireAt.get(key);
44
- // dedupe_window check: suppress if last fire was within this (typically smaller) window
45
- if (dedupeWindowMs !== null && dedupeWindowMs !== undefined && dedupeWindowMs > 0) {
46
- if (last !== undefined) {
47
- const dedupeEnd = last + dedupeWindowMs;
48
- if (now < dedupeEnd) {
49
- return { allowed: false, lastFiredAt: last, nextAllowedAt: dedupeEnd, dedupedBy: 'dedupe_window' };
50
- }
51
- }
52
- }
53
- // max_per / cooldown check
54
- if (windowMs === null || windowMs <= 0)
55
- return { allowed: true, lastFiredAt: last };
56
- if (last === undefined)
57
- return { allowed: true };
58
- const earliest = last + windowMs;
59
- if (now >= earliest)
60
- return { allowed: true, lastFiredAt: last };
61
- return { allowed: false, lastFiredAt: last, nextAllowedAt: earliest, dedupedBy: windowMs > 0 ? 'max_per' : undefined };
62
- }
63
- record(ruleName, now, deviceId) {
64
- this.lastFireAt.set(this.keyOf(ruleName, deviceId), now);
65
- }
66
- /** Count-based check: has the rule fired >= maxCount times in the last windowMs? */
67
- checkMaxFirings(ruleName, maxCount, windowMs, now, deviceId) {
68
- const key = this.keyOf(ruleName, deviceId);
69
- const times = (this.fireTimes.get(key) ?? []).filter((t) => now - t < windowMs);
70
- this.fireTimes.set(key, times);
71
- return { allowed: times.length < maxCount, count: times.length, max: maxCount };
72
- }
73
- /** Record a count-based fire (call alongside record()). */
74
- recordFire(ruleName, now, deviceId) {
75
- const key = this.keyOf(ruleName, deviceId);
76
- const times = this.fireTimes.get(key) ?? [];
77
- times.push(now);
78
- this.fireTimes.set(key, times);
79
- }
80
- /** Drop everything — used by engine.reload when a rule is removed. */
81
- forget(ruleName) {
82
- const prefix = `${ruleName}::`;
83
- for (const k of this.lastFireAt.keys()) {
84
- if (k === ruleName || k.startsWith(prefix))
85
- this.lastFireAt.delete(k);
86
- }
87
- for (const k of this.fireTimes.keys()) {
88
- if (k === ruleName || k.startsWith(prefix))
89
- this.fireTimes.delete(k);
90
- }
91
- }
92
- /**
93
- * Drop every window whose rule name isn't in the given set — used by
94
- * `engine.reload` after a policy swap. Entries for names that survive
95
- * the reload are preserved so unchanged rules don't get a free
96
- * one-fire amnesty.
97
- */
98
- retainOnly(ruleNames) {
99
- for (const k of this.lastFireAt.keys()) {
100
- const sep = k.indexOf('::');
101
- const ruleName = sep === -1 ? k : k.slice(0, sep);
102
- if (!ruleNames.has(ruleName))
103
- this.lastFireAt.delete(k);
104
- }
105
- for (const k of this.fireTimes.keys()) {
106
- const sep = k.indexOf('::');
107
- const ruleName = sep === -1 ? k : k.slice(0, sep);
108
- if (!ruleNames.has(ruleName))
109
- this.fireTimes.delete(k);
110
- }
111
- }
112
- /** Test helper — exposes the underlying size. */
113
- size() {
114
- return this.lastFireAt.size;
115
- }
116
- }
117
- //# sourceMappingURL=throttle.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"throttle.js","sourceRoot":"","sources":["../../src/rules/throttle.ts"],"names":[],"mappings":"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"}
@@ -1,117 +0,0 @@
1
- /**
2
- * Runtime TypeScript shapes for policy v0.2 rule objects.
3
- *
4
- * These are hand-mirrored from `src/policy/schema/v0.2.json` — the ajv
5
- * validator is the source of truth for what a file may contain, this
6
- * file is the source of truth for what the engine expects after load.
7
- * When you edit one, edit the other in the same commit.
8
- */
9
- import type { DestructiveCommand } from './destructive.js';
10
- export type TriggerSource = 'mqtt' | 'cron' | 'webhook';
11
- export interface MqttTrigger {
12
- source: 'mqtt';
13
- /**
14
- * Event name matched against the engine's event classifier. Known
15
- * values today: `device.shadow` (catch-all), `motion.detected`,
16
- * `motion.cleared`, `contact.opened`, `contact.closed`.
17
- */
18
- event: string;
19
- /** Optional filter by deviceId or alias. */
20
- device?: string;
21
- }
22
- export type DayOfWeek = 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat' | 'sun' | 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday' | 'sunday';
23
- export interface CronTrigger {
24
- source: 'cron';
25
- /** Standard 5-field cron (minute hour dom month dow), local tz. */
26
- schedule: string;
27
- /**
28
- * Optional weekday filter applied AFTER the cron expression fires.
29
- * When omitted, every firing passes. Values are matched
30
- * case-insensitively against the local weekday name.
31
- */
32
- days?: DayOfWeek[];
33
- }
34
- export interface WebhookTrigger {
35
- source: 'webhook';
36
- /** Local HTTP path the rule engine listens on, e.g. `/kitchen/motion`. */
37
- path: string;
38
- }
39
- export type Trigger = MqttTrigger | CronTrigger | WebhookTrigger;
40
- export interface TimeBetweenCondition {
41
- time_between: [string, string];
42
- }
43
- export interface DeviceStateCondition {
44
- device: string;
45
- field: string;
46
- op: '==' | '!=' | '<' | '>' | '<=' | '>=';
47
- value: unknown;
48
- }
49
- export interface AllCondition {
50
- all: Condition[];
51
- }
52
- export interface AnyCondition {
53
- any: Condition[];
54
- }
55
- export interface NotCondition {
56
- not: Condition;
57
- }
58
- export type Condition = TimeBetweenCondition | DeviceStateCondition | AllCondition | AnyCondition | NotCondition;
59
- export interface Action {
60
- command: string;
61
- device?: string;
62
- args?: Record<string, unknown> | null;
63
- on_error?: 'continue' | 'stop';
64
- }
65
- export interface Throttle {
66
- max_per: string;
67
- /** Deduplicate identical events arriving within this window after the last fire. */
68
- dedupe_window?: string;
69
- }
70
- export interface Rule {
71
- name: string;
72
- enabled?: boolean;
73
- when: Trigger;
74
- conditions?: Condition[] | null;
75
- then: Action[];
76
- throttle?: Throttle | null;
77
- dry_run?: boolean;
78
- /** Shorthand cooldown — equivalent to throttle.max_per. Takes precedence when both are set. */
79
- cooldown?: string;
80
- /** Hysteresis guard — device state must remain stable for this duration before the rule fires. */
81
- requires_stable_for?: string;
82
- /** Alias for requires_stable_for with clearer semantics (takes precedence when both are set). */
83
- hysteresis?: string;
84
- /** Maximum times this rule may fire per rolling hour (count-based rate limit). */
85
- maxFiringsPerHour?: number;
86
- /** Skip the action if the device's last-known cached state already matches the desired command outcome. */
87
- suppressIfAlreadyDesired?: boolean;
88
- }
89
- export interface AutomationBlock {
90
- enabled?: boolean;
91
- rules?: Rule[] | null;
92
- }
93
- /**
94
- * Engine event — unified shape the matcher consumes regardless of
95
- * trigger source.
96
- */
97
- export interface EngineEvent {
98
- source: TriggerSource;
99
- /** Classifier output for MQTT; schedule string for cron; path for webhook. */
100
- event: string;
101
- t: Date;
102
- /** Resolved deviceId if the trigger carried one (MQTT). */
103
- deviceId?: string;
104
- /** Raw trigger payload for inspection / audit. */
105
- payload?: unknown;
106
- }
107
- /** Guards used outside this file. */
108
- export declare function isMqttTrigger(t: Trigger): t is MqttTrigger;
109
- export declare function isCronTrigger(t: Trigger): t is CronTrigger;
110
- export declare function isWebhookTrigger(t: Trigger): t is WebhookTrigger;
111
- export declare function isTimeBetween(c: Condition): c is TimeBetweenCondition;
112
- export declare function isDeviceState(c: Condition): c is DeviceStateCondition;
113
- export declare function isAllCondition(c: Condition): c is AllCondition;
114
- export declare function isAnyCondition(c: Condition): c is AnyCondition;
115
- export declare function isNotCondition(c: Condition): c is NotCondition;
116
- /** Re-export for consumers that want the single list without a second import. */
117
- export type { DestructiveCommand };
@@ -1,35 +0,0 @@
1
- /**
2
- * Runtime TypeScript shapes for policy v0.2 rule objects.
3
- *
4
- * These are hand-mirrored from `src/policy/schema/v0.2.json` — the ajv
5
- * validator is the source of truth for what a file may contain, this
6
- * file is the source of truth for what the engine expects after load.
7
- * When you edit one, edit the other in the same commit.
8
- */
9
- /** Guards used outside this file. */
10
- export function isMqttTrigger(t) {
11
- return t.source === 'mqtt';
12
- }
13
- export function isCronTrigger(t) {
14
- return t.source === 'cron';
15
- }
16
- export function isWebhookTrigger(t) {
17
- return t.source === 'webhook';
18
- }
19
- export function isTimeBetween(c) {
20
- return Array.isArray(c.time_between);
21
- }
22
- export function isDeviceState(c) {
23
- const d = c;
24
- return typeof d.device === 'string' && typeof d.field === 'string' && typeof d.op === 'string';
25
- }
26
- export function isAllCondition(c) {
27
- return Array.isArray(c.all);
28
- }
29
- export function isAnyCondition(c) {
30
- return Array.isArray(c.any);
31
- }
32
- export function isNotCondition(c) {
33
- return c.not !== undefined && !Array.isArray(c.not);
34
- }
35
- //# sourceMappingURL=types.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/rules/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAuHH,qCAAqC;AACrC,MAAM,UAAU,aAAa,CAAC,CAAU;IACtC,OAAO,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC;AAC7B,CAAC;AACD,MAAM,UAAU,aAAa,CAAC,CAAU;IACtC,OAAO,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC;AAC7B,CAAC;AACD,MAAM,UAAU,gBAAgB,CAAC,CAAU;IACzC,OAAO,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC;AAChC,CAAC;AACD,MAAM,UAAU,aAAa,CAAC,CAAY;IACxC,OAAO,KAAK,CAAC,OAAO,CAAE,CAA0B,CAAC,YAAY,CAAC,CAAC;AACjE,CAAC;AACD,MAAM,UAAU,aAAa,CAAC,CAAY;IACxC,MAAM,CAAC,GAAG,CAAyB,CAAC;IACpC,OAAO,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC;AACjG,CAAC;AACD,MAAM,UAAU,cAAc,CAAC,CAAY;IACzC,OAAO,KAAK,CAAC,OAAO,CAAE,CAAkB,CAAC,GAAG,CAAC,CAAC;AAChD,CAAC;AACD,MAAM,UAAU,cAAc,CAAC,CAAY;IACzC,OAAO,KAAK,CAAC,OAAO,CAAE,CAAkB,CAAC,GAAG,CAAC,CAAC;AAChD,CAAC;AACD,MAAM,UAAU,cAAc,CAAC,CAAY;IACzC,OAAQ,CAAkB,CAAC,GAAG,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAE,CAAkB,CAAC,GAAG,CAAC,CAAC;AAC1F,CAAC"}
@@ -1,63 +0,0 @@
1
- /**
2
- * Local HTTP listener that delivers webhook events to the rules engine.
3
- *
4
- * Scope (E2):
5
- * - Binds to `127.0.0.1` only — the loopback interface keeps the
6
- * listener off the network by default. The plan's integration story
7
- * is that an agent or local script POSTs to this endpoint.
8
- * - Default port is 18790 (phase-3 design doc choice); override with
9
- * `--webhook-port <n>` in `switchbot rules run`. `--webhook-port 0`
10
- * asks the OS for an ephemeral port — useful in tests.
11
- * - Bearer-token auth on every request: `Authorization: Bearer <t>`.
12
- * The expected token comes from `WebhookTokenStore`; unauthorized
13
- * requests get a 401 with no body, no hint about which header
14
- * failed, and an audit entry (`rule-webhook-rejected`).
15
- * - Matches request path against registered webhook rules: only
16
- * `POST /path/exactly/as/declared`. Unknown paths return 404.
17
- *
18
- * Non-goals:
19
- * - No TLS; operators who expose this outside loopback are expected
20
- * to sit behind a reverse proxy that terminates TLS.
21
- * - No payload parsing beyond reading the body as a string — the
22
- * engine passes the raw body through in the event payload.
23
- */
24
- import type { EngineEvent, Rule } from './types.js';
25
- export declare const DEFAULT_WEBHOOK_PORT = 18790;
26
- export interface WebhookDispatch {
27
- (rule: Rule, event: EngineEvent): Promise<void>;
28
- }
29
- export interface WebhookListenerOptions {
30
- rules: Rule[];
31
- /** Bearer token used to authorize incoming requests. */
32
- bearerToken: string;
33
- /**
34
- * Host interface to bind. Defaults to 127.0.0.1; tests can set this
35
- * to '127.0.0.1' + port 0 for ephemeral allocation.
36
- */
37
- host?: string;
38
- port?: number;
39
- dispatch: WebhookDispatch;
40
- /** Optional clock — tests inject a deterministic value. */
41
- now?: () => Date;
42
- }
43
- export declare class WebhookListener {
44
- private readonly opts;
45
- private server;
46
- private readonly pathIndex;
47
- private actualPort;
48
- constructor(opts: WebhookListenerOptions);
49
- /** Start listening. Resolves once the server has bound a port. */
50
- start(): Promise<void>;
51
- stop(): Promise<void>;
52
- getPort(): number | null;
53
- listPaths(): string[];
54
- /**
55
- * Replace the current rule → path index. Used by `engine.reload`: the
56
- * listener keeps its open port and accepted connections, but routes
57
- * subsequent requests against the fresh policy.
58
- */
59
- updateRules(rules: Rule[]): void;
60
- private handle;
61
- private isAuthorized;
62
- private now;
63
- }