@trillboards/edge-sdk 0.2.20 → 0.2.24

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 (48) hide show
  1. package/deploy/macos/scripts/setup-litertlm.sh +30 -0
  2. package/deploy/windows/e2e/test-enterprise-trust-store.ps1 +341 -0
  3. package/deploy/windows/setup-litertlm.ps1 +49 -1
  4. package/dist/AudienceAnalyzeClient.d.ts +32 -1
  5. package/dist/AudienceAnalyzeClient.d.ts.map +1 -1
  6. package/dist/AudienceAnalyzeClient.js +34 -5
  7. package/dist/AudienceAnalyzeClient.js.map +1 -1
  8. package/dist/CloudSensingManager.d.ts +40 -0
  9. package/dist/CloudSensingManager.d.ts.map +1 -1
  10. package/dist/CloudSensingManager.js +117 -1
  11. package/dist/CloudSensingManager.js.map +1 -1
  12. package/dist/EdgeAgent.js +1 -1
  13. package/dist/cli.d.ts.map +1 -1
  14. package/dist/cli.js +60 -0
  15. package/dist/cli.js.map +1 -1
  16. package/dist/diagnose.d.ts +37 -4
  17. package/dist/diagnose.d.ts.map +1 -1
  18. package/dist/diagnose.js +155 -6
  19. package/dist/diagnose.js.map +1 -1
  20. package/dist/enterpriseNetwork.d.ts +130 -0
  21. package/dist/enterpriseNetwork.d.ts.map +1 -0
  22. package/dist/enterpriseNetwork.js +568 -0
  23. package/dist/enterpriseNetwork.js.map +1 -0
  24. package/dist/enterpriseProxy.d.ts +73 -0
  25. package/dist/enterpriseProxy.d.ts.map +1 -0
  26. package/dist/enterpriseProxy.js +406 -0
  27. package/dist/enterpriseProxy.js.map +1 -0
  28. package/dist/enterpriseTrust.d.ts +188 -0
  29. package/dist/enterpriseTrust.d.ts.map +1 -0
  30. package/dist/enterpriseTrust.js +615 -0
  31. package/dist/enterpriseTrust.js.map +1 -0
  32. package/dist/index.d.ts +10 -0
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +29 -1
  35. package/dist/index.js.map +1 -1
  36. package/dist/localNetworkAccess.d.ts +166 -0
  37. package/dist/localNetworkAccess.d.ts.map +1 -0
  38. package/dist/localNetworkAccess.js +490 -0
  39. package/dist/localNetworkAccess.js.map +1 -0
  40. package/dist/sensingRunMode.d.ts +36 -0
  41. package/dist/sensingRunMode.d.ts.map +1 -1
  42. package/dist/sensingRunMode.js +78 -1
  43. package/dist/sensingRunMode.js.map +1 -1
  44. package/dist/transportFailure.d.ts +118 -0
  45. package/dist/transportFailure.d.ts.map +1 -0
  46. package/dist/transportFailure.js +267 -0
  47. package/dist/transportFailure.js.map +1 -0
  48. package/package.json +1 -1
@@ -0,0 +1,490 @@
1
+ "use strict";
2
+ /**
3
+ * macOS **Local Network** (TCC) access detection.
4
+ *
5
+ * ## Why this file exists
6
+ *
7
+ * On macOS 15+ every process that talks to a private-IP LAN host is gated by
8
+ * the *Local Network* privacy grant. The connector's whole camera surface is
9
+ * LAN traffic — ONVIF WS-Discovery multicast, the subnet TCP sweep, and RTSP
10
+ * frame capture — so a missing grant takes every camera offline at once.
11
+ *
12
+ * The failure it produces is not silence, it is **misattribution**: ffmpeg
13
+ * reports "no route to host", `classifyRtspFailureClass` maps that to
14
+ * `rtsp_unreachable`, and the portal tells the operator to check that their
15
+ * camera and connector are on the same network. They are. The fix is a
16
+ * checkbox in System Settings that nobody was told to tick.
17
+ *
18
+ * ## What macOS actually exposes — measured, not assumed
19
+ *
20
+ * Measured on macOS 26.5.2 (arm64) on 2026-08-14:
21
+ *
22
+ * - The grant is **not readable**. `kTCCServiceLocalNetwork` does not exist in
23
+ * `tccd`'s service table (positive control: `kTCCServiceCamera` is present),
24
+ * there is no row in either TCC.db, and `tccutil` cannot address it. The
25
+ * decision is owned by `nehelper` (`com.apple.network.localnetworkdecision`)
26
+ * and is not exposed to a client process by any public or file-level means.
27
+ * **So the state must be inferred from behaviour.**
28
+ *
29
+ * - Denial has a sharp, specific signature. The *same* binary, same machine,
30
+ * same network, same minute, differing only in who launched it:
31
+ *
32
+ * | operation | LAN allowed | LAN denied |
33
+ * |----------------------------------|----------------------|----------------------|
34
+ * | `sendto` 239.255.255.250:3702 | sent | **EHOSTUNREACH, 0 ms** |
35
+ * | `connect` gateway:80 (host up) | connected, 4 ms | **EHOSTUNREACH, 1 ms** |
36
+ * | `connect` gateway:9 (port shut) | ECONNREFUSED, 1005 ms| **EHOSTUNREACH, 0 ms** |
37
+ * | `connect` 192.168.0.222 (no host)| timeout, 3004 ms | timeout, 3193 ms |
38
+ * | `connect` 127.0.0.1 (loopback) | connected | connected |
39
+ *
40
+ * Two things in that table are the entire design:
41
+ *
42
+ * 1. **The absent host times out in BOTH states.** A probe that only tries the
43
+ * camera can never tell "denied" from "the NVR is off", because they look
44
+ * identical. That is precisely the bug, so a probe that reproduces it is
45
+ * worthless.
46
+ *
47
+ * 2. **Multicast `sendto` is the clean discriminator.** An empty network
48
+ * segment still *accepts* a multicast send — nothing answers, but the send
49
+ * succeeds. Only the TCC gate makes `sendto` itself fail. And an immediate
50
+ * `EHOSTUNREACH` toward an address on the machine's own directly-connected
51
+ * subnet cannot come from routing: the kernel has a connected route there by
52
+ * construction, and a missing host shows up as an ARP timeout instead.
53
+ *
54
+ * Loopback is deliberately only a control, never evidence: it is never gated,
55
+ * so it succeeds in both states and separates nothing.
56
+ *
57
+ * ## Why NOT the default gateway
58
+ *
59
+ * The obvious probe — `route -n get default` — is wrong, and measurably so.
60
+ * On the test machine the default route is a Tailscale `utun` interface, and
61
+ * under a denied grant that endpoint answered `ECONNREFUSED` in the same run
62
+ * where the real LAN returned `EHOSTUNREACH`. A VPN default route is not a LAN
63
+ * host and is not gated, so probing it reports "the LAN is fine" every time and
64
+ * sends the operator straight back to debugging the recorder. Probe targets are
65
+ * therefore derived from the machine's **own directly-connected IPv4 subnets**
66
+ * via `os.networkInterfaces()`, never from the default route.
67
+ *
68
+ * ## Failing safe
69
+ *
70
+ * Every ambiguous outcome resolves to `unknown`, never to `denied`. Positive
71
+ * evidence that the LAN is reachable (a completed connect, or an RST) vetoes a
72
+ * denial verdict outright. Claiming a permission problem that isn't there sends
73
+ * the operator to the wrong place just as surely as the bug this replaces.
74
+ */
75
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
76
+ if (k2 === undefined) k2 = k;
77
+ var desc = Object.getOwnPropertyDescriptor(m, k);
78
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
79
+ desc = { enumerable: true, get: function() { return m[k]; } };
80
+ }
81
+ Object.defineProperty(o, k2, desc);
82
+ }) : (function(o, m, k, k2) {
83
+ if (k2 === undefined) k2 = k;
84
+ o[k2] = m[k];
85
+ }));
86
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
87
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
88
+ }) : function(o, v) {
89
+ o["default"] = v;
90
+ });
91
+ var __importStar = (this && this.__importStar) || (function () {
92
+ var ownKeys = function(o) {
93
+ ownKeys = Object.getOwnPropertyNames || function (o) {
94
+ var ar = [];
95
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
96
+ return ar;
97
+ };
98
+ return ownKeys(o);
99
+ };
100
+ return function (mod) {
101
+ if (mod && mod.__esModule) return mod;
102
+ var result = {};
103
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
104
+ __setModuleDefault(result, mod);
105
+ return result;
106
+ };
107
+ })();
108
+ Object.defineProperty(exports, "__esModule", { value: true });
109
+ exports.LOCAL_NETWORK_DENIED_SUMMARY = exports.LOCAL_NETWORK_DENIED_SUGGESTION = void 0;
110
+ exports.probeLocalNetworkAccess = probeLocalNetworkAccess;
111
+ exports.decideLocalNetworkVerdict = decideLocalNetworkVerdict;
112
+ const dgram = __importStar(require("dgram"));
113
+ const net = __importStar(require("net"));
114
+ const os = __importStar(require("os"));
115
+ /** WS-Discovery group — the exact target `discovery.ts` probes. */
116
+ const WSD_MULTICAST_ADDR = '239.255.255.250';
117
+ const WSD_MULTICAST_PORT = 3702;
118
+ /**
119
+ * A connect that fails this fast never left the host. Real LAN round trips —
120
+ * even an RST from a directly-attached router — were measured at ~1 s; the
121
+ * blocked path returned in 0-1 ms. 250 ms is two orders of magnitude of margin
122
+ * on the blocked side and well under the observed floor on the allowed side.
123
+ */
124
+ const IMMEDIATE_FAILURE_MS = 250;
125
+ /** Per-target TCP budget. Absent hosts hit this; blocked ones never get near it. */
126
+ const DEFAULT_TCP_TIMEOUT_MS = 1200;
127
+ /** errno names macOS returns for a gated local-network operation. */
128
+ const BLOCKED_ERROR_CODES = new Set(['EHOSTUNREACH', 'ENETUNREACH', 'EPERM', 'EACCES']);
129
+ /** Ports worth trying on a LAN neighbour: a closed one is as good as an open one. */
130
+ const PROBE_PORTS = [80, 443];
131
+ /** IPv4 dotted-quad → uint32. */
132
+ function ipv4ToInt(ip) {
133
+ const parts = ip.split('.');
134
+ if (parts.length !== 4)
135
+ return null;
136
+ let out = 0;
137
+ for (const part of parts) {
138
+ const n = Number(part);
139
+ if (!Number.isInteger(n) || n < 0 || n > 255)
140
+ return null;
141
+ out = (out << 8) | n;
142
+ }
143
+ return out >>> 0;
144
+ }
145
+ function intToIpv4(value) {
146
+ return [(value >>> 24) & 255, (value >>> 16) & 255, (value >>> 8) & 255, value & 255].join('.');
147
+ }
148
+ /**
149
+ * Directly-connected IPv4 subnets. These are the only place an immediate
150
+ * `EHOSTUNREACH` is diagnostic: the kernel has a route to them by construction,
151
+ * so an instant refusal there came from something above routing.
152
+ */
153
+ function connectedSubnets(ifaces) {
154
+ const out = [];
155
+ for (const infos of Object.values(ifaces)) {
156
+ if (!infos)
157
+ continue;
158
+ for (const info of infos) {
159
+ // Node <18 reports `family` as 'IPv4'; newer builds may use 4.
160
+ const isV4 = info.family === 'IPv4' || info.family === 4;
161
+ if (!isV4 || info.internal)
162
+ continue;
163
+ const addr = ipv4ToInt(info.address);
164
+ const mask = info.netmask ? ipv4ToInt(info.netmask) : null;
165
+ if (addr === null || mask === null || mask === 0)
166
+ continue;
167
+ // A /32 (point-to-point tunnel: VPN, utun) has no local segment to probe.
168
+ if (mask === 0xffffffff)
169
+ continue;
170
+ out.push({
171
+ address: info.address,
172
+ netmask: info.netmask,
173
+ network: (addr & mask) >>> 0,
174
+ mask,
175
+ });
176
+ }
177
+ }
178
+ return out;
179
+ }
180
+ /**
181
+ * Every IPv4 address this host owns — loopback and point-to-point tunnels
182
+ * included, which is why this does NOT reuse `connectedSubnets`' filters.
183
+ *
184
+ * A connection to one of our own addresses never leaves the box, so it is
185
+ * never subject to the Local Network gate: it answers (or RSTs) identically
186
+ * whether the grant is allowed or denied. Probing one would therefore produce
187
+ * a `reachableTarget` that is not evidence of anything, and `decideVerdict`
188
+ * treats a reachable target as a VETO over a blocked multicast send — so a
189
+ * self-probe does not merely add noise, it converts a real `denied` into
190
+ * `granted` and puts us straight back to reporting `rtsp_unreachable` while
191
+ * macOS blocks every camera.
192
+ *
193
+ * This is not hypothetical: the `.1` convention in `buildTargets` picks the
194
+ * host's OWN address on any subnet where this Mac is the router — Internet
195
+ * Sharing (192.168.2.1), and the host-only bridges VMware/Parallels/VirtualBox
196
+ * install (172.16.x.1, 10.211.55.1, 192.168.56.1). Those interfaces are
197
+ * non-internal and carry a real netmask, so they survive every other filter.
198
+ */
199
+ function ownAddresses(ifaces) {
200
+ const own = new Set();
201
+ for (const infos of Object.values(ifaces)) {
202
+ if (!infos)
203
+ continue;
204
+ for (const info of infos) {
205
+ const isV4 = info.family === 'IPv4' || info.family === 4;
206
+ if (isV4 && info.address)
207
+ own.add(info.address);
208
+ }
209
+ }
210
+ return own;
211
+ }
212
+ function isOnConnectedSubnet(host, subnets) {
213
+ const addr = ipv4ToInt(host);
214
+ if (addr === null)
215
+ return false;
216
+ return subnets.some((s) => ((addr & s.mask) >>> 0) === s.network);
217
+ }
218
+ /**
219
+ * Probe targets, best first.
220
+ *
221
+ * Configured camera hosts lead because they are known-real LAN devices. The
222
+ * conventional `.1` follows: on a /24 it is the router in the overwhelming
223
+ * majority of deployments, and — critically — a *closed port* on it is just as
224
+ * useful as an open one, because an RST proves the packet made the round trip.
225
+ *
226
+ * `own` removes this host's own addresses from both sources. Only an
227
+ * off-box destination can carry information about a gate that exists to
228
+ * mediate off-box destinations; see `ownAddresses`.
229
+ */
230
+ function buildTargets(subnets, extraHosts, own) {
231
+ const targets = [];
232
+ const seen = new Set();
233
+ const push = (host) => {
234
+ if (!host || seen.has(host) || own.has(host))
235
+ return;
236
+ seen.add(host);
237
+ targets.push(host);
238
+ };
239
+ for (const host of extraHosts) {
240
+ if (isOnConnectedSubnet(host, subnets))
241
+ push(host);
242
+ }
243
+ for (const subnet of subnets) {
244
+ push(intToIpv4((subnet.network | 1) >>> 0));
245
+ }
246
+ return targets;
247
+ }
248
+ function tcpProbe(host, port, timeoutMs) {
249
+ return new Promise((resolve) => {
250
+ const startedAt = Date.now();
251
+ const socket = new net.Socket();
252
+ let settled = false;
253
+ const finish = (outcome, code) => {
254
+ if (settled)
255
+ return;
256
+ settled = true;
257
+ try {
258
+ socket.destroy();
259
+ }
260
+ catch {
261
+ /* already gone */
262
+ }
263
+ resolve({ target: `${host}:${port}`, outcome, code, elapsedMs: Date.now() - startedAt });
264
+ };
265
+ socket.setTimeout(timeoutMs, () => finish('silent'));
266
+ socket.once('connect', () => finish('reachable'));
267
+ socket.once('error', (err) => {
268
+ const code = err.code ?? 'UNKNOWN';
269
+ const elapsed = Date.now() - startedAt;
270
+ // An RST is positive proof the LAN carried our packet and brought an
271
+ // answer back — it means the host is there and declining, not blocked.
272
+ if (code === 'ECONNREFUSED' || code === 'ECONNRESET')
273
+ return finish('reachable', code);
274
+ // Blocked errnos only count when they arrive impossibly fast. The same
275
+ // errno after a real timeout is an ordinary unreachable host.
276
+ if (BLOCKED_ERROR_CODES.has(code) && elapsed <= IMMEDIATE_FAILURE_MS) {
277
+ return finish('blocked', code);
278
+ }
279
+ finish('silent', code);
280
+ });
281
+ try {
282
+ socket.connect(port, host);
283
+ }
284
+ catch (err) {
285
+ finish('silent', err?.code);
286
+ }
287
+ });
288
+ }
289
+ /**
290
+ * The WS-Discovery multicast send — the single strongest signal available.
291
+ *
292
+ * An empty LAN still accepts this datagram; only the TCC gate rejects the
293
+ * `sendto` itself. Nothing is expected to answer, so no listener is set up.
294
+ */
295
+ function multicastProbe(interfaceAddress) {
296
+ return new Promise((resolve) => {
297
+ let socket;
298
+ try {
299
+ socket = dgram.createSocket({ type: 'udp4', reuseAddr: true });
300
+ }
301
+ catch (err) {
302
+ return resolve({ result: 'error', code: err?.code });
303
+ }
304
+ let settled = false;
305
+ const finish = (result, code) => {
306
+ if (settled)
307
+ return;
308
+ settled = true;
309
+ try {
310
+ socket.close();
311
+ }
312
+ catch {
313
+ /* already closed */
314
+ }
315
+ resolve({ result, code });
316
+ };
317
+ const classify = (code) => code && BLOCKED_ERROR_CODES.has(code) ? finish('blocked', code) : finish('error', code);
318
+ socket.once('error', (err) => classify(err.code));
319
+ // Guard against a socket that never settles for any reason.
320
+ const guard = setTimeout(() => finish('error', 'ETIMEDOUT'), 2000);
321
+ if (typeof guard.unref === 'function')
322
+ guard.unref();
323
+ try {
324
+ socket.bind(0, () => {
325
+ try {
326
+ socket.setMulticastTTL(1);
327
+ // Pin the egress to the LAN interface. Without this the kernel picks
328
+ // one from the route table, and on a host with Tailscale/ZeroTier/a
329
+ // corporate VPN that route is the tunnel — `route to 239.255.255.250
330
+ // -> utun4` was measured on the very machine this was developed on,
331
+ // while the cameras sat on en0. A probe that leaves down the tunnel
332
+ // is not testing the path the cameras are on.
333
+ if (interfaceAddress)
334
+ socket.setMulticastInterface(interfaceAddress);
335
+ }
336
+ catch {
337
+ /* not fatal — the send is what we are measuring */
338
+ }
339
+ const payload = Buffer.from('<trillboards:probe/>');
340
+ socket.send(payload, 0, payload.length, WSD_MULTICAST_PORT, WSD_MULTICAST_ADDR, (err) => {
341
+ clearTimeout(guard);
342
+ if (err)
343
+ return classify(err.code);
344
+ finish('sent');
345
+ });
346
+ });
347
+ }
348
+ catch (err) {
349
+ clearTimeout(guard);
350
+ classify(err?.code);
351
+ }
352
+ });
353
+ }
354
+ /**
355
+ * Decide whether this process can reach the local network.
356
+ *
357
+ * Never throws, never rejects. Ambiguity always resolves toward `unknown`.
358
+ */
359
+ async function probeLocalNetworkAccess(options = {}) {
360
+ const platform = options.platform ?? process.platform;
361
+ const emptyEvidence = {
362
+ multicastSend: 'skipped',
363
+ silentTargets: [],
364
+ loopbackUsable: false,
365
+ subnets: [],
366
+ };
367
+ // Only macOS gates local-network traffic. Reporting anything else on Linux or
368
+ // Windows would invent a permission problem that cannot exist there.
369
+ if (platform !== 'darwin') {
370
+ return {
371
+ verdict: 'not_applicable',
372
+ reason: `${platform} has no Local Network permission gate`,
373
+ evidence: emptyEvidence,
374
+ };
375
+ }
376
+ const ifaces = (options.networkInterfaces ?? os.networkInterfaces)();
377
+ const subnets = connectedSubnets(ifaces);
378
+ const evidence = {
379
+ ...emptyEvidence,
380
+ subnets: subnets.map((s) => `${s.address}/${s.netmask}`),
381
+ };
382
+ if (subnets.length === 0) {
383
+ return {
384
+ verdict: 'unknown',
385
+ reason: 'no directly-connected IPv4 network — cannot assess Local Network access',
386
+ evidence,
387
+ };
388
+ }
389
+ const timeoutMs = options.tcpTimeoutMs ?? DEFAULT_TCP_TIMEOUT_MS;
390
+ const runTcp = options.tcpProbeImpl ?? tcpProbe;
391
+ const runMulticast = options.multicastProbeImpl ?? multicastProbe;
392
+ // Control: prove this process can open sockets at all. Loopback is never
393
+ // gated, so a failure here means something other than a Local Network denial.
394
+ // ECONNREFUSED on a closed port is the expected, healthy answer.
395
+ const loopback = await runTcp('127.0.0.1', 9, Math.min(timeoutMs, 500));
396
+ evidence.loopbackUsable = loopback.outcome === 'reachable' || loopback.outcome === 'silent';
397
+ const multicast = await runMulticast(subnets[0].address);
398
+ evidence.multicastSend = multicast.result;
399
+ if (multicast.code)
400
+ evidence.multicastErrorCode = multicast.code;
401
+ const targets = buildTargets(subnets, options.extraHosts ?? [], ownAddresses(ifaces));
402
+ for (const host of targets) {
403
+ for (const port of PROBE_PORTS) {
404
+ const outcome = await runTcp(host, port, timeoutMs);
405
+ if (outcome.outcome === 'reachable') {
406
+ evidence.reachableTarget = outcome.target;
407
+ break;
408
+ }
409
+ if (outcome.outcome === 'blocked') {
410
+ evidence.blockedTarget = outcome.target;
411
+ break;
412
+ }
413
+ evidence.silentTargets.push(outcome.target);
414
+ }
415
+ // Positive reachability is decisive; stop as soon as we have it.
416
+ if (evidence.reachableTarget)
417
+ break;
418
+ }
419
+ const decision = decideLocalNetworkVerdict(evidence);
420
+ return { ...decision, evidence };
421
+ }
422
+ /**
423
+ * The verdict rule, isolated from all I/O.
424
+ *
425
+ * Split out so it can be driven from the socket outcomes *recorded on a Mac
426
+ * that was actually blocked*. The OS-level denial could not be re-induced on
427
+ * demand after it cleared, so replaying the measured evidence through this
428
+ * exact function is the only way the `denied` branch gets tested against real
429
+ * data rather than against an invented signature.
430
+ */
431
+ function decideLocalNetworkVerdict(evidence) {
432
+ // Anything on the local segment answered us — the grant cannot be missing.
433
+ // This veto runs first on purpose: it is the only unambiguous evidence here.
434
+ if (evidence.reachableTarget) {
435
+ return {
436
+ verdict: 'granted',
437
+ reason: `local network reachable (${evidence.reachableTarget} answered)`,
438
+ };
439
+ }
440
+ if (!evidence.loopbackUsable) {
441
+ return {
442
+ verdict: 'unknown',
443
+ reason: 'loopback socket unusable — this process cannot open sockets at all',
444
+ };
445
+ }
446
+ // The multicast send is the discriminator. An empty segment still ACCEPTS the
447
+ // datagram — nothing answers, but `sendto` succeeds — so a refusal here is not
448
+ // something an absent camera, an absent recorder, or an empty VLAN can produce.
449
+ if (evidence.multicastSend === 'blocked') {
450
+ const corroborated = Boolean(evidence.blockedTarget);
451
+ return {
452
+ verdict: 'denied',
453
+ reason: corroborated
454
+ ? `Local Network permission denied: multicast send refused (${evidence.multicastErrorCode}) ` +
455
+ `and ${evidence.blockedTarget} refused instantly on a directly-connected subnet`
456
+ : `Local Network permission denied: multicast send to ${WSD_MULTICAST_ADDR} refused ` +
457
+ `(${evidence.multicastErrorCode}) while loopback works`,
458
+ };
459
+ }
460
+ // An instant blocked errno toward our own subnet, without the multicast
461
+ // corroboration, is suggestive but not conclusive — say so rather than guess.
462
+ // A reject route produces exactly this shape, and it is NOT a TCC denial.
463
+ if (evidence.blockedTarget) {
464
+ return {
465
+ verdict: 'unknown',
466
+ reason: `${evidence.blockedTarget} refused instantly on a directly-connected subnet, ` +
467
+ 'but the multicast probe was not refused — inconclusive',
468
+ };
469
+ }
470
+ return {
471
+ verdict: 'unknown',
472
+ reason: evidence.silentTargets.length > 0
473
+ ? `no answer from ${evidence.silentTargets.length} local target(s) — ` +
474
+ 'the segment may simply be empty'
475
+ : 'no probeable local targets found',
476
+ };
477
+ }
478
+ /**
479
+ * The operator-facing instruction for a denied grant.
480
+ *
481
+ * Names the pane and says plainly that a human has to be at the machine, because
482
+ * the one thing that cannot be automated here is the only thing that fixes it.
483
+ */
484
+ exports.LOCAL_NETWORK_DENIED_SUGGESTION = 'Open System Settings › Privacy & Security › Local Network and turn on access for ' +
485
+ 'Trillboards. Someone has to do this at the Mac itself — the grant cannot be enabled remotely, ' +
486
+ 'and macOS only offers it to an app a person is signed in to.';
487
+ /** Same message, one line, for a log or a health beacon. */
488
+ exports.LOCAL_NETWORK_DENIED_SUMMARY = 'macOS is blocking this connector from reaching the local network ' +
489
+ '(System Settings › Privacy & Security › Local Network)';
490
+ //# sourceMappingURL=localNetworkAccess.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localNetworkAccess.js","sourceRoot":"","sources":["../src/localNetworkAccess.ts"],"names":[],"mappings":"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"}
@@ -73,6 +73,17 @@ export declare const NO_FEEDS_MESSAGE: string;
73
73
  * 24/7 log, short enough that an operator watching an install sees it.
74
74
  */
75
75
  export declare const SENSING_HEALTH_LOG_INTERVAL_MS: number;
76
+ /**
77
+ * How often a CONTINUING transport failure is restated after its first report.
78
+ *
79
+ * A TLS-inspecting proxy fails every upload on every feed, so an unthrottled
80
+ * report is 32 cameras x every cadence tick — which buries the one thing an
81
+ * operator needs to read under the noise it generates, and burns the 20 MB log
82
+ * budget doing it. The first occurrence and every CHANGE of cause are always
83
+ * reported in full; a continuing one restates itself on this interval with a
84
+ * count, so an operator who opens the log an hour later still sees it.
85
+ */
86
+ export declare const TRANSPORT_FAILURE_RESTATE_INTERVAL_MS: number;
76
87
  /**
77
88
  * The operator-facing degradation line. A machine that cannot analyze 16
78
89
  * cameras every 30 s is not a bug to hide — it is a capacity fact to state, in
@@ -80,6 +91,31 @@ export declare const SENSING_HEALTH_LOG_INTERVAL_MS: number;
80
91
  * at, how many analyses/minute this machine sustains, and where the rest went.
81
92
  */
82
93
  export declare function formatSensingHealth(health: ReturnType<CloudSensingManager['getSensingHealth']>): string;
94
+ /**
95
+ * Wire the manager's lifecycle events to the IO sink — identical for both modes
96
+ * except the per-frame "analyzed" line (cloud says `analyze →`, local says
97
+ * `local→preAnalyzed →`).
98
+ *
99
+ * The cascade's per-frame outcomes (`motionSkipped`, `admissionDenied`) are
100
+ * deliberately NOT logged per event: on a saturated 16-camera connector they
101
+ * would be tens of thousands of lines a day and would bury the events that
102
+ * need a human. They stay on the EventEmitter for embedders, and reach the
103
+ * operator as counts on the periodic capacity line below.
104
+ */
105
+ /**
106
+ * The operator-facing reporter for "I cannot reach the API, and here is why".
107
+ *
108
+ * Returns `true` from `report()` when it handled the error, so the caller can
109
+ * fall through to its ordinary per-feed line for everything else.
110
+ *
111
+ * Exported for tests: the properties worth pinning are that the FIRST failure
112
+ * is stated in full, that a CHANGE of cause is stated in full (otherwise a
113
+ * fixed trust problem followed by a proxy problem would be silent), and that a
114
+ * continuing one is throttled rather than repeated per feed per tick.
115
+ */
116
+ export declare function createTransportFailureReporter(io: SensingIo, now?: () => number): {
117
+ report(name: string, error: Error): boolean;
118
+ };
83
119
  /**
84
120
  * Build (but do NOT start) the thin cloud-sensing manager: RTSP frame → POST
85
121
  * /v2/earner/audience-analyze (cloud VLM does the inference). Returns `null`
@@ -1 +1 @@
1
- {"version":3,"file":"sensingRunMode.d.ts","sourceRoot":"","sources":["../src/sensingRunMode.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EAInB,KAAK,YAAY,EAElB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAMhD;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC/C,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,CAClB,IAAI,EAAE,YAAY,EAClB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,KAAK,KACT,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC7B;AA2CD;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB;;;;;;;;;;;;;;OAcG;IACH,gBAAgB,CAAC,IAAI;QACnB,eAAe,EAAE,MAAM,CAAC;QACxB;;;;;;WAMG;QACH,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,eAAe,CAAC,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC;KACxC,CAAC;CACH;AAED,iFAAiF;AACjF,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3B,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,qEAAqE;AACrE,eAAO,MAAM,SAAS,EAAE,SAIvB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QAEgD,CAAC;AAE9E;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,QAAgB,CAAC;AAuN5D;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,UAAU,CAAC,mBAAmB,CAAC,kBAAkB,CAAC,CAAC,GAC1D,MAAM,CA6CR;AAoDD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,eAAe,EACvB,EAAE,GAAE,SAAqB,EACzB,IAAI,CAAC,EAAE,kBAAkB,GACxB,mBAAmB,GAAG,IAAI,CAiE5B;AAqCD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,eAAe,EACvB,EAAE,GAAE,SAAqB,EACzB,IAAI,CAAC,EAAE,kBAAkB,GACxB,mBAAmB,GAAG,IAAI,CAyF5B"}
1
+ {"version":3,"file":"sensingRunMode.d.ts","sourceRoot":"","sources":["../src/sensingRunMode.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EAInB,KAAK,YAAY,EAElB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAOhD;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC/C,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,CAClB,IAAI,EAAE,YAAY,EAClB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,KAAK,KACT,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC7B;AA2CD;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB;;;;;;;;;;;;;;OAcG;IACH,gBAAgB,CAAC,IAAI;QACnB,eAAe,EAAE,MAAM,CAAC;QACxB;;;;;;WAMG;QACH,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,eAAe,CAAC,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC;KACxC,CAAC;CACH;AAED,iFAAiF;AACjF,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3B,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,qEAAqE;AACrE,eAAO,MAAM,SAAS,EAAE,SAIvB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QAEgD,CAAC;AAE9E;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,QAAgB,CAAC;AAE5D;;;;;;;;;GASG;AACH,eAAO,MAAM,qCAAqC,QAAiB,CAAC;AAuNpE;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,UAAU,CAAC,mBAAmB,CAAC,kBAAkB,CAAC,CAAC,GAC1D,MAAM,CA6CR;AAED;;;;;;;;;;GAUG;AACH;;;;;;;;;;GAUG;AACH,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,SAAS,EACb,GAAG,GAAE,MAAM,MAAiB,GAC3B;IAAE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAA;CAAE,CA+BjD;AAoED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,eAAe,EACvB,EAAE,GAAE,SAAqB,EACzB,IAAI,CAAC,EAAE,kBAAkB,GACxB,mBAAmB,GAAG,IAAI,CAiE5B;AAqCD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,eAAe,EACvB,EAAE,GAAE,SAAqB,EACzB,IAAI,CAAC,EAAE,kBAAkB,GACxB,mBAAmB,GAAG,IAAI,CAyF5B"}