@trillboards/edge-sdk 0.2.4 → 0.2.7
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 +4 -3
- package/deploy/docker/Dockerfile.cloud-sense +117 -0
- package/deploy/docker/Dockerfile.cpu +30 -21
- package/deploy/docker/Dockerfile.cuda +30 -21
- package/deploy/docker/Dockerfile.openvino +30 -20
- package/deploy/docker/README.md +9 -5
- package/deploy/docker/connector-entrypoint.sh +122 -0
- package/deploy/helm/README.md +1 -1
- package/deploy/k8s/daemonset.yaml +1 -1
- package/deploy/macos/README.md +161 -0
- package/deploy/macos/TrillboardsSetupApp.m +603 -0
- package/deploy/macos/build-macos-pkg.sh +588 -0
- package/deploy/macos/com.trillboards.edge.plist +62 -0
- package/deploy/macos/com.trillboards.litertlm.plist +45 -0
- package/deploy/macos/pair.command +519 -0
- package/deploy/macos/scripts/ensure-litertlm.sh +62 -0
- package/deploy/macos/scripts/postinstall +153 -0
- package/deploy/macos/scripts/setup-litertlm.sh +272 -0
- package/deploy/macos/test-install-pair.sh +383 -0
- package/deploy/macos/test-setup-litertlm-reinstall.sh +109 -0
- package/deploy/systemd/install.sh +25 -15
- package/deploy/systemd/trillboards-edge.service +4 -1
- package/deploy/windows/README.md +70 -0
- package/deploy/windows/build-windows.ps1 +225 -0
- package/deploy/windows/bundle-windows-installer.ps1 +153 -0
- package/deploy/windows/check-feeds.js +26 -0
- package/deploy/windows/e2e/fixtures/person.jpg +0 -0
- package/deploy/windows/e2e/test-local-sense.ps1 +185 -0
- package/deploy/windows/install-service.ps1 +6 -1
- package/deploy/windows/install-update.ps1 +101 -0
- package/deploy/windows/installer.nsi +138 -0
- package/deploy/windows/register-litertlm-task.ps1 +42 -0
- package/deploy/windows/register-task.ps1 +44 -0
- package/deploy/windows/run-connector.ps1 +69 -0
- package/deploy/windows/setup-litertlm.ps1 +361 -0
- package/deploy/windows/stop-existing.ps1 +72 -0
- package/deploy/windows/trillboards-edge-task.vbs +25 -0
- package/deploy/windows/trillboards-edge.cmd +33 -0
- package/deploy/windows/trillboards-pair.cmd +276 -0
- package/deploy/windows/trillboards-setup.ps1 +456 -0
- package/deploy/windows/trillboards-setup.vbs +13 -0
- package/dist/AudienceAnalyzeClient.d.ts +136 -0
- package/dist/AudienceAnalyzeClient.d.ts.map +1 -0
- package/dist/AudienceAnalyzeClient.js +246 -0
- package/dist/AudienceAnalyzeClient.js.map +1 -0
- package/dist/ChannelProber.d.ts +150 -0
- package/dist/ChannelProber.d.ts.map +1 -0
- package/dist/ChannelProber.js +887 -0
- package/dist/ChannelProber.js.map +1 -0
- package/dist/CloudEscalationPolicy.d.ts +143 -0
- package/dist/CloudEscalationPolicy.d.ts.map +1 -0
- package/dist/CloudEscalationPolicy.js +137 -0
- package/dist/CloudEscalationPolicy.js.map +1 -0
- package/dist/CloudSensingManager.d.ts +557 -0
- package/dist/CloudSensingManager.d.ts.map +1 -0
- package/dist/CloudSensingManager.js +1267 -0
- package/dist/CloudSensingManager.js.map +1 -0
- package/dist/DiscoveryReportClient.d.ts +66 -0
- package/dist/DiscoveryReportClient.d.ts.map +1 -0
- package/dist/DiscoveryReportClient.js +85 -0
- package/dist/DiscoveryReportClient.js.map +1 -0
- package/dist/EdgeAgent.d.ts +12 -2
- package/dist/EdgeAgent.d.ts.map +1 -1
- package/dist/EdgeAgent.js +55 -13
- package/dist/EdgeAgent.js.map +1 -1
- package/dist/LiteRtVlmProvider.d.ts +193 -0
- package/dist/LiteRtVlmProvider.d.ts.map +1 -0
- package/dist/LiteRtVlmProvider.js +436 -0
- package/dist/LiteRtVlmProvider.js.map +1 -0
- package/dist/MosaicSource.d.ts +108 -0
- package/dist/MosaicSource.d.ts.map +1 -0
- package/dist/MosaicSource.js +274 -0
- package/dist/MosaicSource.js.map +1 -0
- package/dist/OnvifClient.d.ts +83 -0
- package/dist/OnvifClient.d.ts.map +1 -0
- package/dist/OnvifClient.js +209 -0
- package/dist/OnvifClient.js.map +1 -0
- package/dist/PairClient.d.ts +106 -0
- package/dist/PairClient.d.ts.map +1 -0
- package/dist/PairClient.js +186 -0
- package/dist/PairClient.js.map +1 -0
- package/dist/RecorderAddressRecovery.d.ts +53 -0
- package/dist/RecorderAddressRecovery.d.ts.map +1 -0
- package/dist/RecorderAddressRecovery.js +359 -0
- package/dist/RecorderAddressRecovery.js.map +1 -0
- package/dist/SceneChangeDetector.d.ts +291 -0
- package/dist/SceneChangeDetector.d.ts.map +1 -0
- package/dist/SceneChangeDetector.js +682 -0
- package/dist/SceneChangeDetector.js.map +1 -0
- package/dist/SensingProfileClient.d.ts +59 -0
- package/dist/SensingProfileClient.d.ts.map +1 -0
- package/dist/SensingProfileClient.js +78 -0
- package/dist/SensingProfileClient.js.map +1 -0
- package/dist/SetupSessionClient.d.ts +114 -0
- package/dist/SetupSessionClient.d.ts.map +1 -0
- package/dist/SetupSessionClient.js +95 -0
- package/dist/SetupSessionClient.js.map +1 -0
- package/dist/VlmAdmissionGate.d.ts +126 -0
- package/dist/VlmAdmissionGate.d.ts.map +1 -0
- package/dist/VlmAdmissionGate.js +166 -0
- package/dist/VlmAdmissionGate.js.map +1 -0
- package/dist/autoSense.d.ts +266 -0
- package/dist/autoSense.d.ts.map +1 -0
- package/dist/autoSense.js +606 -0
- package/dist/autoSense.js.map +1 -0
- package/dist/cli.d.ts +27 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +526 -27
- package/dist/cli.js.map +1 -1
- package/dist/combinedSense.d.ts +128 -0
- package/dist/combinedSense.d.ts.map +1 -0
- package/dist/combinedSense.js +261 -0
- package/dist/combinedSense.js.map +1 -0
- package/dist/config.d.ts +351 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +99 -2
- package/dist/config.js.map +1 -1
- package/dist/connectorCadence.d.ts +135 -0
- package/dist/connectorCadence.d.ts.map +1 -0
- package/dist/connectorCadence.js +151 -0
- package/dist/connectorCadence.js.map +1 -0
- package/dist/dataDir.d.ts +33 -0
- package/dist/dataDir.d.ts.map +1 -0
- package/dist/dataDir.js +76 -0
- package/dist/dataDir.js.map +1 -0
- package/dist/deployedCadence.d.ts +167 -0
- package/dist/deployedCadence.d.ts.map +1 -0
- package/dist/deployedCadence.js +209 -0
- package/dist/deployedCadence.js.map +1 -0
- package/dist/deployedCadenceSource.d.ts +48 -0
- package/dist/deployedCadenceSource.d.ts.map +1 -0
- package/dist/deployedCadenceSource.js +74 -0
- package/dist/deployedCadenceSource.js.map +1 -0
- package/dist/diagnose.d.ts +1 -1
- package/dist/diagnose.d.ts.map +1 -1
- package/dist/diagnose.js +15 -13
- package/dist/diagnose.js.map +1 -1
- package/dist/discovery.d.ts +131 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +499 -0
- package/dist/discovery.js.map +1 -0
- package/dist/gemmaModelOta.d.ts +118 -0
- package/dist/gemmaModelOta.d.ts.map +1 -0
- package/dist/gemmaModelOta.js +291 -0
- package/dist/gemmaModelOta.js.map +1 -0
- package/dist/index.d.ts +16 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -1
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +25 -87
- package/dist/init.js.map +1 -1
- package/dist/keepAwake.d.ts +33 -0
- package/dist/keepAwake.d.ts.map +1 -0
- package/dist/keepAwake.js +54 -0
- package/dist/keepAwake.js.map +1 -0
- package/dist/legacyRecorderProfile.d.ts +20 -0
- package/dist/legacyRecorderProfile.d.ts.map +1 -0
- package/dist/legacyRecorderProfile.js +27 -0
- package/dist/legacyRecorderProfile.js.map +1 -0
- package/dist/localInferenceSchema.d.ts +132 -0
- package/dist/localInferenceSchema.d.ts.map +1 -0
- package/dist/localInferenceSchema.js +274 -0
- package/dist/localInferenceSchema.js.map +1 -0
- package/dist/localSenseE2eHarness.d.ts +101 -0
- package/dist/localSenseE2eHarness.d.ts.map +1 -0
- package/dist/localSenseE2eHarness.js +279 -0
- package/dist/localSenseE2eHarness.js.map +1 -0
- package/dist/localSensing.d.ts +284 -0
- package/dist/localSensing.d.ts.map +1 -0
- package/dist/localSensing.js +512 -0
- package/dist/localSensing.js.map +1 -0
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +3 -1
- package/dist/mcp-server.js.map +1 -1
- package/dist/modelIntegrity.d.ts +80 -0
- package/dist/modelIntegrity.d.ts.map +1 -0
- package/dist/modelIntegrity.js +194 -0
- package/dist/modelIntegrity.js.map +1 -0
- package/dist/pairVerify.d.ts +100 -0
- package/dist/pairVerify.d.ts.map +1 -0
- package/dist/pairVerify.js +296 -0
- package/dist/pairVerify.js.map +1 -0
- package/dist/qrScanner.d.ts +33 -0
- package/dist/qrScanner.d.ts.map +1 -0
- package/dist/qrScanner.js +103 -0
- package/dist/qrScanner.js.map +1 -0
- package/dist/runtimePaths.d.ts +10 -0
- package/dist/runtimePaths.d.ts.map +1 -0
- package/dist/runtimePaths.js +79 -0
- package/dist/runtimePaths.js.map +1 -0
- package/dist/sensingRunMode.d.ts +86 -0
- package/dist/sensingRunMode.d.ts.map +1 -0
- package/dist/sensingRunMode.js +346 -0
- package/dist/sensingRunMode.js.map +1 -0
- package/dist/setupMode.d.ts +98 -0
- package/dist/setupMode.d.ts.map +1 -0
- package/dist/setupMode.js +828 -0
- package/dist/setupMode.js.map +1 -0
- package/dist/setupProgress.d.ts +31 -0
- package/dist/setupProgress.d.ts.map +1 -0
- package/dist/setupProgress.js +173 -0
- package/dist/setupProgress.js.map +1 -0
- package/package.json +13 -4
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.isNetworkError = isNetworkError;
|
|
37
|
+
exports.classifyPairFailure = classifyPairFailure;
|
|
38
|
+
exports.readVerifiableConfig = readVerifiableConfig;
|
|
39
|
+
exports.verifyApiConnection = verifyApiConnection;
|
|
40
|
+
exports.defaultLogDir = defaultLogDir;
|
|
41
|
+
exports.appendPairLog = appendPairLog;
|
|
42
|
+
exports.runVerifyConnection = runVerifyConnection;
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const os = __importStar(require("os"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const crypto_1 = require("crypto");
|
|
47
|
+
const AudienceAnalyzeClient_1 = require("./AudienceAnalyzeClient");
|
|
48
|
+
const NETWORK_ERRNO = new Set([
|
|
49
|
+
'ENOTFOUND',
|
|
50
|
+
'EAI_AGAIN',
|
|
51
|
+
'ECONNREFUSED',
|
|
52
|
+
'ECONNRESET',
|
|
53
|
+
'ETIMEDOUT',
|
|
54
|
+
'EHOSTUNREACH',
|
|
55
|
+
'ENETUNREACH',
|
|
56
|
+
'ENETDOWN',
|
|
57
|
+
'EPIPE',
|
|
58
|
+
]);
|
|
59
|
+
/** True when an error thrown by the HTTP transport is a connectivity failure. */
|
|
60
|
+
function isNetworkError(err) {
|
|
61
|
+
const e = err;
|
|
62
|
+
if (!e)
|
|
63
|
+
return false;
|
|
64
|
+
if (e.code && NETWORK_ERRNO.has(e.code))
|
|
65
|
+
return true;
|
|
66
|
+
return /timed out|network|getaddrinfo|socket hang up/i.test(String(e.message ?? ''));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Classify a pairing failure. `thrown` is an error from the transport (the
|
|
70
|
+
* request never completed); `statusCode`/`error` come from a completed non-2xx
|
|
71
|
+
* response. The copy rules:
|
|
72
|
+
* - Only a SERVER code rejection (400/404/410) may mention the code.
|
|
73
|
+
* - Connectivity problems say the code is still valid (it was never spent).
|
|
74
|
+
*/
|
|
75
|
+
function classifyPairFailure(input) {
|
|
76
|
+
if (input.thrown !== undefined) {
|
|
77
|
+
if (isNetworkError(input.thrown)) {
|
|
78
|
+
const code = input.thrown?.code;
|
|
79
|
+
return {
|
|
80
|
+
kind: 'network',
|
|
81
|
+
message: `This computer can't reach Trillboards right now` +
|
|
82
|
+
(code ? ` (${code})` : '') +
|
|
83
|
+
`.\nCheck this machine's internet connection (Wi-Fi/ethernet, firewall, captive portal),\n` +
|
|
84
|
+
`then run pairing again. Your code was NOT used — it stays valid until it expires.`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const msg = input.thrown instanceof Error ? input.thrown.message : String(input.thrown);
|
|
88
|
+
return {
|
|
89
|
+
kind: 'server',
|
|
90
|
+
message: `Pairing hit an unexpected error: ${msg}\n` +
|
|
91
|
+
`Try again in a minute. Your code was NOT used.`,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const status = input.statusCode ?? 0;
|
|
95
|
+
if (status === 429) {
|
|
96
|
+
return {
|
|
97
|
+
kind: 'rate_limited',
|
|
98
|
+
message: `Too many pairing attempts from this network — wait a minute, then try again.\n` +
|
|
99
|
+
`Your code stays valid until it expires.`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (status === 400 || status === 404 || status === 410) {
|
|
103
|
+
return {
|
|
104
|
+
kind: 'bad_code',
|
|
105
|
+
message: `That code wasn't recognized — it may have expired (codes last about 30 minutes)\n` +
|
|
106
|
+
`or have a typo. Get a fresh code from the portal and try again.` +
|
|
107
|
+
(input.error ? `\n(Server said: ${input.error})` : ''),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
kind: 'server',
|
|
112
|
+
message: `Trillboards had a hiccup (HTTP ${status || '?'}). This is not a code problem —\n` +
|
|
113
|
+
`wait a minute and try again. Your code stays valid until it expires.` +
|
|
114
|
+
(input.error ? `\n(Server said: ${input.error})` : ''),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Extract the API base + one device token from a written config file. Accepts
|
|
119
|
+
* both shapes (multi-feed `cameras: []` and the single-camera back-compat
|
|
120
|
+
* top-level `deviceToken`), mirroring pair.command's count_feeds_missing_rtsp.
|
|
121
|
+
* Returns null when the file is missing/unreadable or holds no token.
|
|
122
|
+
*/
|
|
123
|
+
function readVerifiableConfig(configPath) {
|
|
124
|
+
let raw;
|
|
125
|
+
try {
|
|
126
|
+
raw = fs.readFileSync(configPath, 'utf8');
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
const cfg = JSON.parse(raw);
|
|
133
|
+
const apiBaseUrl = String(cfg.apiBaseUrl || 'https://api.trillboards.com');
|
|
134
|
+
const cameras = Array.isArray(cfg.cameras) ? cfg.cameras : [];
|
|
135
|
+
const withToken = cameras.find((c) => c && typeof c.deviceToken === 'string' && c.deviceToken);
|
|
136
|
+
if (withToken) {
|
|
137
|
+
return {
|
|
138
|
+
apiBaseUrl,
|
|
139
|
+
deviceToken: String(withToken.deviceToken),
|
|
140
|
+
feedName: String(withToken.name || withToken.screenId || 'camera'),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
if (typeof cfg.deviceToken === 'string' && cfg.deviceToken) {
|
|
144
|
+
return { apiBaseUrl, deviceToken: cfg.deviceToken, feedName: 'camera' };
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Prove the pairing works end-to-end: an authenticated GET of this feed's
|
|
154
|
+
* sensing profile. Same endpoint + device-auth headers as
|
|
155
|
+
* SensingProfileClient.fetchProfile (deviceRequestAuth validates the token +
|
|
156
|
+
* nonce + timestamp) — but unlike that best-effort fetch, this one DISTINGUISHES
|
|
157
|
+
* failure classes, because the whole point is telling the operator the truth.
|
|
158
|
+
*/
|
|
159
|
+
async function verifyApiConnection(config, poster = AudienceAnalyzeClient_1.defaultHttpPoster) {
|
|
160
|
+
const base = config.apiBaseUrl.replace(/\/+$/, '');
|
|
161
|
+
const endpoint = `${base}/v2/earner/cameras/sensing-profile`;
|
|
162
|
+
const headers = {
|
|
163
|
+
Accept: 'application/json',
|
|
164
|
+
'X-Device-Token': config.deviceToken,
|
|
165
|
+
'X-Trillboard-Device-Token': config.deviceToken,
|
|
166
|
+
'X-Device-Timestamp': String(Date.now()),
|
|
167
|
+
'X-Device-Nonce': (0, crypto_1.randomUUID)(),
|
|
168
|
+
};
|
|
169
|
+
let result;
|
|
170
|
+
try {
|
|
171
|
+
result = await poster(endpoint, { method: 'GET', headers, timeoutMs: 15000 }, '');
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
const code = err?.code;
|
|
175
|
+
return {
|
|
176
|
+
ok: false,
|
|
177
|
+
kind: 'network',
|
|
178
|
+
message: `Paired and saved, but this computer can't reach Trillboards right now` +
|
|
179
|
+
(code ? ` (${code})` : '') +
|
|
180
|
+
`.\nYour pairing is SAVED — fix this machine's internet connection and run the\n` +
|
|
181
|
+
`pairing helper again. You will NOT need a new code.`,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
if (result.statusCode >= 200 && result.statusCode < 300) {
|
|
185
|
+
return { ok: true, kind: 'verified', message: '', statusCode: result.statusCode };
|
|
186
|
+
}
|
|
187
|
+
if (result.statusCode === 401 || result.statusCode === 403) {
|
|
188
|
+
return {
|
|
189
|
+
ok: false,
|
|
190
|
+
kind: 'auth',
|
|
191
|
+
statusCode: result.statusCode,
|
|
192
|
+
message: `Trillboards rejected this machine's saved pairing (HTTP ${result.statusCode}).\n` +
|
|
193
|
+
`The pairing may have been revoked. Generate a fresh code in the portal and pair again.`,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
ok: false,
|
|
198
|
+
kind: 'server',
|
|
199
|
+
statusCode: result.statusCode,
|
|
200
|
+
message: `Paired and saved, but the connection check got HTTP ${result.statusCode} from Trillboards.\n` +
|
|
201
|
+
`Your pairing is SAVED — wait a minute and run the pairing helper again.`,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
// ─── 3. Rolling pairing log ──────────────────────────────────────────────────
|
|
205
|
+
/** Rotate at 512 KB, keep one previous generation — enough for diagnostics. */
|
|
206
|
+
const LOG_MAX_BYTES = 512 * 1024;
|
|
207
|
+
const LOG_FILE = 'pairing.log';
|
|
208
|
+
/**
|
|
209
|
+
* Platform log dir, matching where the installers already put logs:
|
|
210
|
+
* macOS ~/Library/Logs/Trillboards (postinstall creates it)
|
|
211
|
+
* Windows %LOCALAPPDATA%\Trillboards\logs
|
|
212
|
+
* other ~/.trillboards/logs (Docker/systemd installs)
|
|
213
|
+
* Injectable platform/env for tests.
|
|
214
|
+
*/
|
|
215
|
+
function defaultLogDir(platform = process.platform, env = process.env, homedir = os.homedir()) {
|
|
216
|
+
if (platform === 'darwin')
|
|
217
|
+
return path.join(homedir, 'Library', 'Logs', 'Trillboards');
|
|
218
|
+
if (platform === 'win32') {
|
|
219
|
+
const localAppData = env.LOCALAPPDATA || path.join(homedir, 'AppData', 'Local');
|
|
220
|
+
return path.join(localAppData, 'Trillboards', 'logs');
|
|
221
|
+
}
|
|
222
|
+
return path.join(homedir, '.trillboards', 'logs');
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Append timestamped lines to the rolling pairing log. Fully best-effort: a
|
|
226
|
+
* logging failure must never fail pairing. Returns the log file path (for the
|
|
227
|
+
* "details saved to …" hint) or null when the write failed.
|
|
228
|
+
* NEVER pass claim codes or device tokens in `lines`.
|
|
229
|
+
*/
|
|
230
|
+
function appendPairLog(logDir, lines) {
|
|
231
|
+
try {
|
|
232
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
233
|
+
const file = path.join(logDir, LOG_FILE);
|
|
234
|
+
try {
|
|
235
|
+
const st = fs.statSync(file);
|
|
236
|
+
if (st.size > LOG_MAX_BYTES)
|
|
237
|
+
fs.renameSync(file, `${file}.1`);
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
/* first write */
|
|
241
|
+
}
|
|
242
|
+
const stamp = new Date().toISOString();
|
|
243
|
+
const text = (Array.isArray(lines) ? lines : [lines])
|
|
244
|
+
.map((l) => `[${stamp}] ${l}`)
|
|
245
|
+
.join('\n');
|
|
246
|
+
fs.appendFileSync(file, text + '\n');
|
|
247
|
+
return file;
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// ─── CLI entry: `trillboards-edge verify-connection` ─────────────────────────
|
|
254
|
+
/**
|
|
255
|
+
* Exit-code contract (the install wrappers branch on these — keep stable):
|
|
256
|
+
* 0 verified — config present, API reachable, token accepted
|
|
257
|
+
* 2 network — config present but Trillboards is unreachable from here
|
|
258
|
+
* 3 auth — API reachable but the saved pairing was rejected
|
|
259
|
+
* 4 no usable config (missing file / no device token)
|
|
260
|
+
* 5 server — API responded with an unexpected status
|
|
261
|
+
*/
|
|
262
|
+
async function runVerifyConnection(args) {
|
|
263
|
+
const cfgIdx = args.indexOf('--config');
|
|
264
|
+
const configPath = cfgIdx >= 0 && args[cfgIdx + 1] ? args[cfgIdx + 1] : 'trillboards.config.json';
|
|
265
|
+
const asJson = args.includes('--json');
|
|
266
|
+
const resolved = path.resolve(configPath);
|
|
267
|
+
const cfg = readVerifiableConfig(resolved);
|
|
268
|
+
if (!cfg) {
|
|
269
|
+
if (asJson)
|
|
270
|
+
console.log(JSON.stringify({ ok: false, kind: 'no_config' }));
|
|
271
|
+
else
|
|
272
|
+
console.error(`No paired config with a device token at: ${resolved}`);
|
|
273
|
+
process.exit(4);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const res = await verifyApiConnection(cfg);
|
|
277
|
+
appendPairLog(defaultLogDir(), `verify-connection: ${res.kind}${res.statusCode ? ` (HTTP ${res.statusCode})` : ''}`);
|
|
278
|
+
if (asJson) {
|
|
279
|
+
console.log(JSON.stringify({ ok: res.ok, kind: res.kind, statusCode: res.statusCode ?? null }));
|
|
280
|
+
}
|
|
281
|
+
else if (res.ok) {
|
|
282
|
+
console.log(`Connected to Trillboards — pairing for "${cfg.feedName}" is valid.`);
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
console.error(res.message);
|
|
286
|
+
}
|
|
287
|
+
const exitByKind = {
|
|
288
|
+
verified: 0,
|
|
289
|
+
network: 2,
|
|
290
|
+
auth: 3,
|
|
291
|
+
server: 5,
|
|
292
|
+
no_config: 4,
|
|
293
|
+
};
|
|
294
|
+
process.exit(exitByKind[res.kind]);
|
|
295
|
+
}
|
|
296
|
+
//# sourceMappingURL=pairVerify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pairVerify.js","sourceRoot":"","sources":["../src/pairVerify.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDA,wCAKC;AASD,kDAmDC;AA8BD,oDA0BC;AASD,kDAmDC;AAeD,sCAWC;AAQD,sCAmBC;AAYD,kDAgCC;AA1UD,uCAAyB;AACzB,uCAAyB;AACzB,2CAA6B;AAC7B,mCAAoC;AACpC,mEAA6E;AAmC7E,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IAC5B,WAAW;IACX,WAAW;IACX,cAAc;IACd,YAAY;IACZ,WAAW;IACX,cAAc;IACd,aAAa;IACb,UAAU;IACV,OAAO;CACR,CAAC,CAAC;AAEH,iFAAiF;AACjF,SAAgB,cAAc,CAAC,GAAY;IACzC,MAAM,CAAC,GAAG,GAAwE,CAAC;IACnF,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACrB,IAAI,CAAC,CAAC,IAAI,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACrD,OAAO,+CAA+C,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC;AACvF,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,mBAAmB,CAAC,KAInC;IACC,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC/B,IAAI,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,GAAI,KAAK,CAAC,MAAgC,EAAE,IAAI,CAAC;YAC3D,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,OAAO,EACL,iDAAiD;oBACjD,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC1B,2FAA2F;oBAC3F,mFAAmF;aACtF,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACxF,OAAO;YACL,IAAI,EAAE,QAAQ;YACd,OAAO,EACL,oCAAoC,GAAG,IAAI;gBAC3C,gDAAgD;SACnD,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC;IACrC,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;QACnB,OAAO;YACL,IAAI,EAAE,cAAc;YACpB,OAAO,EACL,gFAAgF;gBAChF,yCAAyC;SAC5C,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;QACvD,OAAO;YACL,IAAI,EAAE,UAAU;YAChB,OAAO,EACL,mFAAmF;gBACnF,iEAAiE;gBACjE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,mBAAmB,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;SACzD,CAAC;IACJ,CAAC;IACD,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,OAAO,EACL,kCAAkC,MAAM,IAAI,GAAG,mCAAmC;YAClF,sEAAsE;YACtE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,mBAAmB,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;KACzD,CAAC;AACJ,CAAC;AAwBD;;;;;GAKG;AACH,SAAgB,oBAAoB,CAAC,UAAkB;IACrD,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4B,CAAC;QACvD,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,IAAI,6BAA6B,CAAC,CAAC;QAC3E,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,OAA0C,CAAC,CAAC,CAAC,EAAE,CAAC;QAClG,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,IAAI,CAAC,CAAC,WAAW,CAAC,CAAC;QAC/F,IAAI,SAAS,EAAE,CAAC;YACd,OAAO;gBACL,UAAU;gBACV,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC;gBAC1C,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,IAAI,IAAI,SAAS,CAAC,QAAQ,IAAI,QAAQ,CAAC;aACnE,CAAC;QACJ,CAAC;QACD,IAAI,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;YAC3D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;QAC1E,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,mBAAmB,CACvC,MAAwB,EACxB,SAAqB,yCAAiB;IAEtC,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,GAAG,IAAI,oCAAoC,CAAC;IAC7D,MAAM,OAAO,GAA2B;QACtC,MAAM,EAAE,kBAAkB;QAC1B,gBAAgB,EAAE,MAAM,CAAC,WAAW;QACpC,2BAA2B,EAAE,MAAM,CAAC,WAAW;QAC/C,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACxC,gBAAgB,EAAE,IAAA,mBAAU,GAAE;KAC/B,CAAC;IAEF,IAAI,MAA4C,CAAC;IACjD,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,KAAM,EAAE,EAAE,EAAE,CAAC,CAAC;IACrF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,GAAI,GAA6B,EAAE,IAAI,CAAC;QAClD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,IAAI,EAAE,SAAS;YACf,OAAO,EACL,uEAAuE;gBACvE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1B,iFAAiF;gBACjF,qDAAqD;SACxD,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,UAAU,IAAI,GAAG,IAAI,MAAM,CAAC,UAAU,GAAG,GAAG,EAAE,CAAC;QACxD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;IACpF,CAAC;IACD,IAAI,MAAM,CAAC,UAAU,KAAK,GAAG,IAAI,MAAM,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;QAC3D,OAAO;YACL,EAAE,EAAE,KAAK;YACT,IAAI,EAAE,MAAM;YACZ,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,OAAO,EACL,2DAA2D,MAAM,CAAC,UAAU,MAAM;gBAClF,wFAAwF;SAC3F,CAAC;IACJ,CAAC;IACD,OAAO;QACL,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,OAAO,EACL,uDAAuD,MAAM,CAAC,UAAU,sBAAsB;YAC9F,yEAAyE;KAC5E,CAAC;AACJ,CAAC;AAED,gFAAgF;AAEhF,+EAA+E;AAC/E,MAAM,aAAa,GAAG,GAAG,GAAG,IAAI,CAAC;AACjC,MAAM,QAAQ,GAAG,aAAa,CAAC;AAE/B;;;;;;GAMG;AACH,SAAgB,aAAa,CAC3B,WAA4B,OAAO,CAAC,QAAQ,EAC5C,MAAyB,OAAO,CAAC,GAAG,EACpC,UAAkB,EAAE,CAAC,OAAO,EAAE;IAE9B,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;IACvF,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,MAAM,YAAY,GAAG,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QAChF,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC;AACpD,CAAC;AAED;;;;;GAKG;AACH,SAAgB,aAAa,CAAC,MAAc,EAAE,KAAwB;IACpE,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACzC,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC7B,IAAI,EAAE,CAAC,IAAI,GAAG,aAAa;gBAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC;QAChE,CAAC;QAAC,MAAM,CAAC;YACP,iBAAiB;QACnB,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;aAClD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;aAC7B,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,gFAAgF;AAEhF;;;;;;;GAOG;AACI,KAAK,UAAU,mBAAmB,CAAC,IAAc;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACxC,MAAM,UAAU,GACd,MAAM,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAC;IACjF,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAE1C,MAAM,GAAG,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,IAAI,MAAM;YAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;;YACrE,OAAO,CAAC,KAAK,CAAC,4CAA4C,QAAQ,EAAE,CAAC,CAAC;QAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChB,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,mBAAmB,CAAC,GAAG,CAAC,CAAC;IAC3C,aAAa,CAAC,aAAa,EAAE,EAAE,sBAAsB,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACrH,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;IAClG,CAAC;SAAM,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,2CAA2C,GAAG,CAAC,QAAQ,aAAa,CAAC,CAAC;IACpF,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IACD,MAAM,UAAU,GAA+B;QAC7C,QAAQ,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;QACV,IAAI,EAAE,CAAC;QACP,MAAM,EAAE,CAAC;QACT,SAAS,EAAE,CAAC;KACb,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* qrScanner — decode a Trillboards claim code from a QR image so the connector's
|
|
3
|
+
* `pair` flow can be driven by SCANNING the portal's Install-step QR instead of
|
|
4
|
+
* hand-typing the code. The portal renders that QR via `<QrCodeDisplay
|
|
5
|
+
* value={claimCode} />`, so the QR payload IS the raw claim code — we return it
|
|
6
|
+
* verbatim and let PairClient.normalizeClaimCode canonicalize it.
|
|
7
|
+
*
|
|
8
|
+
* Pure-JS and only reached via cli.ts's lazy `require('./qrScanner')` inside the
|
|
9
|
+
* `pair --qr` branch, so the common `pair --code` entrypoint (the macOS/edge
|
|
10
|
+
* "cloud-sense" installer surface) never pulls in the image-decode deps. Supports
|
|
11
|
+
* PNG (a screenshot / "save image" of the portal QR) and JPEG (a phone photo).
|
|
12
|
+
*/
|
|
13
|
+
export interface DecodedImage {
|
|
14
|
+
/** RGBA pixels, 4 bytes per pixel. */
|
|
15
|
+
data: Uint8ClampedArray;
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Decode a PNG or JPEG buffer to RGBA pixels, or null for an unsupported format
|
|
21
|
+
* (sniffed by magic bytes, not file extension, so a mislabeled file still works).
|
|
22
|
+
*/
|
|
23
|
+
export declare function decodeImageToRgba(buf: Buffer): DecodedImage | null;
|
|
24
|
+
/** Decode the QR payload from an image buffer, or null if unsupported / no QR found. */
|
|
25
|
+
export declare function decodeQrFromImageBuffer(buf: Buffer): string | null;
|
|
26
|
+
/**
|
|
27
|
+
* Read an image file (a PNG/JPEG screenshot or photo of the portal's claim-code
|
|
28
|
+
* QR) and return the embedded claim code. Throws a clear, owner-facing error for
|
|
29
|
+
* a missing file, an unsupported format, or an image with no QR — so the CLI can
|
|
30
|
+
* print actionable guidance instead of a stack trace.
|
|
31
|
+
*/
|
|
32
|
+
export declare function decodeClaimCodeFromImageFile(filePath: string): Promise<string>;
|
|
33
|
+
//# sourceMappingURL=qrScanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qrScanner.d.ts","sourceRoot":"","sources":["../src/qrScanner.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,YAAY;IAC3B,sCAAsC;IACtC,IAAI,EAAE,iBAAiB,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAaD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAUlE;AAED,wFAAwF;AACxF,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKlE;AAED;;;;;GAKG;AACH,wBAAsB,4BAA4B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAepF"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.decodeImageToRgba = decodeImageToRgba;
|
|
40
|
+
exports.decodeQrFromImageBuffer = decodeQrFromImageBuffer;
|
|
41
|
+
exports.decodeClaimCodeFromImageFile = decodeClaimCodeFromImageFile;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const jsqr_1 = __importDefault(require("jsqr"));
|
|
44
|
+
const pngjs_1 = require("pngjs");
|
|
45
|
+
const jpeg = __importStar(require("jpeg-js"));
|
|
46
|
+
const PNG_MAGIC = [0x89, 0x50, 0x4e, 0x47]; // "\x89PNG"
|
|
47
|
+
const JPEG_MAGIC = [0xff, 0xd8, 0xff];
|
|
48
|
+
function startsWith(buf, sig) {
|
|
49
|
+
if (buf.length < sig.length)
|
|
50
|
+
return false;
|
|
51
|
+
for (let i = 0; i < sig.length; i += 1) {
|
|
52
|
+
if (buf[i] !== sig[i])
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Decode a PNG or JPEG buffer to RGBA pixels, or null for an unsupported format
|
|
59
|
+
* (sniffed by magic bytes, not file extension, so a mislabeled file still works).
|
|
60
|
+
*/
|
|
61
|
+
function decodeImageToRgba(buf) {
|
|
62
|
+
if (startsWith(buf, PNG_MAGIC)) {
|
|
63
|
+
const png = pngjs_1.PNG.sync.read(buf); // always RGBA
|
|
64
|
+
return { data: new Uint8ClampedArray(png.data), width: png.width, height: png.height };
|
|
65
|
+
}
|
|
66
|
+
if (startsWith(buf, JPEG_MAGIC)) {
|
|
67
|
+
const img = jpeg.decode(buf, { useTArray: true, formatAsRGBA: true, maxMemoryUsageInMB: 512 });
|
|
68
|
+
return { data: new Uint8ClampedArray(img.data), width: img.width, height: img.height };
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
/** Decode the QR payload from an image buffer, or null if unsupported / no QR found. */
|
|
73
|
+
function decodeQrFromImageBuffer(buf) {
|
|
74
|
+
const img = decodeImageToRgba(buf);
|
|
75
|
+
if (!img)
|
|
76
|
+
return null;
|
|
77
|
+
const result = (0, jsqr_1.default)(img.data, img.width, img.height);
|
|
78
|
+
return result && typeof result.data === 'string' ? result.data : null;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Read an image file (a PNG/JPEG screenshot or photo of the portal's claim-code
|
|
82
|
+
* QR) and return the embedded claim code. Throws a clear, owner-facing error for
|
|
83
|
+
* a missing file, an unsupported format, or an image with no QR — so the CLI can
|
|
84
|
+
* print actionable guidance instead of a stack trace.
|
|
85
|
+
*/
|
|
86
|
+
async function decodeClaimCodeFromImageFile(filePath) {
|
|
87
|
+
let buf;
|
|
88
|
+
try {
|
|
89
|
+
buf = await fs.promises.readFile(filePath);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
throw new Error(`could not read image file: ${filePath}`);
|
|
93
|
+
}
|
|
94
|
+
if (!decodeImageToRgba(buf)) {
|
|
95
|
+
throw new Error(`unsupported image format (save the QR as a PNG or JPEG): ${filePath}`);
|
|
96
|
+
}
|
|
97
|
+
const code = decodeQrFromImageBuffer(buf);
|
|
98
|
+
if (!code || !code.trim()) {
|
|
99
|
+
throw new Error(`no QR code found in image: ${filePath}`);
|
|
100
|
+
}
|
|
101
|
+
return code.trim();
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=qrScanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qrScanner.js","sourceRoot":"","sources":["../src/qrScanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the FFmpeg binary for connector run modes.
|
|
3
|
+
*
|
|
4
|
+
* macOS LaunchAgents and Windows scheduled tasks can start with a minimal PATH,
|
|
5
|
+
* so the packaged connector should prefer the FFmpeg shipped beside its bundled
|
|
6
|
+
* Node runtime. Operators can still override with an explicit config/CLI path
|
|
7
|
+
* or TRILLBOARDS_FFMPEG.
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveFfmpegBinaryPath(...configuredPaths: Array<string | null | undefined>): string;
|
|
10
|
+
//# sourceMappingURL=runtimePaths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtimePaths.d.ts","sourceRoot":"","sources":["../src/runtimePaths.ts"],"names":[],"mappings":"AAgBA;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,eAAe,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GACnD,MAAM,CAmBR"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.resolveFfmpegBinaryPath = resolveFfmpegBinaryPath;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const FFMPEG_BINARY = process.platform === 'win32' ? 'ffmpeg.exe' : 'ffmpeg';
|
|
40
|
+
function firstExistingFile(paths) {
|
|
41
|
+
for (const candidate of new Set(paths)) {
|
|
42
|
+
try {
|
|
43
|
+
if (fs.statSync(candidate).isFile())
|
|
44
|
+
return candidate;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// keep looking
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Resolve the FFmpeg binary for connector run modes.
|
|
54
|
+
*
|
|
55
|
+
* macOS LaunchAgents and Windows scheduled tasks can start with a minimal PATH,
|
|
56
|
+
* so the packaged connector should prefer the FFmpeg shipped beside its bundled
|
|
57
|
+
* Node runtime. Operators can still override with an explicit config/CLI path
|
|
58
|
+
* or TRILLBOARDS_FFMPEG.
|
|
59
|
+
*/
|
|
60
|
+
function resolveFfmpegBinaryPath(...configuredPaths) {
|
|
61
|
+
for (const configuredPath of configuredPaths) {
|
|
62
|
+
const trimmed = configuredPath?.trim();
|
|
63
|
+
if (trimmed)
|
|
64
|
+
return trimmed;
|
|
65
|
+
}
|
|
66
|
+
const envPath = process.env.TRILLBOARDS_FFMPEG?.trim();
|
|
67
|
+
if (envPath)
|
|
68
|
+
return envPath;
|
|
69
|
+
const bundled = firstExistingFile([
|
|
70
|
+
// Installed connector: edge/bin/node and edge/bin/ffmpeg are siblings.
|
|
71
|
+
path.join(path.dirname(process.execPath), FFMPEG_BINARY),
|
|
72
|
+
// dist/runtimePaths.js in the packaged connector: edge/lib/edge-sdk/dist.
|
|
73
|
+
path.resolve(__dirname, '../../../bin', FFMPEG_BINARY),
|
|
74
|
+
// In-package fallback for future layouts: edge-sdk/dist next to edge-sdk/bin.
|
|
75
|
+
path.resolve(__dirname, '../bin', FFMPEG_BINARY),
|
|
76
|
+
]);
|
|
77
|
+
return bundled || FFMPEG_BINARY;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=runtimePaths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtimePaths.js","sourceRoot":"","sources":["../src/runtimePaths.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwBA,0DAqBC;AA7CD,uCAAyB;AACzB,2CAA6B;AAE7B,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC;AAE7E,SAAS,iBAAiB,CAAC,KAAe;IACxC,KAAK,MAAM,SAAS,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QACvC,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE;gBAAE,OAAO,SAAS,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,eAAe;QACjB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,uBAAuB,CACrC,GAAG,eAAiD;IAEpD,KAAK,MAAM,cAAc,IAAI,eAAe,EAAE,CAAC;QAC7C,MAAM,OAAO,GAAG,cAAc,EAAE,IAAI,EAAE,CAAC;QACvC,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC;IAC9B,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,CAAC;IACvD,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAE5B,MAAM,OAAO,GAAG,iBAAiB,CAAC;QAChC,uEAAuE;QACvE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,aAAa,CAAC;QACxD,0EAA0E;QAC1E,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,cAAc,EAAE,aAAa,CAAC;QACtD,8EAA8E;QAC9E,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,aAAa,CAAC;KACjD,CAAC,CAAC;IAEH,OAAO,OAAO,IAAI,aAAa,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { CloudSensingManager, type ResolvedFeed } from './CloudSensingManager';
|
|
2
|
+
import type { SharedFrameSource } from './MosaicSource';
|
|
3
|
+
import type { EdgeAgentConfig } from './config';
|
|
4
|
+
/**
|
|
5
|
+
* Optional cross-rail mosaic-pull sharing: the combined `sense` entrypoint passes
|
|
6
|
+
* a `sharedSources` registry so the VLM rail attaches to the SAME SharedFrameSource
|
|
7
|
+
* the on-device ONNX zoo rail uses — one RTSP pull per mosaic source feeds both.
|
|
8
|
+
*/
|
|
9
|
+
export interface SensingManagerOpts {
|
|
10
|
+
sharedSources?: Map<string, SharedFrameSource>;
|
|
11
|
+
/** Persist DHCP-recovered recorder addresses back to this local config. */
|
|
12
|
+
configPath?: string;
|
|
13
|
+
/** Reuse a caller-owned recovery coordinator across shared sensing rails. */
|
|
14
|
+
streamUrlResolver?: (feed: ResolvedFeed, currentUrl: string, error: Error) => Promise<string | null>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The lifecycle surface the auto-sense supervisor drives. `CloudSensingManager`
|
|
18
|
+
* already satisfies it: `start()` opens cameras + runs the capture loops;
|
|
19
|
+
* `stop()` clears the loop timers + closes cameras (a clean teardown that a
|
|
20
|
+
* later `start()` resumes from). Narrowed to just these two so the supervisor
|
|
21
|
+
* can hold either a real manager or a test fake.
|
|
22
|
+
*/
|
|
23
|
+
export interface SensingManager {
|
|
24
|
+
start(): Promise<void>;
|
|
25
|
+
stop(): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* How many frames the ON-DEVICE runtime has produced a result for so far this
|
|
28
|
+
* run (`start()` resets the count). NOT the total analysis count: a frame the
|
|
29
|
+
* local provider threw on and the cloud answered — `cloudFallbackOnError`, or
|
|
30
|
+
* an escalation — is an analysis but proves nothing about the local runtime.
|
|
31
|
+
*
|
|
32
|
+
* OPTIONAL, and structurally satisfied by `CloudSensingManager` already — no
|
|
33
|
+
* manager code changes to supply it. The auto-sense supervisor reads it for
|
|
34
|
+
* one reason: `litert-lm serve` is `http.server.HTTPServer`, the SERIAL one,
|
|
35
|
+
* so while WE are generating it cannot answer its own readiness endpoint
|
|
36
|
+
* either. A probe that goes unanswered in that window says nothing about the
|
|
37
|
+
* model — but an on-device inference that COMPLETED proves it is alive, which
|
|
38
|
+
* is the evidence the supervisor actually needs. See
|
|
39
|
+
* `AutoSenseSupervisor.recheck`.
|
|
40
|
+
*/
|
|
41
|
+
getSensingHealth?(): {
|
|
42
|
+
localInferences: number;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** A console-shaped sink so callers can capture/redirect the build-time logs. */
|
|
46
|
+
export interface SensingIo {
|
|
47
|
+
log: (msg: string) => void;
|
|
48
|
+
warn: (msg: string) => void;
|
|
49
|
+
error: (msg: string) => void;
|
|
50
|
+
}
|
|
51
|
+
/** Default sink: the real console (what the CLI entrypoints use). */
|
|
52
|
+
export declare const consoleIo: SensingIo;
|
|
53
|
+
/**
|
|
54
|
+
* The error logged (and `null` returned) when a build is attempted with no
|
|
55
|
+
* camera feeds configured. Exported so the supervisor + CLI surface the SAME
|
|
56
|
+
* message and so tests can assert on it.
|
|
57
|
+
*/
|
|
58
|
+
export declare const NO_FEEDS_MESSAGE: string;
|
|
59
|
+
/**
|
|
60
|
+
* How often the connector prints the one line that answers "why is my
|
|
61
|
+
* 16-camera store only sampling every N seconds?". Long enough not to spam a
|
|
62
|
+
* 24/7 log, short enough that an operator watching an install sees it.
|
|
63
|
+
*/
|
|
64
|
+
export declare const SENSING_HEALTH_LOG_INTERVAL_MS: number;
|
|
65
|
+
/**
|
|
66
|
+
* The operator-facing degradation line. A machine that cannot analyze 16
|
|
67
|
+
* cameras every 30 s is not a bug to hide — it is a capacity fact to state, in
|
|
68
|
+
* the terms an operator can act on: how often each camera is actually looked
|
|
69
|
+
* at, how many analyses/minute this machine sustains, and where the rest went.
|
|
70
|
+
*/
|
|
71
|
+
export declare function formatSensingHealth(health: ReturnType<CloudSensingManager['getSensingHealth']>): string;
|
|
72
|
+
/**
|
|
73
|
+
* Build (but do NOT start) the thin cloud-sensing manager: RTSP frame → POST
|
|
74
|
+
* /v2/earner/audience-analyze (cloud VLM does the inference). Returns `null`
|
|
75
|
+
* after logging NO_FEEDS_MESSAGE when no feeds are configured — the caller
|
|
76
|
+
* decides how to surface that (the CLI + the supervisor both exit 1).
|
|
77
|
+
*/
|
|
78
|
+
export declare function buildCloudSensingManager(config: EdgeAgentConfig, io?: SensingIo, opts?: SensingManagerOpts): CloudSensingManager | null;
|
|
79
|
+
/**
|
|
80
|
+
* Build (but do NOT start) the on-device LOCAL-sensing manager: RTSP frame →
|
|
81
|
+
* LOCAL VLM (LiteRT-LM serving Gemma) → POST the STRUCTURED result as
|
|
82
|
+
* `preAnalyzed` (skips the cloud VLM → no Vertex cost). Returns `null` after
|
|
83
|
+
* logging NO_FEEDS_MESSAGE when no feeds are configured.
|
|
84
|
+
*/
|
|
85
|
+
export declare function buildLocalSensingManager(config: EdgeAgentConfig, io?: SensingIo, opts?: SensingManagerOpts): CloudSensingManager | null;
|
|
86
|
+
//# sourceMappingURL=sensingRunMode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sensingRunMode.d.ts","sourceRoot":"","sources":["../src/sensingRunMode.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EAInB,KAAK,YAAY,EAClB,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;QAAE,eAAe,EAAE,MAAM,CAAA;KAAE,CAAC;CAClD;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;AA4C5D;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,UAAU,CAAC,mBAAmB,CAAC,kBAAkB,CAAC,CAAC,GAC1D,MAAM,CAqBR;AAoDD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,eAAe,EACvB,EAAE,GAAE,SAAqB,EACzB,IAAI,CAAC,EAAE,kBAAkB,GACxB,mBAAmB,GAAG,IAAI,CA6D5B;AAqCD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,eAAe,EACvB,EAAE,GAAE,SAAqB,EACzB,IAAI,CAAC,EAAE,kBAAkB,GACxB,mBAAmB,GAAG,IAAI,CAmF5B"}
|