@trillboards/edge-sdk 0.2.24 → 0.2.26
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/deploy/windows/build-windows.ps1 +1 -0
- package/deploy/windows/ci/verify-update-applier.ps1 +168 -27
- package/deploy/windows/enroll-connector.ps1 +169 -0
- package/deploy/windows/installer.nsi +102 -6
- package/deploy/windows/run-connector.ps1 +30 -0
- package/dist/ChannelProber.d.ts +37 -1
- package/dist/ChannelProber.d.ts.map +1 -1
- package/dist/ChannelProber.js +113 -5
- package/dist/ChannelProber.js.map +1 -1
- package/dist/ConnectorCameraClient.d.ts +79 -0
- package/dist/ConnectorCameraClient.d.ts.map +1 -0
- package/dist/ConnectorCameraClient.js +114 -0
- package/dist/ConnectorCameraClient.js.map +1 -0
- package/dist/EdgeAgent.js +1 -1
- package/dist/EnrollClient.d.ts +81 -0
- package/dist/EnrollClient.d.ts.map +1 -0
- package/dist/EnrollClient.js +97 -0
- package/dist/EnrollClient.js.map +1 -0
- package/dist/SetupSessionClient.d.ts +2 -0
- package/dist/SetupSessionClient.d.ts.map +1 -1
- package/dist/SetupSessionClient.js.map +1 -1
- package/dist/cli.d.ts +49 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +332 -0
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +15 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -0
- package/dist/config.js.map +1 -1
- package/dist/diagnose.d.ts +1 -1
- package/dist/diagnose.js +1 -1
- package/dist/setupMode.d.ts.map +1 -1
- package/dist/setupMode.js +1 -0
- package/dist/setupMode.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { type HttpPoster } from './AudienceAnalyzeClient';
|
|
2
|
+
import type { CameraFeedConfig } from './config';
|
|
3
|
+
import type { DiscoveredCamera } from './discovery';
|
|
4
|
+
/**
|
|
5
|
+
* ConnectorCameraClient — registers the feeds this machine found, using THIS
|
|
6
|
+
* machine's own connector credential, and turns the answer into `cameras[]`.
|
|
7
|
+
*
|
|
8
|
+
* This is the consumer of `connector.key` and the producer for
|
|
9
|
+
* `POST /v2/earner/connectors/cameras`. Without it the unattended path stops one
|
|
10
|
+
* step short of useful: the machine has an identity, and no feeds, and no device
|
|
11
|
+
* tokens — so `auto-sense` finds no `cameras[]` and exits through its no-feeds
|
|
12
|
+
* path while the installer reports success. A human would still have to run the
|
|
13
|
+
* interactive camera setup, which is the exact step this whole feature removes.
|
|
14
|
+
*
|
|
15
|
+
* WHAT IT SENDS, AND WHAT IT DOES NOT. The body carries only a stable
|
|
16
|
+
* `cameraKey` per feed plus a display name — never the RTSP URL and never the
|
|
17
|
+
* recorder credentials. Those stay on this machine: the server mints one screen
|
|
18
|
+
* + device token per `cameraKey`, and the URLs are matched back to the returned
|
|
19
|
+
* tokens locally, below. That preserves the property the interactive setup
|
|
20
|
+
* already has and is worth selling — the connection details never leave the
|
|
21
|
+
* venue on this path.
|
|
22
|
+
*
|
|
23
|
+
* The owner is NOT in the body. It comes from the credential server-side.
|
|
24
|
+
*/
|
|
25
|
+
export interface ConnectorCameraClientOptions {
|
|
26
|
+
apiBaseUrl: string;
|
|
27
|
+
/** This machine's connector credential (`connector.key`). */
|
|
28
|
+
connectorKey: string;
|
|
29
|
+
timeoutMs?: number;
|
|
30
|
+
}
|
|
31
|
+
/** One feed as the server needs to see it — no URL, no credentials. */
|
|
32
|
+
export interface RegisterCameraInput {
|
|
33
|
+
cameraKey: string;
|
|
34
|
+
name?: string;
|
|
35
|
+
brand?: string;
|
|
36
|
+
latitude?: number;
|
|
37
|
+
longitude?: number;
|
|
38
|
+
}
|
|
39
|
+
export interface RegisteredCamera {
|
|
40
|
+
screenId: string;
|
|
41
|
+
deviceId: string;
|
|
42
|
+
deviceToken: string;
|
|
43
|
+
cameraKey: string;
|
|
44
|
+
name: string;
|
|
45
|
+
isReRegistration?: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface RegisterResult {
|
|
48
|
+
ok: boolean;
|
|
49
|
+
cameras?: RegisteredCamera[];
|
|
50
|
+
error?: string;
|
|
51
|
+
/** Same taxonomy as EnrollClient — see there for why it matters. */
|
|
52
|
+
kind?: 'auth' | 'network' | 'server' | 'invalid';
|
|
53
|
+
}
|
|
54
|
+
/** The server caps a single registration call; mirrors MAX_CAMERAS_PER_CALL. */
|
|
55
|
+
export declare const MAX_CAMERAS_PER_CALL = 64;
|
|
56
|
+
export declare class ConnectorCameraClient {
|
|
57
|
+
private readonly endpoint;
|
|
58
|
+
private readonly connectorKey;
|
|
59
|
+
private readonly timeoutMs;
|
|
60
|
+
private readonly poster;
|
|
61
|
+
constructor(options: ConnectorCameraClientOptions, poster?: HttpPoster);
|
|
62
|
+
registerCameras(cameras: RegisterCameraInput[]): Promise<RegisterResult>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Join the server's answer back to the LOCAL stream URLs, producing the
|
|
66
|
+
* `cameras[]` the connector runs on.
|
|
67
|
+
*
|
|
68
|
+
* Matching is by `cameraKey` and ONLY by `cameraKey` — never by name and never
|
|
69
|
+
* by array position. Names are truncated server-side (200 chars) so two feeds
|
|
70
|
+
* differing only past that point would collapse onto one screen, and the server
|
|
71
|
+
* is free to return fewer rows than were sent. `cameraKey` is the deterministic
|
|
72
|
+
* idempotency key both sides already agree on.
|
|
73
|
+
*
|
|
74
|
+
* A returned camera with no local match is DROPPED rather than guessed at: a
|
|
75
|
+
* feed configured with the wrong URL would sense the wrong room, which is worse
|
|
76
|
+
* than a feed that is absent and visibly missing from the camera board.
|
|
77
|
+
*/
|
|
78
|
+
export declare function buildCameraFeeds(registered: RegisteredCamera[], discovered: DiscoveredCamera[]): CameraFeedConfig[];
|
|
79
|
+
//# sourceMappingURL=ConnectorCameraClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConnectorCameraClient.d.ts","sourceRoot":"","sources":["../src/ConnectorCameraClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,WAAW,4BAA4B;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,uEAAuE;AACvE,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;CAClD;AAED,gFAAgF;AAChF,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;gBAExB,OAAO,EAAE,4BAA4B,EAAE,MAAM,GAAE,UAA8B;IAUnF,eAAe,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC;CAmE/E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,gBAAgB,EAAE,EAC9B,UAAU,EAAE,gBAAgB,EAAE,GAC7B,gBAAgB,EAAE,CAiBpB"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConnectorCameraClient = exports.MAX_CAMERAS_PER_CALL = void 0;
|
|
4
|
+
exports.buildCameraFeeds = buildCameraFeeds;
|
|
5
|
+
const AudienceAnalyzeClient_1 = require("./AudienceAnalyzeClient");
|
|
6
|
+
/** The server caps a single registration call; mirrors MAX_CAMERAS_PER_CALL. */
|
|
7
|
+
exports.MAX_CAMERAS_PER_CALL = 64;
|
|
8
|
+
class ConnectorCameraClient {
|
|
9
|
+
constructor(options, poster = AudienceAnalyzeClient_1.defaultHttpPoster) {
|
|
10
|
+
if (!options?.apiBaseUrl)
|
|
11
|
+
throw new Error('ConnectorCameraClient requires an apiBaseUrl');
|
|
12
|
+
if (!options?.connectorKey)
|
|
13
|
+
throw new Error('ConnectorCameraClient requires a connectorKey');
|
|
14
|
+
const base = options.apiBaseUrl.replace(/\/+$/, '');
|
|
15
|
+
this.endpoint = `${base}/v2/earner/connectors/cameras`;
|
|
16
|
+
this.connectorKey = options.connectorKey;
|
|
17
|
+
this.timeoutMs = options.timeoutMs ?? 60000;
|
|
18
|
+
this.poster = poster;
|
|
19
|
+
}
|
|
20
|
+
async registerCameras(cameras) {
|
|
21
|
+
if (!Array.isArray(cameras) || cameras.length === 0) {
|
|
22
|
+
return { ok: false, error: 'registerCameras() requires at least one camera', kind: 'invalid' };
|
|
23
|
+
}
|
|
24
|
+
if (cameras.length > exports.MAX_CAMERAS_PER_CALL) {
|
|
25
|
+
return {
|
|
26
|
+
ok: false,
|
|
27
|
+
error: `registerCameras() accepts at most ${exports.MAX_CAMERAS_PER_CALL} cameras per call`,
|
|
28
|
+
kind: 'invalid',
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
let response;
|
|
32
|
+
try {
|
|
33
|
+
response = await this.poster(this.endpoint, {
|
|
34
|
+
method: 'POST',
|
|
35
|
+
headers: {
|
|
36
|
+
'Content-Type': 'application/json',
|
|
37
|
+
Accept: 'application/json',
|
|
38
|
+
Authorization: `Bearer ${this.connectorKey}`,
|
|
39
|
+
},
|
|
40
|
+
timeoutMs: this.timeoutMs,
|
|
41
|
+
}, JSON.stringify({ cameras }));
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
return {
|
|
45
|
+
ok: false,
|
|
46
|
+
error: `camera registration failed: ${err?.message ?? 'unknown error'}`,
|
|
47
|
+
kind: 'network',
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
let parsed = null;
|
|
51
|
+
try {
|
|
52
|
+
parsed = JSON.parse(response.body);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
parsed = null;
|
|
56
|
+
}
|
|
57
|
+
const code = response.statusCode;
|
|
58
|
+
if (code < 200 || code >= 300) {
|
|
59
|
+
const kind = code === 401 || code === 403 ? 'auth' : code === 400 ? 'invalid' : 'server';
|
|
60
|
+
return {
|
|
61
|
+
ok: false,
|
|
62
|
+
error: parsed?.error || `camera registration failed (HTTP ${code})`,
|
|
63
|
+
kind,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const list = Array.isArray(parsed?.cameras) ? parsed.cameras : [];
|
|
67
|
+
// A 2xx that carries no tokens is a failure, not an empty success — treating
|
|
68
|
+
// it as success would write a `cameras[]` with no credentials and the defect
|
|
69
|
+
// would surface much later as a feed that never posts.
|
|
70
|
+
if (list.length === 0 || list.some((c) => !c?.deviceToken || !c?.screenId)) {
|
|
71
|
+
return {
|
|
72
|
+
ok: false,
|
|
73
|
+
error: 'registration response did not contain device tokens for every camera',
|
|
74
|
+
kind: 'server',
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
return { ok: true, cameras: list };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.ConnectorCameraClient = ConnectorCameraClient;
|
|
81
|
+
/**
|
|
82
|
+
* Join the server's answer back to the LOCAL stream URLs, producing the
|
|
83
|
+
* `cameras[]` the connector runs on.
|
|
84
|
+
*
|
|
85
|
+
* Matching is by `cameraKey` and ONLY by `cameraKey` — never by name and never
|
|
86
|
+
* by array position. Names are truncated server-side (200 chars) so two feeds
|
|
87
|
+
* differing only past that point would collapse onto one screen, and the server
|
|
88
|
+
* is free to return fewer rows than were sent. `cameraKey` is the deterministic
|
|
89
|
+
* idempotency key both sides already agree on.
|
|
90
|
+
*
|
|
91
|
+
* A returned camera with no local match is DROPPED rather than guessed at: a
|
|
92
|
+
* feed configured with the wrong URL would sense the wrong room, which is worse
|
|
93
|
+
* than a feed that is absent and visibly missing from the camera board.
|
|
94
|
+
*/
|
|
95
|
+
function buildCameraFeeds(registered, discovered) {
|
|
96
|
+
const byKey = new Map(discovered.map((d) => [d.cameraKey, d]));
|
|
97
|
+
const feeds = [];
|
|
98
|
+
for (const cam of registered) {
|
|
99
|
+
const local = byKey.get(cam.cameraKey);
|
|
100
|
+
if (!local?.rtspUrl)
|
|
101
|
+
continue;
|
|
102
|
+
feeds.push({
|
|
103
|
+
name: cam.name || local.name,
|
|
104
|
+
screenId: cam.screenId,
|
|
105
|
+
deviceToken: cam.deviceToken,
|
|
106
|
+
rtspUrl: local.rtspUrl,
|
|
107
|
+
sourceType: local.source === 'channel-range' ? 'recorder' : 'direct_url',
|
|
108
|
+
channelKey: cam.cameraKey,
|
|
109
|
+
transport: 'tcp',
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return feeds;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=ConnectorCameraClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConnectorCameraClient.js","sourceRoot":"","sources":["../src/ConnectorCameraClient.ts"],"names":[],"mappings":"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"}
|
package/dist/EdgeAgent.js
CHANGED
|
@@ -44,7 +44,7 @@ const edge_ads_1 = require("@trillboards/edge-ads");
|
|
|
44
44
|
const CommandRouter_1 = require("./CommandRouter");
|
|
45
45
|
const config_1 = require("./config");
|
|
46
46
|
const dataDir_1 = require("./dataDir");
|
|
47
|
-
const SDK_VERSION = '0.2.
|
|
47
|
+
const SDK_VERSION = '0.2.26';
|
|
48
48
|
class EdgeAgent extends events_1.EventEmitter {
|
|
49
49
|
constructor(config, deps) {
|
|
50
50
|
super();
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type HttpPoster } from './AudienceAnalyzeClient';
|
|
2
|
+
/**
|
|
3
|
+
* EnrollClient — UNATTENDED first-boot provisioning.
|
|
4
|
+
*
|
|
5
|
+
* Exchanges a FLEET enrollment credential (issued once in the portal, shipped
|
|
6
|
+
* inside the MDM/Intune/SCCM package) for THIS MACHINE's own connector
|
|
7
|
+
* credential, via `POST {apiBaseUrl}/v2/earner/connectors/enroll`.
|
|
8
|
+
*
|
|
9
|
+
* WHY THIS EXISTS. Every other path to a working connector needs a human at the
|
|
10
|
+
* machine: `pair --code` needs an 8-character claim code typed in, and `setup`
|
|
11
|
+
* needs a code read off this screen and typed into a browser on another. Neither
|
|
12
|
+
* can be automated, so before this there was no way to deploy to N machines.
|
|
13
|
+
*
|
|
14
|
+
* WHAT COMES BACK, AND WHAT DOES NOT. The response carries a `connectorKey`
|
|
15
|
+
* scoped to camera registration for one account — NOT the fleet credential, and
|
|
16
|
+
* NOT any device token. Device tokens are still minted per camera feed, later,
|
|
17
|
+
* when the cameras this machine finds are registered. That split is deliberate:
|
|
18
|
+
* the credential that ends up sitting on 200 store PCs must not be able to
|
|
19
|
+
* enroll a 201st machine.
|
|
20
|
+
*
|
|
21
|
+
* THE FLEET CREDENTIAL IS CONSUMED, NOT KEPT. The caller writes `connectorKey`
|
|
22
|
+
* into the config and DELETES the enrollment file — see `runEnroll` in cli.ts.
|
|
23
|
+
* A bootstrap credential that outlives its bootstrap is just a credential.
|
|
24
|
+
*
|
|
25
|
+
* Auth is `Authorization: Bearer <enrollment token>` — the same platform-key
|
|
26
|
+
* header the Partner API and the CTV SDK use. Unlike `PairClient`, this request
|
|
27
|
+
* IS authenticated; unlike `AudienceAnalyzeClient`, it carries no device token,
|
|
28
|
+
* because at first boot this machine has no device identity yet. That is the
|
|
29
|
+
* whole point of the exchange.
|
|
30
|
+
*
|
|
31
|
+
* Uses the same built-in-http poster as its siblings (no extra dep → survives
|
|
32
|
+
* bundling; trivially mockable in tests).
|
|
33
|
+
*/
|
|
34
|
+
export interface EnrollClientOptions {
|
|
35
|
+
/** Base URL, e.g. https://api.trillboards.com (no trailing slash needed). */
|
|
36
|
+
apiBaseUrl: string;
|
|
37
|
+
/** Request timeout in ms. Default: 30000. */
|
|
38
|
+
timeoutMs?: number;
|
|
39
|
+
}
|
|
40
|
+
export interface EnrollRequest {
|
|
41
|
+
/** The fleet enrollment credential from the MDM package. */
|
|
42
|
+
enrollmentToken: string;
|
|
43
|
+
/** This machine's stable fingerprint — `hostFingerprint()` in cli.ts. */
|
|
44
|
+
machineId: string;
|
|
45
|
+
/** Free-text install label, e.g. "Store 0417". Optional. */
|
|
46
|
+
siteLabel?: string;
|
|
47
|
+
hostname?: string;
|
|
48
|
+
platform?: string;
|
|
49
|
+
connectorVersion?: string;
|
|
50
|
+
}
|
|
51
|
+
export interface EnrollResult {
|
|
52
|
+
ok: boolean;
|
|
53
|
+
/** Present only when ok. */
|
|
54
|
+
connectorId?: string;
|
|
55
|
+
connectorKey?: string;
|
|
56
|
+
siteLabel?: string | null;
|
|
57
|
+
reEnrollment?: boolean;
|
|
58
|
+
remainingEnrollments?: number | null;
|
|
59
|
+
error?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Classification, so the installer wrapper can tell an operator-fixable
|
|
62
|
+
* problem from a wait-and-retry one WITHOUT parsing prose:
|
|
63
|
+
*
|
|
64
|
+
* 'auth' the credential is wrong, expired, revoked or exhausted. A human
|
|
65
|
+
* must issue a new one — retrying forever cannot help, and a
|
|
66
|
+
* connector that retries a dead credential every 60s across 200
|
|
67
|
+
* stores is a self-inflicted DDoS.
|
|
68
|
+
* 'network' unreachable / timed out. Retry.
|
|
69
|
+
* 'server' 5xx or an unparseable body. Retry.
|
|
70
|
+
* 'invalid' this machine sent something malformed. A bug, not a retry.
|
|
71
|
+
*/
|
|
72
|
+
kind?: 'auth' | 'network' | 'server' | 'invalid';
|
|
73
|
+
}
|
|
74
|
+
export declare class EnrollClient {
|
|
75
|
+
private readonly endpoint;
|
|
76
|
+
private readonly timeoutMs;
|
|
77
|
+
private readonly poster;
|
|
78
|
+
constructor(options: EnrollClientOptions, poster?: HttpPoster);
|
|
79
|
+
enroll(req: EnrollRequest): Promise<EnrollResult>;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=EnrollClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EnrollClient.d.ts","sourceRoot":"","sources":["../src/EnrollClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,MAAM,WAAW,mBAAmB;IAClC,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,4DAA4D;IAC5D,eAAe,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,4BAA4B;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;CAClD;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;gBAExB,OAAO,EAAE,mBAAmB,EAAE,MAAM,GAAE,UAA8B;IAU1E,MAAM,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CAqFxD"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EnrollClient = void 0;
|
|
4
|
+
const AudienceAnalyzeClient_1 = require("./AudienceAnalyzeClient");
|
|
5
|
+
class EnrollClient {
|
|
6
|
+
constructor(options, poster = AudienceAnalyzeClient_1.defaultHttpPoster) {
|
|
7
|
+
if (!options?.apiBaseUrl) {
|
|
8
|
+
throw new Error('EnrollClient requires an apiBaseUrl');
|
|
9
|
+
}
|
|
10
|
+
const base = options.apiBaseUrl.replace(/\/+$/, '');
|
|
11
|
+
this.endpoint = `${base}/v2/earner/connectors/enroll`;
|
|
12
|
+
this.timeoutMs = options.timeoutMs ?? 30000;
|
|
13
|
+
this.poster = poster;
|
|
14
|
+
}
|
|
15
|
+
async enroll(req) {
|
|
16
|
+
const token = (req?.enrollmentToken ?? '').trim();
|
|
17
|
+
if (!token) {
|
|
18
|
+
return { ok: false, error: 'enroll() requires a non-empty enrollmentToken', kind: 'invalid' };
|
|
19
|
+
}
|
|
20
|
+
if (!req?.machineId) {
|
|
21
|
+
return { ok: false, error: 'enroll() requires a machineId', kind: 'invalid' };
|
|
22
|
+
}
|
|
23
|
+
const body = { machineId: req.machineId };
|
|
24
|
+
if (req.siteLabel)
|
|
25
|
+
body.siteLabel = req.siteLabel;
|
|
26
|
+
if (req.hostname)
|
|
27
|
+
body.hostname = req.hostname;
|
|
28
|
+
if (req.platform)
|
|
29
|
+
body.platform = req.platform;
|
|
30
|
+
if (req.connectorVersion)
|
|
31
|
+
body.connectorVersion = req.connectorVersion;
|
|
32
|
+
let response;
|
|
33
|
+
try {
|
|
34
|
+
response = await this.poster(this.endpoint, {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
headers: {
|
|
37
|
+
'Content-Type': 'application/json',
|
|
38
|
+
Accept: 'application/json',
|
|
39
|
+
Authorization: `Bearer ${token}`,
|
|
40
|
+
},
|
|
41
|
+
timeoutMs: this.timeoutMs,
|
|
42
|
+
}, JSON.stringify(body));
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
return {
|
|
46
|
+
ok: false,
|
|
47
|
+
error: `enrollment request failed: ${err?.message ?? 'unknown error'}`,
|
|
48
|
+
kind: 'network',
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
let parsed = null;
|
|
52
|
+
try {
|
|
53
|
+
parsed = JSON.parse(response.body);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
parsed = null;
|
|
57
|
+
}
|
|
58
|
+
const code = response.statusCode;
|
|
59
|
+
if (code < 200 || code >= 300) {
|
|
60
|
+
// 401/403 is terminal: the credential is wrong, spent, expired or revoked.
|
|
61
|
+
// The server deliberately does not say WHICH — see consumeKeyUse — so the
|
|
62
|
+
// connector cannot tell either, and must not retry as if it could.
|
|
63
|
+
const kind = code === 401 || code === 403
|
|
64
|
+
? 'auth'
|
|
65
|
+
: code === 400
|
|
66
|
+
? 'invalid'
|
|
67
|
+
: 'server';
|
|
68
|
+
const message = parsed?.error
|
|
69
|
+
|| parsed?.message
|
|
70
|
+
|| `enrollment failed (HTTP ${code})`;
|
|
71
|
+
return { ok: false, error: message, kind };
|
|
72
|
+
}
|
|
73
|
+
const connectorKey = typeof parsed?.connectorKey === 'string' ? parsed.connectorKey : '';
|
|
74
|
+
const connectorId = typeof parsed?.connectorId === 'string' ? parsed.connectorId : '';
|
|
75
|
+
if (!connectorKey || !connectorId) {
|
|
76
|
+
// A 2xx that carries no credential is the ingestion-endpoint trap in
|
|
77
|
+
// reverse: treating it as success would leave a "provisioned" machine with
|
|
78
|
+
// nothing to authenticate with, and the failure would only surface much
|
|
79
|
+
// later as a camera that never registers.
|
|
80
|
+
return {
|
|
81
|
+
ok: false,
|
|
82
|
+
error: 'enrollment response did not contain a connector credential',
|
|
83
|
+
kind: 'server',
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
ok: true,
|
|
88
|
+
connectorId,
|
|
89
|
+
connectorKey,
|
|
90
|
+
siteLabel: parsed?.siteLabel ?? null,
|
|
91
|
+
reEnrollment: parsed?.reEnrollment === true,
|
|
92
|
+
remainingEnrollments: typeof parsed?.remainingEnrollments === 'number' ? parsed.remainingEnrollments : null,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
exports.EnrollClient = EnrollClient;
|
|
97
|
+
//# sourceMappingURL=EnrollClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EnrollClient.js","sourceRoot":"","sources":["../src/EnrollClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,6 +27,8 @@ export interface SetupCommand {
|
|
|
27
27
|
port?: number;
|
|
28
28
|
brandHint?: string;
|
|
29
29
|
channelHint?: number;
|
|
30
|
+
/** Operator-typed RTSP stream path, tried first in the brand-candidate walk. */
|
|
31
|
+
pathHint?: string;
|
|
30
32
|
credentials?: {
|
|
31
33
|
username: string;
|
|
32
34
|
password: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SetupSessionClient.d.ts","sourceRoot":"","sources":["../src/SetupSessionClient.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SetupSessionClient.d.ts","sourceRoot":"","sources":["../src/SetupSessionClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SetupSessionClient.js","sourceRoot":"","sources":["../src/SetupSessionClient.ts"],"names":[],"mappings":";;;AAAA,mEAA6E;
|
|
1
|
+
{"version":3,"file":"SetupSessionClient.js","sourceRoot":"","sources":["../src/SetupSessionClient.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
CHANGED
|
@@ -26,4 +26,53 @@ export declare function configWritePermissionMessage(resolvedConfigPath: string)
|
|
|
26
26
|
export declare function writePairedConfig(resolvedConfigPath: string, serialized: string, writeFile?: (p: string, data: string, opts: {
|
|
27
27
|
mode: number;
|
|
28
28
|
}) => void): void;
|
|
29
|
+
/** Show a credential's SHAPE without showing the credential. */
|
|
30
|
+
export declare function maskConnectorKey(key: string | undefined | null): string;
|
|
31
|
+
/**
|
|
32
|
+
* Read the enrollment token for an unattended install, in precedence order.
|
|
33
|
+
*
|
|
34
|
+
* 1. `--enrollment-token <value>` — for a scripted/manual run.
|
|
35
|
+
* 2. `TRILLBOARDS_ENROLLMENT_TOKEN` — the Docker/systemd path.
|
|
36
|
+
* 3. `--enrollment-file <path>` / the default bootstrap file next to the config
|
|
37
|
+
* — what the Windows installer writes from `/ENROLLMENT_TOKEN=`.
|
|
38
|
+
*
|
|
39
|
+
* The FILE is the preferred form for MDM and the reason this function exists:
|
|
40
|
+
* an argument shows up in the process table and an env var is inherited by every
|
|
41
|
+
* child process, while a file can be read once and DELETED. That deletion is not
|
|
42
|
+
* hygiene, it is the design — the fleet credential must not outlive the
|
|
43
|
+
* bootstrap, or every store PC keeps something that can enroll more machines.
|
|
44
|
+
*/
|
|
45
|
+
export declare function readEnrollmentToken(args: string[], configPath: string, env?: NodeJS.ProcessEnv, readFile?: (p: string) => string, exists?: (p: string) => boolean): {
|
|
46
|
+
token: string | null;
|
|
47
|
+
source: 'flag' | 'env' | 'file' | null;
|
|
48
|
+
filePath: string | null;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* UNATTENDED first-boot provisioning — the MDM/Intune/SCCM path.
|
|
52
|
+
*
|
|
53
|
+
* trillboards-edge enroll [--enrollment-token T | --enrollment-file P]
|
|
54
|
+
* [--site "Store 0417"] [--config PATH] [--api-base URL]
|
|
55
|
+
*
|
|
56
|
+
* Exchanges the FLEET enrollment credential shipped in the deployment package
|
|
57
|
+
* for THIS MACHINE's own connector credential and writes it to the config. No
|
|
58
|
+
* human touches the machine, which is the entire point: `pair` needs a code
|
|
59
|
+
* typed in and `setup` needs a code read off the screen, so neither can be
|
|
60
|
+
* automated across N stores.
|
|
61
|
+
*
|
|
62
|
+
* IDEMPOTENT BY DESIGN. Re-running on an already-enrolled machine is safe and
|
|
63
|
+
* FREE — the server keys on `machineId` and does not spend another use of the
|
|
64
|
+
* bounded fleet credential. MDM re-pushes packages; if a re-push cost a use, a
|
|
65
|
+
* 200-use credential would die partway through a 200-store rollout.
|
|
66
|
+
*
|
|
67
|
+
* ON SUCCESS THE ENROLLMENT FILE IS DELETED. See readEnrollmentToken.
|
|
68
|
+
*
|
|
69
|
+
* Exit codes (the install wrappers branch on these — keep stable, and note they
|
|
70
|
+
* mirror `pair`'s so a wrapper can treat the two paths alike):
|
|
71
|
+
* 0 enrolled (or already enrolled), config written
|
|
72
|
+
* 1 the credential was rejected — wrong, expired, revoked or exhausted. A
|
|
73
|
+
* human must issue a new one; retrying cannot help.
|
|
74
|
+
* 4 no enrollment token was supplied at all (not an unattended install)
|
|
75
|
+
* 6 network/server failure — the credential is UNSPENT. Retry later.
|
|
76
|
+
*/
|
|
77
|
+
export declare function runEnroll(args: string[]): Promise<void>;
|
|
29
78
|
//# sourceMappingURL=cli.d.ts.map
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAscA;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAKvD;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAW/E;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,kBAAkB,EAAE,MAAM,EAC1B,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,KAAK,IAC/B,GAChC,IAAI,CAWN;AAUD,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CASvE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EAAE,EACd,UAAU,EAAE,MAAM,EAClB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,QAAQ,GAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAA2C,EACpE,MAAM,GAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAiC,GACvD;IAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAyB3F;AAgGD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA+K7D"}
|