@switchbot/openapi-cli 3.2.1 → 3.2.2
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/README.md +3 -1
- package/dist/index.js +57349 -170
- package/package.json +9 -5
- package/dist/api/client.d.ts +0 -31
- package/dist/api/client.js +0 -236
- package/dist/api/client.js.map +0 -1
- package/dist/auth.d.ts +0 -1
- package/dist/auth.js +0 -21
- package/dist/auth.js.map +0 -1
- package/dist/commands/agent-bootstrap.d.ts +0 -10
- package/dist/commands/agent-bootstrap.js +0 -200
- package/dist/commands/agent-bootstrap.js.map +0 -1
- package/dist/commands/auth.d.ts +0 -18
- package/dist/commands/auth.js +0 -355
- package/dist/commands/auth.js.map +0 -1
- package/dist/commands/batch.d.ts +0 -2
- package/dist/commands/batch.js +0 -414
- package/dist/commands/batch.js.map +0 -1
- package/dist/commands/cache.d.ts +0 -2
- package/dist/commands/cache.js +0 -127
- package/dist/commands/cache.js.map +0 -1
- package/dist/commands/capabilities.d.ts +0 -31
- package/dist/commands/capabilities.js +0 -383
- package/dist/commands/capabilities.js.map +0 -1
- package/dist/commands/catalog.d.ts +0 -2
- package/dist/commands/catalog.js +0 -360
- package/dist/commands/catalog.js.map +0 -1
- package/dist/commands/completion.d.ts +0 -2
- package/dist/commands/completion.js +0 -386
- package/dist/commands/completion.js.map +0 -1
- package/dist/commands/config.d.ts +0 -21
- package/dist/commands/config.js +0 -377
- package/dist/commands/config.js.map +0 -1
- package/dist/commands/daemon.d.ts +0 -2
- package/dist/commands/daemon.js +0 -411
- package/dist/commands/daemon.js.map +0 -1
- package/dist/commands/device-meta.d.ts +0 -2
- package/dist/commands/device-meta.js +0 -160
- package/dist/commands/device-meta.js.map +0 -1
- package/dist/commands/devices.d.ts +0 -2
- package/dist/commands/devices.js +0 -949
- package/dist/commands/devices.js.map +0 -1
- package/dist/commands/doctor.d.ts +0 -3
- package/dist/commands/doctor.js +0 -1016
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/events.d.ts +0 -31
- package/dist/commands/events.js +0 -564
- package/dist/commands/events.js.map +0 -1
- package/dist/commands/expand.d.ts +0 -2
- package/dist/commands/expand.js +0 -131
- package/dist/commands/expand.js.map +0 -1
- package/dist/commands/explain.d.ts +0 -2
- package/dist/commands/explain.js +0 -140
- package/dist/commands/explain.js.map +0 -1
- package/dist/commands/health.d.ts +0 -8
- package/dist/commands/health.js +0 -114
- package/dist/commands/health.js.map +0 -1
- package/dist/commands/history.d.ts +0 -2
- package/dist/commands/history.js +0 -321
- package/dist/commands/history.js.map +0 -1
- package/dist/commands/identity.d.ts +0 -45
- package/dist/commands/identity.js +0 -60
- package/dist/commands/identity.js.map +0 -1
- package/dist/commands/install.d.ts +0 -20
- package/dist/commands/install.js +0 -247
- package/dist/commands/install.js.map +0 -1
- package/dist/commands/mcp.d.ts +0 -14
- package/dist/commands/mcp.js +0 -2018
- package/dist/commands/mcp.js.map +0 -1
- package/dist/commands/plan.d.ts +0 -51
- package/dist/commands/plan.js +0 -654
- package/dist/commands/plan.js.map +0 -1
- package/dist/commands/policy.d.ts +0 -24
- package/dist/commands/policy.js +0 -587
- package/dist/commands/policy.js.map +0 -1
- package/dist/commands/quota.d.ts +0 -2
- package/dist/commands/quota.js +0 -79
- package/dist/commands/quota.js.map +0 -1
- package/dist/commands/rules.d.ts +0 -2
- package/dist/commands/rules.js +0 -876
- package/dist/commands/rules.js.map +0 -1
- package/dist/commands/scenes.d.ts +0 -2
- package/dist/commands/scenes.js +0 -265
- package/dist/commands/scenes.js.map +0 -1
- package/dist/commands/schema.d.ts +0 -2
- package/dist/commands/schema.js +0 -185
- package/dist/commands/schema.js.map +0 -1
- package/dist/commands/status-sync.d.ts +0 -2
- package/dist/commands/status-sync.js +0 -132
- package/dist/commands/status-sync.js.map +0 -1
- package/dist/commands/uninstall.d.ts +0 -20
- package/dist/commands/uninstall.js +0 -238
- package/dist/commands/uninstall.js.map +0 -1
- package/dist/commands/upgrade-check.d.ts +0 -2
- package/dist/commands/upgrade-check.js +0 -107
- package/dist/commands/upgrade-check.js.map +0 -1
- package/dist/commands/watch.d.ts +0 -2
- package/dist/commands/watch.js +0 -195
- package/dist/commands/watch.js.map +0 -1
- package/dist/commands/webhook.d.ts +0 -2
- package/dist/commands/webhook.js +0 -183
- package/dist/commands/webhook.js.map +0 -1
- package/dist/config.d.ts +0 -57
- package/dist/config.js +0 -259
- package/dist/config.js.map +0 -1
- package/dist/credentials/backends/file.d.ts +0 -18
- package/dist/credentials/backends/file.js +0 -102
- package/dist/credentials/backends/file.js.map +0 -1
- package/dist/credentials/backends/linux.d.ts +0 -16
- package/dist/credentials/backends/linux.js +0 -130
- package/dist/credentials/backends/linux.js.map +0 -1
- package/dist/credentials/backends/macos.d.ts +0 -18
- package/dist/credentials/backends/macos.js +0 -130
- package/dist/credentials/backends/macos.js.map +0 -1
- package/dist/credentials/backends/windows.d.ts +0 -23
- package/dist/credentials/backends/windows.js +0 -216
- package/dist/credentials/backends/windows.js.map +0 -1
- package/dist/credentials/keychain.d.ts +0 -83
- package/dist/credentials/keychain.js +0 -89
- package/dist/credentials/keychain.js.map +0 -1
- package/dist/credentials/prime.d.ts +0 -32
- package/dist/credentials/prime.js +0 -53
- package/dist/credentials/prime.js.map +0 -1
- package/dist/devices/cache.d.ts +0 -79
- package/dist/devices/cache.js +0 -294
- package/dist/devices/cache.js.map +0 -1
- package/dist/devices/catalog.d.ts +0 -138
- package/dist/devices/catalog.js +0 -768
- package/dist/devices/catalog.js.map +0 -1
- package/dist/devices/device-meta.d.ts +0 -15
- package/dist/devices/device-meta.js +0 -57
- package/dist/devices/device-meta.js.map +0 -1
- package/dist/devices/history-agg.d.ts +0 -37
- package/dist/devices/history-agg.js +0 -139
- package/dist/devices/history-agg.js.map +0 -1
- package/dist/devices/history-query.d.ts +0 -45
- package/dist/devices/history-query.js +0 -182
- package/dist/devices/history-query.js.map +0 -1
- package/dist/devices/param-validator.d.ts +0 -40
- package/dist/devices/param-validator.js +0 -434
- package/dist/devices/param-validator.js.map +0 -1
- package/dist/devices/resources.d.ts +0 -74
- package/dist/devices/resources.js +0 -271
- package/dist/devices/resources.js.map +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js.map +0 -1
- package/dist/install/default-steps.d.ts +0 -66
- package/dist/install/default-steps.js +0 -258
- package/dist/install/default-steps.js.map +0 -1
- package/dist/install/preflight.d.ts +0 -60
- package/dist/install/preflight.js +0 -213
- package/dist/install/preflight.js.map +0 -1
- package/dist/install/steps.d.ts +0 -61
- package/dist/install/steps.js +0 -68
- package/dist/install/steps.js.map +0 -1
- package/dist/lib/command-keywords.d.ts +0 -5
- package/dist/lib/command-keywords.js +0 -18
- package/dist/lib/command-keywords.js.map +0 -1
- package/dist/lib/daemon-state.d.ts +0 -24
- package/dist/lib/daemon-state.js +0 -47
- package/dist/lib/daemon-state.js.map +0 -1
- package/dist/lib/destructive-mode.d.ts +0 -2
- package/dist/lib/destructive-mode.js +0 -13
- package/dist/lib/destructive-mode.js.map +0 -1
- package/dist/lib/devices.d.ts +0 -151
- package/dist/lib/devices.js +0 -383
- package/dist/lib/devices.js.map +0 -1
- package/dist/lib/idempotency.d.ts +0 -46
- package/dist/lib/idempotency.js +0 -107
- package/dist/lib/idempotency.js.map +0 -1
- package/dist/lib/plan-store.d.ts +0 -19
- package/dist/lib/plan-store.js +0 -69
- package/dist/lib/plan-store.js.map +0 -1
- package/dist/lib/request-context.d.ts +0 -7
- package/dist/lib/request-context.js +0 -13
- package/dist/lib/request-context.js.map +0 -1
- package/dist/lib/scenes.d.ts +0 -7
- package/dist/lib/scenes.js +0 -11
- package/dist/lib/scenes.js.map +0 -1
- package/dist/logger.d.ts +0 -4
- package/dist/logger.js +0 -17
- package/dist/logger.js.map +0 -1
- package/dist/mcp/device-history.d.ts +0 -36
- package/dist/mcp/device-history.js +0 -146
- package/dist/mcp/device-history.js.map +0 -1
- package/dist/mcp/events-subscription.d.ts +0 -45
- package/dist/mcp/events-subscription.js +0 -214
- package/dist/mcp/events-subscription.js.map +0 -1
- package/dist/mqtt/client.d.ts +0 -25
- package/dist/mqtt/client.js +0 -181
- package/dist/mqtt/client.js.map +0 -1
- package/dist/mqtt/credential.d.ts +0 -16
- package/dist/mqtt/credential.js +0 -31
- package/dist/mqtt/credential.js.map +0 -1
- package/dist/policy/add-rule.d.ts +0 -21
- package/dist/policy/add-rule.js +0 -125
- package/dist/policy/add-rule.js.map +0 -1
- package/dist/policy/diff.d.ts +0 -21
- package/dist/policy/diff.js +0 -92
- package/dist/policy/diff.js.map +0 -1
- package/dist/policy/format.d.ts +0 -6
- package/dist/policy/format.js +0 -58
- package/dist/policy/format.js.map +0 -1
- package/dist/policy/load.d.ts +0 -32
- package/dist/policy/load.js +0 -62
- package/dist/policy/load.js.map +0 -1
- package/dist/policy/migrate.d.ts +0 -21
- package/dist/policy/migrate.js +0 -68
- package/dist/policy/migrate.js.map +0 -1
- package/dist/policy/schema.d.ts +0 -5
- package/dist/policy/schema.js +0 -19
- package/dist/policy/schema.js.map +0 -1
- package/dist/policy/validate.d.ts +0 -19
- package/dist/policy/validate.js +0 -263
- package/dist/policy/validate.js.map +0 -1
- package/dist/rules/action.d.ts +0 -65
- package/dist/rules/action.js +0 -217
- package/dist/rules/action.js.map +0 -1
- package/dist/rules/audit-query.d.ts +0 -51
- package/dist/rules/audit-query.js +0 -90
- package/dist/rules/audit-query.js.map +0 -1
- package/dist/rules/conflict-analyzer.d.ts +0 -57
- package/dist/rules/conflict-analyzer.js +0 -215
- package/dist/rules/conflict-analyzer.js.map +0 -1
- package/dist/rules/cron-scheduler.d.ts +0 -62
- package/dist/rules/cron-scheduler.js +0 -187
- package/dist/rules/cron-scheduler.js.map +0 -1
- package/dist/rules/destructive.d.ts +0 -20
- package/dist/rules/destructive.js +0 -53
- package/dist/rules/destructive.js.map +0 -1
- package/dist/rules/engine.d.ts +0 -193
- package/dist/rules/engine.js +0 -758
- package/dist/rules/engine.js.map +0 -1
- package/dist/rules/matcher.d.ts +0 -56
- package/dist/rules/matcher.js +0 -231
- package/dist/rules/matcher.js.map +0 -1
- package/dist/rules/pid-file.d.ts +0 -43
- package/dist/rules/pid-file.js +0 -96
- package/dist/rules/pid-file.js.map +0 -1
- package/dist/rules/quiet-hours.d.ts +0 -26
- package/dist/rules/quiet-hours.js +0 -46
- package/dist/rules/quiet-hours.js.map +0 -1
- package/dist/rules/suggest.d.ts +0 -20
- package/dist/rules/suggest.js +0 -96
- package/dist/rules/suggest.js.map +0 -1
- package/dist/rules/throttle.d.ts +0 -61
- package/dist/rules/throttle.js +0 -117
- package/dist/rules/throttle.js.map +0 -1
- package/dist/rules/types.d.ts +0 -117
- package/dist/rules/types.js +0 -35
- package/dist/rules/types.js.map +0 -1
- package/dist/rules/webhook-listener.d.ts +0 -63
- package/dist/rules/webhook-listener.js +0 -224
- package/dist/rules/webhook-listener.js.map +0 -1
- package/dist/rules/webhook-token.d.ts +0 -50
- package/dist/rules/webhook-token.js +0 -91
- package/dist/rules/webhook-token.js.map +0 -1
- package/dist/schema/field-aliases.d.ts +0 -34
- package/dist/schema/field-aliases.js +0 -132
- package/dist/schema/field-aliases.js.map +0 -1
- package/dist/sinks/dispatcher.d.ts +0 -7
- package/dist/sinks/dispatcher.js +0 -13
- package/dist/sinks/dispatcher.js.map +0 -1
- package/dist/sinks/file.d.ts +0 -6
- package/dist/sinks/file.js +0 -20
- package/dist/sinks/file.js.map +0 -1
- package/dist/sinks/format.d.ts +0 -20
- package/dist/sinks/format.js +0 -57
- package/dist/sinks/format.js.map +0 -1
- package/dist/sinks/homeassistant.d.ts +0 -18
- package/dist/sinks/homeassistant.js +0 -45
- package/dist/sinks/homeassistant.js.map +0 -1
- package/dist/sinks/openclaw.d.ts +0 -13
- package/dist/sinks/openclaw.js +0 -34
- package/dist/sinks/openclaw.js.map +0 -1
- package/dist/sinks/stdout.d.ts +0 -4
- package/dist/sinks/stdout.js +0 -6
- package/dist/sinks/stdout.js.map +0 -1
- package/dist/sinks/telegram.d.ts +0 -11
- package/dist/sinks/telegram.js +0 -29
- package/dist/sinks/telegram.js.map +0 -1
- package/dist/sinks/types.d.ts +0 -13
- package/dist/sinks/types.js +0 -2
- package/dist/sinks/types.js.map +0 -1
- package/dist/sinks/webhook.d.ts +0 -6
- package/dist/sinks/webhook.js +0 -23
- package/dist/sinks/webhook.js.map +0 -1
- package/dist/status-sync/manager.d.ts +0 -48
- package/dist/status-sync/manager.js +0 -269
- package/dist/status-sync/manager.js.map +0 -1
- package/dist/utils/arg-parsers.d.ts +0 -16
- package/dist/utils/arg-parsers.js +0 -67
- package/dist/utils/arg-parsers.js.map +0 -1
- package/dist/utils/audit.d.ts +0 -69
- package/dist/utils/audit.js +0 -122
- package/dist/utils/audit.js.map +0 -1
- package/dist/utils/filter.d.ts +0 -81
- package/dist/utils/filter.js +0 -190
- package/dist/utils/filter.js.map +0 -1
- package/dist/utils/flags.d.ts +0 -72
- package/dist/utils/flags.js +0 -187
- package/dist/utils/flags.js.map +0 -1
- package/dist/utils/format.d.ts +0 -9
- package/dist/utils/format.js +0 -118
- package/dist/utils/format.js.map +0 -1
- package/dist/utils/health.d.ts +0 -48
- package/dist/utils/health.js +0 -102
- package/dist/utils/health.js.map +0 -1
- package/dist/utils/help-json.d.ts +0 -39
- package/dist/utils/help-json.js +0 -55
- package/dist/utils/help-json.js.map +0 -1
- package/dist/utils/name-resolver.d.ts +0 -26
- package/dist/utils/name-resolver.js +0 -138
- package/dist/utils/name-resolver.js.map +0 -1
- package/dist/utils/output.d.ts +0 -73
- package/dist/utils/output.js +0 -405
- package/dist/utils/output.js.map +0 -1
- package/dist/utils/quota.d.ts +0 -61
- package/dist/utils/quota.js +0 -228
- package/dist/utils/quota.js.map +0 -1
- package/dist/utils/redact.d.ts +0 -23
- package/dist/utils/redact.js +0 -69
- package/dist/utils/redact.js.map +0 -1
- package/dist/utils/retry.d.ts +0 -72
- package/dist/utils/retry.js +0 -141
- package/dist/utils/retry.js.map +0 -1
- package/dist/utils/string.d.ts +0 -2
- package/dist/utils/string.js +0 -23
- package/dist/utils/string.js.map +0 -1
- package/dist/version.d.ts +0 -2
- package/dist/version.js +0 -5
- package/dist/version.js.map +0 -1
|
@@ -1,224 +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 http from 'node:http';
|
|
25
|
-
import { timingSafeEqual } from 'node:crypto';
|
|
26
|
-
import { writeAudit } from '../utils/audit.js';
|
|
27
|
-
import { isWebhookTrigger } from './types.js';
|
|
28
|
-
export const DEFAULT_WEBHOOK_PORT = 18790;
|
|
29
|
-
const MAX_BODY_BYTES = 16 * 1024; // guard against huge POSTs from misbehaving callers
|
|
30
|
-
export class WebhookListener {
|
|
31
|
-
opts;
|
|
32
|
-
server = null;
|
|
33
|
-
pathIndex = new Map();
|
|
34
|
-
actualPort = null;
|
|
35
|
-
constructor(opts) {
|
|
36
|
-
this.opts = opts;
|
|
37
|
-
for (const rule of opts.rules) {
|
|
38
|
-
if (!isWebhookTrigger(rule.when))
|
|
39
|
-
continue;
|
|
40
|
-
const normalised = normalisePath(rule.when.path);
|
|
41
|
-
if (this.pathIndex.has(normalised)) {
|
|
42
|
-
throw new Error(`WebhookListener: duplicate webhook path "${normalised}" — every webhook rule needs a unique path`);
|
|
43
|
-
}
|
|
44
|
-
this.pathIndex.set(normalised, rule);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
/** Start listening. Resolves once the server has bound a port. */
|
|
48
|
-
async start() {
|
|
49
|
-
if (this.server)
|
|
50
|
-
return;
|
|
51
|
-
const server = http.createServer((req, res) => {
|
|
52
|
-
this.handle(req, res).catch((err) => {
|
|
53
|
-
// The dispatch chain should never reject — but if it does,
|
|
54
|
-
// make sure we close the socket so the caller doesn't hang.
|
|
55
|
-
if (!res.headersSent) {
|
|
56
|
-
res.writeHead(500);
|
|
57
|
-
res.end();
|
|
58
|
-
}
|
|
59
|
-
// eslint-disable-next-line no-console
|
|
60
|
-
console.error(`webhook-listener: unhandled dispatch error: ${err instanceof Error ? err.message : String(err)}`);
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
const host = this.opts.host ?? '127.0.0.1';
|
|
64
|
-
const port = this.opts.port ?? DEFAULT_WEBHOOK_PORT;
|
|
65
|
-
await new Promise((resolve, reject) => {
|
|
66
|
-
const onError = (err) => {
|
|
67
|
-
server.off('listening', onListening);
|
|
68
|
-
reject(err);
|
|
69
|
-
};
|
|
70
|
-
const onListening = () => {
|
|
71
|
-
server.off('error', onError);
|
|
72
|
-
resolve();
|
|
73
|
-
};
|
|
74
|
-
server.once('error', onError);
|
|
75
|
-
server.once('listening', onListening);
|
|
76
|
-
server.listen(port, host);
|
|
77
|
-
});
|
|
78
|
-
const address = server.address();
|
|
79
|
-
this.actualPort = typeof address === 'object' && address ? address.port : port;
|
|
80
|
-
this.server = server;
|
|
81
|
-
}
|
|
82
|
-
async stop() {
|
|
83
|
-
if (!this.server)
|
|
84
|
-
return;
|
|
85
|
-
const server = this.server;
|
|
86
|
-
this.server = null;
|
|
87
|
-
this.actualPort = null;
|
|
88
|
-
await new Promise((resolve) => server.close(() => resolve()));
|
|
89
|
-
}
|
|
90
|
-
getPort() {
|
|
91
|
-
return this.actualPort;
|
|
92
|
-
}
|
|
93
|
-
listPaths() {
|
|
94
|
-
return [...this.pathIndex.keys()].sort();
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Replace the current rule → path index. Used by `engine.reload`: the
|
|
98
|
-
* listener keeps its open port and accepted connections, but routes
|
|
99
|
-
* subsequent requests against the fresh policy.
|
|
100
|
-
*/
|
|
101
|
-
updateRules(rules) {
|
|
102
|
-
const next = new Map();
|
|
103
|
-
for (const rule of rules) {
|
|
104
|
-
if (!isWebhookTrigger(rule.when))
|
|
105
|
-
continue;
|
|
106
|
-
const normalised = normalisePath(rule.when.path);
|
|
107
|
-
if (next.has(normalised)) {
|
|
108
|
-
throw new Error(`WebhookListener.updateRules: duplicate webhook path "${normalised}"`);
|
|
109
|
-
}
|
|
110
|
-
next.set(normalised, rule);
|
|
111
|
-
}
|
|
112
|
-
this.pathIndex.clear();
|
|
113
|
-
for (const [k, v] of next)
|
|
114
|
-
this.pathIndex.set(k, v);
|
|
115
|
-
}
|
|
116
|
-
async handle(req, res) {
|
|
117
|
-
// Auth gate first — reject everything else so a wrong token never
|
|
118
|
-
// reveals which paths exist.
|
|
119
|
-
if (!this.isAuthorized(req)) {
|
|
120
|
-
writeAudit({
|
|
121
|
-
t: this.now().toISOString(),
|
|
122
|
-
kind: 'rule-webhook-rejected',
|
|
123
|
-
deviceId: 'unknown',
|
|
124
|
-
command: req.url ?? '',
|
|
125
|
-
parameter: null,
|
|
126
|
-
commandType: 'command',
|
|
127
|
-
dryRun: true,
|
|
128
|
-
result: 'error',
|
|
129
|
-
error: 'unauthorized',
|
|
130
|
-
});
|
|
131
|
-
res.writeHead(401);
|
|
132
|
-
res.end();
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
if (req.method !== 'POST') {
|
|
136
|
-
res.writeHead(405, { Allow: 'POST' });
|
|
137
|
-
res.end();
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
const reqUrl = req.url ?? '/';
|
|
141
|
-
const questionMarkIdx = reqUrl.indexOf('?');
|
|
142
|
-
const rawPath = questionMarkIdx === -1 ? reqUrl : reqUrl.slice(0, questionMarkIdx);
|
|
143
|
-
const normalised = normalisePath(rawPath);
|
|
144
|
-
const rule = this.pathIndex.get(normalised);
|
|
145
|
-
if (!rule) {
|
|
146
|
-
writeAudit({
|
|
147
|
-
t: this.now().toISOString(),
|
|
148
|
-
kind: 'rule-webhook-rejected',
|
|
149
|
-
deviceId: 'unknown',
|
|
150
|
-
command: rawPath,
|
|
151
|
-
parameter: null,
|
|
152
|
-
commandType: 'command',
|
|
153
|
-
dryRun: true,
|
|
154
|
-
result: 'error',
|
|
155
|
-
error: 'unknown-path',
|
|
156
|
-
});
|
|
157
|
-
res.writeHead(404);
|
|
158
|
-
res.end();
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
const body = await readLimitedBody(req, MAX_BODY_BYTES);
|
|
162
|
-
if (body === null) {
|
|
163
|
-
res.writeHead(413);
|
|
164
|
-
res.end();
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
const event = {
|
|
168
|
-
source: 'webhook',
|
|
169
|
-
event: normalised,
|
|
170
|
-
t: this.now(),
|
|
171
|
-
payload: { path: normalised, body },
|
|
172
|
-
};
|
|
173
|
-
// Accept the request before dispatch so callers aren't held waiting
|
|
174
|
-
// on rule actions (which can include SwitchBot API calls).
|
|
175
|
-
res.writeHead(202, { 'Content-Type': 'application/json' });
|
|
176
|
-
res.end(JSON.stringify({ status: 'accepted', path: normalised }));
|
|
177
|
-
this.opts.dispatch(rule, event).catch(() => undefined);
|
|
178
|
-
}
|
|
179
|
-
isAuthorized(req) {
|
|
180
|
-
const h = req.headers['authorization'];
|
|
181
|
-
if (typeof h !== 'string')
|
|
182
|
-
return false;
|
|
183
|
-
const match = /^Bearer\s+(.+)$/i.exec(h.trim());
|
|
184
|
-
if (!match)
|
|
185
|
-
return false;
|
|
186
|
-
const provided = Buffer.from(match[1].trim(), 'utf-8');
|
|
187
|
-
const expected = Buffer.from(this.opts.bearerToken, 'utf-8');
|
|
188
|
-
if (provided.length !== expected.length)
|
|
189
|
-
return false;
|
|
190
|
-
return timingSafeEqual(provided, expected);
|
|
191
|
-
}
|
|
192
|
-
now() {
|
|
193
|
-
return this.opts.now ? this.opts.now() : new Date();
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
function normalisePath(p) {
|
|
197
|
-
if (!p)
|
|
198
|
-
return '/';
|
|
199
|
-
let out = p.trim();
|
|
200
|
-
if (!out.startsWith('/'))
|
|
201
|
-
out = `/${out}`;
|
|
202
|
-
// Collapse a trailing slash (but leave the root '/').
|
|
203
|
-
if (out.length > 1 && out.endsWith('/'))
|
|
204
|
-
out = out.slice(0, -1);
|
|
205
|
-
return out;
|
|
206
|
-
}
|
|
207
|
-
function readLimitedBody(req, max) {
|
|
208
|
-
return new Promise((resolve, reject) => {
|
|
209
|
-
const chunks = [];
|
|
210
|
-
let total = 0;
|
|
211
|
-
req.on('data', (chunk) => {
|
|
212
|
-
total += chunk.length;
|
|
213
|
-
if (total > max) {
|
|
214
|
-
req.destroy();
|
|
215
|
-
resolve(null);
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
chunks.push(chunk);
|
|
219
|
-
});
|
|
220
|
-
req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
|
|
221
|
-
req.on('error', reject);
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
//# sourceMappingURL=webhook-listener.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"webhook-listener.js","sourceRoot":"","sources":["../../src/rules/webhook-listener.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Webhook bearer-token management for the rules engine.
|
|
3
|
-
*
|
|
4
|
-
* Responsibilities:
|
|
5
|
-
* - Resolve the bearer token the listener will accept. The order is
|
|
6
|
-
* env var (SWITCHBOT_WEBHOOK_TOKEN) → on-disk cache
|
|
7
|
-
* (~/.switchbot/webhook-token, chmod 0600) → generate a fresh
|
|
8
|
-
* 32-byte hex token and persist it.
|
|
9
|
-
* - Rotate the token on demand (`rules webhook-rotate-token` cli).
|
|
10
|
-
*
|
|
11
|
-
* Why not the OS keychain (F1 abstraction)? The webhook bearer is a
|
|
12
|
-
* single opaque string, whereas `CredentialStore` is shaped around the
|
|
13
|
-
* SwitchBot {token,secret} bundle. Fitting a one-field artifact into
|
|
14
|
-
* that contract bloats every profile; keeping it in a 0600 file gives
|
|
15
|
-
* the same protection the CLI has used for `~/.switchbot/config.json`.
|
|
16
|
-
* Promotion into the keychain is a future follow-up once the
|
|
17
|
-
* abstraction grows a generic single-value slot.
|
|
18
|
-
*/
|
|
19
|
-
export interface WebhookTokenStoreOptions {
|
|
20
|
-
/** Override the resolved token path — tests use a tmpdir. */
|
|
21
|
-
filePath?: string;
|
|
22
|
-
/**
|
|
23
|
-
* Override the environment lookup. When set to `false` the env var is
|
|
24
|
-
* not consulted; useful for tests that want the file path exercised
|
|
25
|
-
* even though a token is set in the shell.
|
|
26
|
-
*/
|
|
27
|
-
envLookup?: () => string | undefined;
|
|
28
|
-
}
|
|
29
|
-
export declare class WebhookTokenStore {
|
|
30
|
-
private readonly filePath;
|
|
31
|
-
private readonly envLookup;
|
|
32
|
-
constructor(opts?: WebhookTokenStoreOptions);
|
|
33
|
-
/**
|
|
34
|
-
* Return a bearer token, creating + persisting one if none exists yet.
|
|
35
|
-
* Env var wins when set; otherwise the on-disk token is read (and
|
|
36
|
-
* generated on first call).
|
|
37
|
-
*/
|
|
38
|
-
getOrCreate(): string;
|
|
39
|
-
/**
|
|
40
|
-
* Read the persisted token, returning null when the file is absent
|
|
41
|
-
* or empty. Does NOT consult the env var — callers that want the
|
|
42
|
-
* env-aware path should use `getOrCreate()`.
|
|
43
|
-
*/
|
|
44
|
-
readFromDisk(): string | null;
|
|
45
|
-
/** Write a new token, persisting with 0600 perms. */
|
|
46
|
-
rotate(): string;
|
|
47
|
-
getFilePath(): string;
|
|
48
|
-
private writeToDisk;
|
|
49
|
-
}
|
|
50
|
-
export declare function generateToken(): string;
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Webhook bearer-token management for the rules engine.
|
|
3
|
-
*
|
|
4
|
-
* Responsibilities:
|
|
5
|
-
* - Resolve the bearer token the listener will accept. The order is
|
|
6
|
-
* env var (SWITCHBOT_WEBHOOK_TOKEN) → on-disk cache
|
|
7
|
-
* (~/.switchbot/webhook-token, chmod 0600) → generate a fresh
|
|
8
|
-
* 32-byte hex token and persist it.
|
|
9
|
-
* - Rotate the token on demand (`rules webhook-rotate-token` cli).
|
|
10
|
-
*
|
|
11
|
-
* Why not the OS keychain (F1 abstraction)? The webhook bearer is a
|
|
12
|
-
* single opaque string, whereas `CredentialStore` is shaped around the
|
|
13
|
-
* SwitchBot {token,secret} bundle. Fitting a one-field artifact into
|
|
14
|
-
* that contract bloats every profile; keeping it in a 0600 file gives
|
|
15
|
-
* the same protection the CLI has used for `~/.switchbot/config.json`.
|
|
16
|
-
* Promotion into the keychain is a future follow-up once the
|
|
17
|
-
* abstraction grows a generic single-value slot.
|
|
18
|
-
*/
|
|
19
|
-
import fs from 'node:fs';
|
|
20
|
-
import os from 'node:os';
|
|
21
|
-
import path from 'node:path';
|
|
22
|
-
import { randomBytes } from 'node:crypto';
|
|
23
|
-
const ENV_TOKEN = 'SWITCHBOT_WEBHOOK_TOKEN';
|
|
24
|
-
const DEFAULT_FILE = '.switchbot/webhook-token';
|
|
25
|
-
export class WebhookTokenStore {
|
|
26
|
-
filePath;
|
|
27
|
-
envLookup;
|
|
28
|
-
constructor(opts = {}) {
|
|
29
|
-
this.filePath = opts.filePath ?? path.join(os.homedir(), DEFAULT_FILE);
|
|
30
|
-
this.envLookup = opts.envLookup ?? (() => process.env[ENV_TOKEN]);
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Return a bearer token, creating + persisting one if none exists yet.
|
|
34
|
-
* Env var wins when set; otherwise the on-disk token is read (and
|
|
35
|
-
* generated on first call).
|
|
36
|
-
*/
|
|
37
|
-
getOrCreate() {
|
|
38
|
-
const fromEnv = this.envLookup();
|
|
39
|
-
if (fromEnv && fromEnv.trim().length > 0)
|
|
40
|
-
return fromEnv.trim();
|
|
41
|
-
const existing = this.readFromDisk();
|
|
42
|
-
if (existing)
|
|
43
|
-
return existing;
|
|
44
|
-
const fresh = generateToken();
|
|
45
|
-
this.writeToDisk(fresh);
|
|
46
|
-
return fresh;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Read the persisted token, returning null when the file is absent
|
|
50
|
-
* or empty. Does NOT consult the env var — callers that want the
|
|
51
|
-
* env-aware path should use `getOrCreate()`.
|
|
52
|
-
*/
|
|
53
|
-
readFromDisk() {
|
|
54
|
-
try {
|
|
55
|
-
const raw = fs.readFileSync(this.filePath, 'utf-8').trim();
|
|
56
|
-
return raw.length > 0 ? raw : null;
|
|
57
|
-
}
|
|
58
|
-
catch (err) {
|
|
59
|
-
if (err.code === 'ENOENT')
|
|
60
|
-
return null;
|
|
61
|
-
throw err;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
/** Write a new token, persisting with 0600 perms. */
|
|
65
|
-
rotate() {
|
|
66
|
-
const fresh = generateToken();
|
|
67
|
-
this.writeToDisk(fresh);
|
|
68
|
-
return fresh;
|
|
69
|
-
}
|
|
70
|
-
getFilePath() {
|
|
71
|
-
return this.filePath;
|
|
72
|
-
}
|
|
73
|
-
writeToDisk(token) {
|
|
74
|
-
const dir = path.dirname(this.filePath);
|
|
75
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
76
|
-
fs.writeFileSync(this.filePath, `${token}\n`, { mode: 0o600 });
|
|
77
|
-
// mkdirSync + writeFileSync race can leave broader perms on Windows
|
|
78
|
-
// (perm bits are mostly advisory there anyway), but on POSIX we
|
|
79
|
-
// re-chmod to be explicit about intent.
|
|
80
|
-
try {
|
|
81
|
-
fs.chmodSync(this.filePath, 0o600);
|
|
82
|
-
}
|
|
83
|
-
catch {
|
|
84
|
-
// non-POSIX filesystems may reject chmod — intentional best effort.
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
export function generateToken() {
|
|
89
|
-
return randomBytes(32).toString('hex');
|
|
90
|
-
}
|
|
91
|
-
//# sourceMappingURL=webhook-token.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"webhook-token.js","sourceRoot":"","sources":["../../src/rules/webhook-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,SAAS,GAAG,yBAAyB,CAAC;AAC5C,MAAM,YAAY,GAAG,0BAA0B,CAAC;AAahD,MAAM,OAAO,iBAAiB;IACX,QAAQ,CAAS;IACjB,SAAS,CAA2B;IAErD,YAAY,OAAiC,EAAE;QAC7C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,CAAC,CAAC;QACvE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;IACpE,CAAC;IAED;;;;OAIG;IACH,WAAW;QACT,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QACjC,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;QAEhE,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACrC,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAE9B,MAAM,KAAK,GAAG,aAAa,EAAE,CAAC;QAC9B,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;OAIG;IACH,YAAY;QACV,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;YAC3D,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;QACrC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAC;YAClE,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,qDAAqD;IACrD,MAAM;QACJ,MAAM,KAAK,GAAG,aAAa,EAAE,CAAC;QAC9B,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAEO,WAAW,CAAC,KAAa;QAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxC,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC/D,oEAAoE;QACpE,gEAAgE;QAChE,wCAAwC;QACxC,IAAI,CAAC;YACH,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,oEAAoE;QACtE,CAAC;IACH,CAAC;CACF;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* User-facing aliases for canonical field names.
|
|
3
|
-
*
|
|
4
|
-
* Keys are canonical names (matching API response keys and CLI/schema output);
|
|
5
|
-
* values are lowercase alternatives a user may type for `--fields` or `--filter`.
|
|
6
|
-
*
|
|
7
|
-
* Conflict rules (do not add an alias that violates these — tests will fail):
|
|
8
|
-
* - `temp` is exclusive to `temperature` (NOT `colorTemperature`, `targetTemperature`).
|
|
9
|
-
* - `motion` is exclusive to `moveDetected`; `moving` uses `active` instead.
|
|
10
|
-
* - `mode` is exclusive to top-level `mode` (preset); device-specific modes go through `deviceMode`.
|
|
11
|
-
* - Reserved / too-generic words never appear as aliases: `auto`, `status`, `state`,
|
|
12
|
-
* `switch`, `type`, `on`, `off`.
|
|
13
|
-
* - Device-type words are never aliases: `lock`, `fan`.
|
|
14
|
-
*/
|
|
15
|
-
export declare const FIELD_ALIASES: Record<string, readonly string[]>;
|
|
16
|
-
/**
|
|
17
|
-
* Resolve a user-typed field name to its canonical form against an allowed list.
|
|
18
|
-
*
|
|
19
|
-
* Matching is case-insensitive and trims surrounding whitespace. Direct matches
|
|
20
|
-
* win over alias matches. Throws UsageError if the input is empty or does not
|
|
21
|
-
* match any canonical / alias in the allowed list.
|
|
22
|
-
*/
|
|
23
|
-
export declare function resolveField(input: string, allowedCanonical: readonly string[]): string;
|
|
24
|
-
/**
|
|
25
|
-
* Resolve every field in a list. Preserves order and the original UsageError
|
|
26
|
-
* from resolveField() on the first unknown input.
|
|
27
|
-
*/
|
|
28
|
-
export declare function resolveFieldList(inputs: readonly string[], allowedCanonical: readonly string[]): string[];
|
|
29
|
-
export declare function listSupportedFieldInputs(allowedCanonical: readonly string[]): string[];
|
|
30
|
-
/**
|
|
31
|
-
* All canonical keys known to the alias registry. Use when no dynamic
|
|
32
|
-
* canonical list is available (e.g. `watch` before the first poll response).
|
|
33
|
-
*/
|
|
34
|
-
export declare function listAllCanonical(): string[];
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { UsageError } from '../utils/output.js';
|
|
2
|
-
/**
|
|
3
|
-
* User-facing aliases for canonical field names.
|
|
4
|
-
*
|
|
5
|
-
* Keys are canonical names (matching API response keys and CLI/schema output);
|
|
6
|
-
* values are lowercase alternatives a user may type for `--fields` or `--filter`.
|
|
7
|
-
*
|
|
8
|
-
* Conflict rules (do not add an alias that violates these — tests will fail):
|
|
9
|
-
* - `temp` is exclusive to `temperature` (NOT `colorTemperature`, `targetTemperature`).
|
|
10
|
-
* - `motion` is exclusive to `moveDetected`; `moving` uses `active` instead.
|
|
11
|
-
* - `mode` is exclusive to top-level `mode` (preset); device-specific modes go through `deviceMode`.
|
|
12
|
-
* - Reserved / too-generic words never appear as aliases: `auto`, `status`, `state`,
|
|
13
|
-
* `switch`, `type`, `on`, `off`.
|
|
14
|
-
* - Device-type words are never aliases: `lock`, `fan`.
|
|
15
|
-
*/
|
|
16
|
-
export const FIELD_ALIASES = {
|
|
17
|
-
// Identification (shared with list/filter)
|
|
18
|
-
deviceId: ['id'],
|
|
19
|
-
deviceName: ['name'],
|
|
20
|
-
deviceType: ['type'],
|
|
21
|
-
controlType: ['control'],
|
|
22
|
-
roomName: ['room'],
|
|
23
|
-
roomID: ['roomid'],
|
|
24
|
-
familyName: ['family'],
|
|
25
|
-
hubDeviceId: ['hub'],
|
|
26
|
-
enableCloudService: ['cloud'],
|
|
27
|
-
alias: ['alias'],
|
|
28
|
-
// Phase 1 — common status fields
|
|
29
|
-
battery: ['batt', 'bat'],
|
|
30
|
-
temperature: ['temp', 'ambient'],
|
|
31
|
-
colorTemperature: ['kelvin', 'colortemp'],
|
|
32
|
-
humidity: ['humid', 'rh'],
|
|
33
|
-
brightness: ['bright', 'bri'],
|
|
34
|
-
fanSpeed: ['speed'],
|
|
35
|
-
position: ['pos'],
|
|
36
|
-
moveDetected: ['motion'],
|
|
37
|
-
openState: ['open'],
|
|
38
|
-
doorState: ['door'],
|
|
39
|
-
CO2: ['co2'],
|
|
40
|
-
power: ['enabled'],
|
|
41
|
-
mode: ['preset'],
|
|
42
|
-
// Phase 2 — niche device fields
|
|
43
|
-
childLock: ['safe', 'childlock'],
|
|
44
|
-
targetTemperature: ['setpoint', 'target'],
|
|
45
|
-
electricCurrent: ['current', 'amps'],
|
|
46
|
-
voltage: ['volts'],
|
|
47
|
-
usedElectricity: ['energy', 'kwh'],
|
|
48
|
-
electricityOfDay: ['daily', 'today'],
|
|
49
|
-
weight: ['load'],
|
|
50
|
-
version: ['firmware', 'fw'],
|
|
51
|
-
lightLevel: ['light', 'lux'],
|
|
52
|
-
oscillation: ['swing', 'osc'],
|
|
53
|
-
verticalOscillation: ['vswing'],
|
|
54
|
-
nightStatus: ['night'],
|
|
55
|
-
chargingStatus: ['charging', 'charge'],
|
|
56
|
-
switch1Status: ['ch1', 'channel1'],
|
|
57
|
-
switch2Status: ['ch2', 'channel2'],
|
|
58
|
-
taskType: ['task'],
|
|
59
|
-
moving: ['active'],
|
|
60
|
-
onlineStatus: ['online_status'],
|
|
61
|
-
workingStatus: ['working'],
|
|
62
|
-
// Phase 3 — catalog statusFields coverage
|
|
63
|
-
group: ['cluster'],
|
|
64
|
-
calibrate: ['calibration', 'calib'],
|
|
65
|
-
direction: ['tilt'],
|
|
66
|
-
deviceMode: ['devmode'],
|
|
67
|
-
nebulizationEfficiency: ['mist', 'spray'],
|
|
68
|
-
sound: ['audio'],
|
|
69
|
-
lackWater: ['tank', 'water-low'],
|
|
70
|
-
filterElement: ['filter'],
|
|
71
|
-
color: ['rgb', 'hex'],
|
|
72
|
-
useTime: ['runtime', 'uptime'],
|
|
73
|
-
switchStatus: ['relay'],
|
|
74
|
-
lockState: ['locked'],
|
|
75
|
-
slidePosition: ['slide'],
|
|
76
|
-
// Phase 4 — ultra-niche sensor + webhook fields (~98% coverage target)
|
|
77
|
-
waterLeakDetect: ['leak', 'water'],
|
|
78
|
-
pressure: ['press', 'pa'],
|
|
79
|
-
moveCount: ['movecnt'],
|
|
80
|
-
errorCode: ['err'],
|
|
81
|
-
buttonName: ['btn', 'button'],
|
|
82
|
-
pressedAt: ['pressed'],
|
|
83
|
-
deviceMac: ['mac'],
|
|
84
|
-
detectionState: ['detected', 'detect'],
|
|
85
|
-
};
|
|
86
|
-
/**
|
|
87
|
-
* Resolve a user-typed field name to its canonical form against an allowed list.
|
|
88
|
-
*
|
|
89
|
-
* Matching is case-insensitive and trims surrounding whitespace. Direct matches
|
|
90
|
-
* win over alias matches. Throws UsageError if the input is empty or does not
|
|
91
|
-
* match any canonical / alias in the allowed list.
|
|
92
|
-
*/
|
|
93
|
-
export function resolveField(input, allowedCanonical) {
|
|
94
|
-
const normalized = input.trim().toLowerCase();
|
|
95
|
-
if (!normalized) {
|
|
96
|
-
throw new UsageError('Field name cannot be empty.');
|
|
97
|
-
}
|
|
98
|
-
for (const canonical of allowedCanonical) {
|
|
99
|
-
if (canonical.toLowerCase() === normalized)
|
|
100
|
-
return canonical;
|
|
101
|
-
}
|
|
102
|
-
for (const canonical of allowedCanonical) {
|
|
103
|
-
const aliases = FIELD_ALIASES[canonical] ?? [];
|
|
104
|
-
if (aliases.some((a) => a.toLowerCase() === normalized))
|
|
105
|
-
return canonical;
|
|
106
|
-
}
|
|
107
|
-
throw new UsageError(`Unknown field "${input}". Supported: ${listSupportedFieldInputs(allowedCanonical).join(', ')}`);
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Resolve every field in a list. Preserves order and the original UsageError
|
|
111
|
-
* from resolveField() on the first unknown input.
|
|
112
|
-
*/
|
|
113
|
-
export function resolveFieldList(inputs, allowedCanonical) {
|
|
114
|
-
return inputs.map((f) => resolveField(f, allowedCanonical));
|
|
115
|
-
}
|
|
116
|
-
export function listSupportedFieldInputs(allowedCanonical) {
|
|
117
|
-
const out = new Set();
|
|
118
|
-
for (const canonical of allowedCanonical) {
|
|
119
|
-
out.add(canonical);
|
|
120
|
-
for (const alias of FIELD_ALIASES[canonical] ?? [])
|
|
121
|
-
out.add(alias);
|
|
122
|
-
}
|
|
123
|
-
return [...out];
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* All canonical keys known to the alias registry. Use when no dynamic
|
|
127
|
-
* canonical list is available (e.g. `watch` before the first poll response).
|
|
128
|
-
*/
|
|
129
|
-
export function listAllCanonical() {
|
|
130
|
-
return Object.keys(FIELD_ALIASES);
|
|
131
|
-
}
|
|
132
|
-
//# sourceMappingURL=field-aliases.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"field-aliases.js","sourceRoot":"","sources":["../../src/schema/field-aliases.ts"],"names":[],"mappings":"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"}
|
package/dist/sinks/dispatcher.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export class SinkDispatcher {
|
|
2
|
-
sinks;
|
|
3
|
-
constructor(sinks) {
|
|
4
|
-
this.sinks = sinks;
|
|
5
|
-
}
|
|
6
|
-
async dispatch(event) {
|
|
7
|
-
await Promise.allSettled(this.sinks.map((s) => s.write(event)));
|
|
8
|
-
}
|
|
9
|
-
async close() {
|
|
10
|
-
await Promise.allSettled(this.sinks.map((s) => s.close?.()));
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
//# sourceMappingURL=dispatcher.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dispatcher.js","sourceRoot":"","sources":["../../src/sinks/dispatcher.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,cAAc;IACjB,KAAK,CAAS;IAEtB,YAAY,KAAa;QACvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,KAAoB;QACjC,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IAC/D,CAAC;CACF"}
|
package/dist/sinks/file.d.ts
DELETED
package/dist/sinks/file.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
export class FileSink {
|
|
4
|
-
filePath;
|
|
5
|
-
constructor(filePath) {
|
|
6
|
-
this.filePath = path.resolve(filePath);
|
|
7
|
-
const dir = path.dirname(this.filePath);
|
|
8
|
-
if (!fs.existsSync(dir))
|
|
9
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
10
|
-
}
|
|
11
|
-
async write(event) {
|
|
12
|
-
try {
|
|
13
|
-
fs.appendFileSync(this.filePath, JSON.stringify(event) + '\n', { encoding: 'utf-8' });
|
|
14
|
-
}
|
|
15
|
-
catch {
|
|
16
|
-
// best-effort
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
//# sourceMappingURL=file.js.map
|
package/dist/sinks/file.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"file.js","sourceRoot":"","sources":["../../src/sinks/file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,MAAM,OAAO,QAAQ;IACX,QAAQ,CAAS;IAEzB,YAAY,QAAgB;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,KAAoB;QAC9B,IAAI,CAAC;YACH,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QACxF,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;IACH,CAAC;CACF"}
|
package/dist/sinks/format.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export interface DeviceContext {
|
|
2
|
-
deviceMac?: string;
|
|
3
|
-
deviceType?: string;
|
|
4
|
-
temperature?: number;
|
|
5
|
-
humidity?: number;
|
|
6
|
-
power?: string;
|
|
7
|
-
battery?: number;
|
|
8
|
-
brightness?: string;
|
|
9
|
-
detectionState?: string;
|
|
10
|
-
openState?: string;
|
|
11
|
-
lockState?: string;
|
|
12
|
-
lightLevel?: number;
|
|
13
|
-
[key: string]: unknown;
|
|
14
|
-
}
|
|
15
|
-
export declare function formatEventText(context: DeviceContext): string;
|
|
16
|
-
export declare function parseSinkEvent(payload: unknown): {
|
|
17
|
-
deviceId: string;
|
|
18
|
-
deviceType: string;
|
|
19
|
-
text: string;
|
|
20
|
-
};
|