@camstack/system 1.1.50 → 1.1.51
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/dist/addon-runner.js +2 -2
- package/dist/addon-runner.mjs +2 -2
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/device-manager/device-manager.addon.js +1 -1
- package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
- package/dist/builtins/local-network/local-network.addon.js +1 -1
- package/dist/builtins/local-network/local-network.addon.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +162 -12
- package/dist/builtins/snapshot/index.mjs +162 -12
- package/dist/builtins/snapshot/snapshot-media-handler.d.ts +38 -0
- package/dist/builtins/snapshot/snapshot.addon.d.ts +26 -0
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{dist-CC3E-_3h.mjs → dist-BWQX9yUj.mjs} +11 -3
- package/dist/{dist-CQYo6Zp8.js → dist-C3uHEBtP.js} +10 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +34 -22
- package/dist/index.mjs +34 -23
- package/dist/kernel/addon-installer.d.ts +8 -0
- package/dist/kernel/deps/manifest-native-deps.d.ts +1 -1
- package/dist/kernel/deps/npm-command.d.ts +38 -0
- package/dist/{manifest-python-deps-DqATCsK0.mjs → manifest-python-deps-BA6KA9If.mjs} +268 -124
- package/dist/{manifest-python-deps-Wy8dNJpr.js → manifest-python-deps-CVcJ9hDX.js} +279 -123
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Q as streamQualityLabel, Y as snapshotCapability, lt as DeviceType, nt as errMsg, rt as BaseAddon, st as DeviceFeature, z as nodePin } from "../../dist-
|
|
1
|
+
import { Q as streamQualityLabel, Y as snapshotCapability, lt as DeviceType, nt as errMsg, rt as BaseAddon, st as DeviceFeature, z as nodePin } from "../../dist-BWQX9yUj.mjs";
|
|
2
2
|
import { execFile } from "node:child_process";
|
|
3
3
|
//#region src/builtins/snapshot/snapshot-coalescing.ts
|
|
4
4
|
/**
|
|
@@ -195,12 +195,102 @@ function raceForResult(promise, timeoutMs) {
|
|
|
195
195
|
});
|
|
196
196
|
}
|
|
197
197
|
//#endregion
|
|
198
|
+
//#region src/builtins/snapshot/snapshot-media-handler.ts
|
|
199
|
+
/**
|
|
200
|
+
* Parse the handler-relative path (`/<deviceId>.jpg?query`) into a request.
|
|
201
|
+
* Returns null for a malformed / nested / non-numeric id so the handler answers
|
|
202
|
+
* 404 without ever reaching `getMedia`.
|
|
203
|
+
*/
|
|
204
|
+
function parseSnapshotMediaRequest(url) {
|
|
205
|
+
const qIdx = url.indexOf("?");
|
|
206
|
+
const rawPath = qIdx === -1 ? url : url.slice(0, qIdx);
|
|
207
|
+
const query = qIdx === -1 ? "" : url.slice(qIdx + 1);
|
|
208
|
+
const segment = rawPath.replace(/^\/+/, "");
|
|
209
|
+
if (segment.length === 0 || segment.includes("/")) return null;
|
|
210
|
+
const idPart = segment.replace(/\.jpe?g$/i, "");
|
|
211
|
+
if (!/^\d+$/.test(idPart)) return null;
|
|
212
|
+
const deviceId = Number.parseInt(idPart, 10);
|
|
213
|
+
if (!Number.isSafeInteger(deviceId)) return null;
|
|
214
|
+
const params = new URLSearchParams(query);
|
|
215
|
+
const rawStream = params.get("streamId");
|
|
216
|
+
const streamId = rawStream !== null && rawStream.length > 0 ? rawStream : void 0;
|
|
217
|
+
const rawForce = params.get("force");
|
|
218
|
+
return {
|
|
219
|
+
deviceId,
|
|
220
|
+
streamId,
|
|
221
|
+
force: rawForce === "1" || rawForce === "true"
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Create a data-plane handler that serves per-device snapshots as JPEG images.
|
|
226
|
+
* `deps.getMedia` is called once per request; null → 404, throw → 500. A
|
|
227
|
+
* conditional GET with a matching `If-None-Match` produces a 304.
|
|
228
|
+
*/
|
|
229
|
+
function createSnapshotMediaHandler(deps) {
|
|
230
|
+
return async (req, res) => {
|
|
231
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
232
|
+
res.writeHead(405, { allow: "GET, HEAD" }).end();
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const parsed = parseSnapshotMediaRequest(req.url ?? "/");
|
|
236
|
+
if (parsed === null) {
|
|
237
|
+
res.writeHead(404).end();
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
let media;
|
|
241
|
+
try {
|
|
242
|
+
media = await deps.getMedia(parsed.deviceId, parsed.streamId, parsed.force);
|
|
243
|
+
} catch {
|
|
244
|
+
const body = "Internal server error";
|
|
245
|
+
res.writeHead(500, {
|
|
246
|
+
"content-type": "text/plain",
|
|
247
|
+
"content-length": String(Buffer.byteLength(body))
|
|
248
|
+
});
|
|
249
|
+
if (req.method === "HEAD") res.end();
|
|
250
|
+
else res.end(body);
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
if (media === null) {
|
|
254
|
+
res.writeHead(404).end();
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const etag = `"${parsed.deviceId}-${media.capturedAt}"`;
|
|
258
|
+
const cacheControl = `private, max-age=${Math.max(0, Math.floor(media.maxAgeS))}`;
|
|
259
|
+
if (req.headers["if-none-match"] === etag) {
|
|
260
|
+
res.writeHead(304, {
|
|
261
|
+
etag,
|
|
262
|
+
"cache-control": cacheControl
|
|
263
|
+
}).end();
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
res.writeHead(200, {
|
|
267
|
+
"content-type": media.contentType,
|
|
268
|
+
"cache-control": cacheControl,
|
|
269
|
+
etag,
|
|
270
|
+
"content-length": String(media.bytes.byteLength)
|
|
271
|
+
});
|
|
272
|
+
if (req.method === "HEAD") res.end();
|
|
273
|
+
else res.end(Buffer.from(media.bytes));
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
//#endregion
|
|
198
277
|
//#region src/builtins/snapshot/snapshot.addon.ts
|
|
199
278
|
/** Default cache window for non-battery cams (seconds). 10s feels live. */
|
|
200
279
|
var NON_BATTERY_DEFAULT_MAX_AGE_S = 10;
|
|
201
280
|
/** Default cache window for battery cams (seconds). 1h ≈ "don't wake the cam unless asked". */
|
|
202
281
|
var BATTERY_DEFAULT_MAX_AGE_S = 3600;
|
|
203
282
|
/**
|
|
283
|
+
* Effective per-device max cache age (seconds): the operator override
|
|
284
|
+
* (`snapshotMaxAgeS`) when a finite non-negative number, else the battery-aware
|
|
285
|
+
* default. Shared by the freshness gate (`getSnapshot`) and the HTTP endpoint's
|
|
286
|
+
* `Cache-Control: max-age` (so the browser/`expo-image` layer caches for exactly
|
|
287
|
+
* as long as the wrapper considers the frame fresh).
|
|
288
|
+
*/
|
|
289
|
+
function effectiveMaxAgeS(prefs, isBattery) {
|
|
290
|
+
const def = isBattery ? BATTERY_DEFAULT_MAX_AGE_S : NON_BATTERY_DEFAULT_MAX_AGE_S;
|
|
291
|
+
return typeof prefs.snapshotMaxAgeS === "number" && prefs.snapshotMaxAgeS >= 0 ? prefs.snapshotMaxAgeS : def;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
204
294
|
* SnapshotAddon — wrapper over the `snapshot` capability.
|
|
205
295
|
*
|
|
206
296
|
* Activated per-device (toggleable by user; default active). When active,
|
|
@@ -240,25 +330,86 @@ var SnapshotAddon = class SnapshotAddon extends BaseAddon {
|
|
|
240
330
|
*/
|
|
241
331
|
ownerCache = null;
|
|
242
332
|
static OWNER_CACHE_TTL_MS = 3e4;
|
|
333
|
+
/**
|
|
334
|
+
* Handle for the `/addon/snapshot/media/<deviceId>.jpg` HTTP data-plane
|
|
335
|
+
* endpoint (§3.1). Null when the host provides no `ctx.dataPlane` facility
|
|
336
|
+
* (the tRPC `getSnapshot` base64 surface still works — the endpoint is a
|
|
337
|
+
* strictly-additive delivery path). Disposed on shutdown.
|
|
338
|
+
*/
|
|
339
|
+
mediaDataPlane = null;
|
|
243
340
|
constructor() {
|
|
244
341
|
super({ staleTtlMs: 6e4 });
|
|
245
342
|
}
|
|
246
343
|
async onInitialize() {
|
|
247
344
|
this.ctx.logger.info("Snapshot wrapper initialized");
|
|
345
|
+
const provider = {
|
|
346
|
+
getSnapshot: (input) => this.getSnapshot(input),
|
|
347
|
+
invalidateCache: (input) => this.invalidateCache(input),
|
|
348
|
+
getDeviceSettingsContribution: (input) => this.buildDeviceSettingsContribution(input.deviceId),
|
|
349
|
+
getDeviceLiveContribution: async () => null,
|
|
350
|
+
applyDeviceSettingsPatch: (input) => this.saveDeviceSettingsPatch(input.deviceId, input.patch),
|
|
351
|
+
getStatus: async (input) => this.getStatus(input.deviceId),
|
|
352
|
+
getSnapshotOverview: (input) => this.getSnapshotOverview(input)
|
|
353
|
+
};
|
|
354
|
+
await this.serveMediaDataPlane();
|
|
248
355
|
return [{
|
|
249
356
|
capability: snapshotCapability,
|
|
250
|
-
provider
|
|
251
|
-
getSnapshot: (input) => this.getSnapshot(input),
|
|
252
|
-
invalidateCache: (input) => this.invalidateCache(input),
|
|
253
|
-
getDeviceSettingsContribution: (input) => this.buildDeviceSettingsContribution(input.deviceId),
|
|
254
|
-
getDeviceLiveContribution: async () => null,
|
|
255
|
-
applyDeviceSettingsPatch: (input) => this.saveDeviceSettingsPatch(input.deviceId, input.patch),
|
|
256
|
-
getStatus: async (input) => this.getStatus(input.deviceId),
|
|
257
|
-
getSnapshotOverview: (input) => this.getSnapshotOverview(input)
|
|
258
|
-
}
|
|
357
|
+
provider
|
|
259
358
|
}];
|
|
260
359
|
}
|
|
360
|
+
/**
|
|
361
|
+
* Serve the per-device snapshot image endpoint on the addon data-plane
|
|
362
|
+
* (§3.1). Delivery: `GET /addon/snapshot/media/<deviceId>.jpg` → raw JPEG with
|
|
363
|
+
* `ETag` + `Cache-Control: private, max-age=<device maxAgeS>`, so a grid is N
|
|
364
|
+
* independent `<Image>` tiles served from the coalesced server cache (no
|
|
365
|
+
* base64 tax, no batch head-of-line blocking, browser/`expo-image` caching for
|
|
366
|
+
* free). Best-effort: a host without a `dataPlane` facility keeps the tRPC
|
|
367
|
+
* base64 path.
|
|
368
|
+
*/
|
|
369
|
+
async serveMediaDataPlane() {
|
|
370
|
+
const handler = createSnapshotMediaHandler({ getMedia: (deviceId, streamId, force) => this.resolveSnapshotMedia(deviceId, streamId, force) });
|
|
371
|
+
try {
|
|
372
|
+
this.mediaDataPlane = await this.ctx.dataPlane?.serve({
|
|
373
|
+
prefix: "media",
|
|
374
|
+
access: "authenticated",
|
|
375
|
+
handler
|
|
376
|
+
}) ?? null;
|
|
377
|
+
this.ctx.logger.info("snapshot media data-plane served", { meta: { baseUrl: this.mediaDataPlane ? `/addon/${this.ctx.id}/media` : "(no dataPlane facility)" } });
|
|
378
|
+
} catch (err) {
|
|
379
|
+
this.ctx.logger.warn("snapshot media data-plane failed to serve", { meta: { error: errMsg(err) } });
|
|
380
|
+
this.mediaDataPlane = null;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Resolve a device (+ optional stream, + force) to renderable JPEG bytes for
|
|
385
|
+
* the HTTP endpoint. Runs the same coalesced capture ladder as the tRPC
|
|
386
|
+
* `getSnapshot` (so every consumer shares one upstream pull), then decodes the
|
|
387
|
+
* base64 cache into raw bytes and stamps the frame identity: `capturedAt` from
|
|
388
|
+
* the cache entry (matching the ETag `getSnapshotOverview` advertises) and the
|
|
389
|
+
* effective per-device `maxAgeS` for `Cache-Control`. Null → 404.
|
|
390
|
+
*/
|
|
391
|
+
async resolveSnapshotMedia(deviceId, streamId, force) {
|
|
392
|
+
const image = await this.getSnapshot({
|
|
393
|
+
deviceId,
|
|
394
|
+
...streamId !== void 0 ? { streamId } : {},
|
|
395
|
+
force
|
|
396
|
+
});
|
|
397
|
+
if (!image) return null;
|
|
398
|
+
const capturedAt = this.cache.get(deviceId)?.ts ?? Date.now();
|
|
399
|
+
const prefs = await this.readDeviceSettings(deviceId).catch(() => ({}));
|
|
400
|
+
const isBattery = (await this.lookupDeviceMeta(deviceId))?.isBattery ?? false;
|
|
401
|
+
return {
|
|
402
|
+
bytes: Buffer.from(image.base64, "base64"),
|
|
403
|
+
contentType: image.contentType,
|
|
404
|
+
capturedAt,
|
|
405
|
+
maxAgeS: effectiveMaxAgeS(prefs, isBattery)
|
|
406
|
+
};
|
|
407
|
+
}
|
|
261
408
|
async onShutdown() {
|
|
409
|
+
if (this.mediaDataPlane) {
|
|
410
|
+
await this.mediaDataPlane.dispose().catch(() => void 0);
|
|
411
|
+
this.mediaDataPlane = null;
|
|
412
|
+
}
|
|
262
413
|
this.cache.clear();
|
|
263
414
|
this.captureFlight.clear();
|
|
264
415
|
this.ownerCache = null;
|
|
@@ -311,8 +462,7 @@ var SnapshotAddon = class SnapshotAddon extends BaseAddon {
|
|
|
311
462
|
tags: { deviceId },
|
|
312
463
|
meta: { stream: effectiveStreamId ?? "auto" }
|
|
313
464
|
});
|
|
314
|
-
const
|
|
315
|
-
const effectiveMaxAgeMs = (typeof prefs.snapshotMaxAgeS === "number" && prefs.snapshotMaxAgeS >= 0 ? prefs.snapshotMaxAgeS : defaultMaxAgeS) * 1e3;
|
|
465
|
+
const effectiveMaxAgeMs = effectiveMaxAgeS(prefs, isBatteryDevice) * 1e3;
|
|
316
466
|
const decision = decideSnapshotServe({
|
|
317
467
|
now,
|
|
318
468
|
cachedAt: hit?.ts ?? null,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { DataPlaneHandler } from '@camstack/types';
|
|
2
|
+
/** A renderable snapshot frame resolved for one device. */
|
|
3
|
+
export interface SnapshotMedia {
|
|
4
|
+
/** Raw image bytes (already decoded from the wrapper's base64 cache). */
|
|
5
|
+
readonly bytes: Uint8Array;
|
|
6
|
+
/** MIME type — practically always `image/jpeg`. */
|
|
7
|
+
readonly contentType: string;
|
|
8
|
+
/** Epoch ms of the cached capture — drives the ETag and frame identity. */
|
|
9
|
+
readonly capturedAt: number;
|
|
10
|
+
/** Effective per-device max cache age (seconds) → `Cache-Control: max-age`. */
|
|
11
|
+
readonly maxAgeS: number;
|
|
12
|
+
}
|
|
13
|
+
export interface SnapshotMediaHandlerDeps {
|
|
14
|
+
/**
|
|
15
|
+
* Resolve a device (+ optional stream, + force) to a renderable frame. Runs
|
|
16
|
+
* the wrapper's coalesced capture ladder; returns null when no frame can be
|
|
17
|
+
* produced (→ 404). Throwing produces an opaque 500 (caller logs).
|
|
18
|
+
*/
|
|
19
|
+
readonly getMedia: (deviceId: number, streamId: string | undefined, force: boolean) => Promise<SnapshotMedia | null>;
|
|
20
|
+
}
|
|
21
|
+
/** Parsed `/<deviceId>[.jpg][?streamId=…&force=1]` request. */
|
|
22
|
+
export interface SnapshotMediaRequest {
|
|
23
|
+
readonly deviceId: number;
|
|
24
|
+
readonly streamId: string | undefined;
|
|
25
|
+
readonly force: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Parse the handler-relative path (`/<deviceId>.jpg?query`) into a request.
|
|
29
|
+
* Returns null for a malformed / nested / non-numeric id so the handler answers
|
|
30
|
+
* 404 without ever reaching `getMedia`.
|
|
31
|
+
*/
|
|
32
|
+
export declare function parseSnapshotMediaRequest(url: string): SnapshotMediaRequest | null;
|
|
33
|
+
/**
|
|
34
|
+
* Create a data-plane handler that serves per-device snapshots as JPEG images.
|
|
35
|
+
* `deps.getMedia` is called once per request; null → 404, throw → 500. A
|
|
36
|
+
* conditional GET with a matching `If-None-Match` produces a 304.
|
|
37
|
+
*/
|
|
38
|
+
export declare function createSnapshotMediaHandler(deps: SnapshotMediaHandlerDeps): DataPlaneHandler;
|
|
@@ -50,8 +50,34 @@ export declare class SnapshotAddon extends BaseAddon<SnapshotAddonConfig> {
|
|
|
50
50
|
*/
|
|
51
51
|
private ownerCache;
|
|
52
52
|
private static readonly OWNER_CACHE_TTL_MS;
|
|
53
|
+
/**
|
|
54
|
+
* Handle for the `/addon/snapshot/media/<deviceId>.jpg` HTTP data-plane
|
|
55
|
+
* endpoint (§3.1). Null when the host provides no `ctx.dataPlane` facility
|
|
56
|
+
* (the tRPC `getSnapshot` base64 surface still works — the endpoint is a
|
|
57
|
+
* strictly-additive delivery path). Disposed on shutdown.
|
|
58
|
+
*/
|
|
59
|
+
private mediaDataPlane;
|
|
53
60
|
constructor();
|
|
54
61
|
protected onInitialize(): Promise<ProviderRegistration[]>;
|
|
62
|
+
/**
|
|
63
|
+
* Serve the per-device snapshot image endpoint on the addon data-plane
|
|
64
|
+
* (§3.1). Delivery: `GET /addon/snapshot/media/<deviceId>.jpg` → raw JPEG with
|
|
65
|
+
* `ETag` + `Cache-Control: private, max-age=<device maxAgeS>`, so a grid is N
|
|
66
|
+
* independent `<Image>` tiles served from the coalesced server cache (no
|
|
67
|
+
* base64 tax, no batch head-of-line blocking, browser/`expo-image` caching for
|
|
68
|
+
* free). Best-effort: a host without a `dataPlane` facility keeps the tRPC
|
|
69
|
+
* base64 path.
|
|
70
|
+
*/
|
|
71
|
+
private serveMediaDataPlane;
|
|
72
|
+
/**
|
|
73
|
+
* Resolve a device (+ optional stream, + force) to renderable JPEG bytes for
|
|
74
|
+
* the HTTP endpoint. Runs the same coalesced capture ladder as the tRPC
|
|
75
|
+
* `getSnapshot` (so every consumer shares one upstream pull), then decodes the
|
|
76
|
+
* base64 cache into raw bytes and stamps the frame identity: `capturedAt` from
|
|
77
|
+
* the cache entry (matching the ETag `getSnapshotOverview` advertises) and the
|
|
78
|
+
* effective per-device `maxAgeS` for `Cache-Control`. Null → 404.
|
|
79
|
+
*/
|
|
80
|
+
private resolveSnapshotMedia;
|
|
55
81
|
protected onShutdown(): Promise<void>;
|
|
56
82
|
/**
|
|
57
83
|
* Drop the cached ingest owner whenever addon-level settings change —
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-C3uHEBtP.js");
|
|
7
7
|
let node_fs = require("node:fs");
|
|
8
8
|
node_fs = require_chunk.__toESM(node_fs);
|
|
9
9
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as filesystemBrowseCapability, Z as storageProviderCapability, rt as BaseAddon } from "../../dist-
|
|
1
|
+
import { D as filesystemBrowseCapability, Z as storageProviderCapability, rt as BaseAddon } from "../../dist-BWQX9yUj.mjs";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path$1 from "node:path";
|
|
4
4
|
import { basename, dirname, join, resolve, sep } from "node:path";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-C3uHEBtP.js");
|
|
7
7
|
let node_crypto = require("node:crypto");
|
|
8
8
|
let better_sqlite3 = require("better-sqlite3");
|
|
9
9
|
better_sqlite3 = require_chunk.__toESM(better_sqlite3);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ct as parseJsonUnknown, J as settingsStoreCapability, nt as errMsg, pt as asJsonObject, rt as BaseAddon, s as RUNTIME_DEFAULTS } from "../../dist-BWQX9yUj.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import Database from "better-sqlite3";
|
|
4
4
|
//#region src/builtins/sqlite-storage/sqlite-settings-backend.ts
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-C3uHEBtP.js");
|
|
7
7
|
let node_path = require("node:path");
|
|
8
8
|
node_path = require_chunk.__toESM(node_path);
|
|
9
9
|
let node_fs_promises = require("node:fs/promises");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { St as parseJsonObject, X as storageCapability, rt as BaseAddon, u as StorageLocationTypeSchema } from "../../dist-BWQX9yUj.mjs";
|
|
2
2
|
import * as path$1 from "node:path";
|
|
3
3
|
import * as fs from "node:fs/promises";
|
|
4
4
|
import { buildStorageLocationRegistry } from "@camstack/system";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-C3uHEBtP.js");
|
|
7
7
|
//#region src/builtins/system-config/system-config.addon.ts
|
|
8
8
|
/**
|
|
9
9
|
* Built-in `system-config` addon — Phase 4 of the settings redesign.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { bt as hydrateSchema, nt as errMsg, rt as BaseAddon } from "../../dist-BWQX9yUj.mjs";
|
|
2
2
|
//#region src/builtins/system-config/system-config.addon.ts
|
|
3
3
|
/**
|
|
4
4
|
* Built-in `system-config` addon — Phase 4 of the settings redesign.
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-C3uHEBtP.js");
|
|
7
7
|
const require_formatter = require("../../formatter-DqAKDlvN.js");
|
|
8
8
|
let node_path = require("node:path");
|
|
9
9
|
node_path = require_chunk.__toESM(node_path);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { I as logDestinationCapability, rt as BaseAddon } from "../../dist-
|
|
1
|
+
import { I as logDestinationCapability, rt as BaseAddon } from "../../dist-BWQX9yUj.mjs";
|
|
2
2
|
import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
|
|
3
3
|
import * as path$1 from "node:path";
|
|
4
4
|
import path from "node:path";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
//#region ../types/dist/
|
|
2
|
+
//#region ../types/dist/event-category-CFZs3jI4.mjs
|
|
3
3
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4
4
|
EventCategory["SystemBoot"] = "system.boot";
|
|
5
5
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -17952,7 +17952,15 @@ var webrtcSessionCapability = {
|
|
|
17952
17952
|
*/
|
|
17953
17953
|
disableIpv6: z.boolean().optional(),
|
|
17954
17954
|
/** Subscriber attribution. See `createSession` for the contract. */
|
|
17955
|
-
consumerAttribution: BrokerConsumerAttributionSchema.optional()
|
|
17955
|
+
consumerAttribution: BrokerConsumerAttributionSchema.optional(),
|
|
17956
|
+
/**
|
|
17957
|
+
* Client-side stream hints (viewport, downlink) — same contract as
|
|
17958
|
+
* `createSession.hints`. Client-offer viewers (the RN viewer's
|
|
17959
|
+
* `WebrtcLiveSession`) negotiate via `handleOffer`, so without this
|
|
17960
|
+
* field their hints were silently stripped by the schema and the
|
|
17961
|
+
* adaptive ladder started blind on the client's display size.
|
|
17962
|
+
*/
|
|
17963
|
+
hints: webrtcClientHintsSchema.optional()
|
|
17956
17964
|
}), z.object({
|
|
17957
17965
|
sessionId: z.string(),
|
|
17958
17966
|
sdpAnswer: z.string()
|
|
@@ -26318,4 +26326,4 @@ function scoreRuntimes(hw) {
|
|
|
26318
26326
|
};
|
|
26319
26327
|
}
|
|
26320
26328
|
//#endregion
|
|
26321
|
-
export { toExpressionValue as $, isCollectionArrayMethod as A, normalizeUnit as B, enumerateItemArrayFields as C,
|
|
26329
|
+
export { toExpressionValue as $, isCollectionArrayMethod as A, normalizeUnit as B, enumerateItemArrayFields as C, parseJsonUnknown as Ct, filesystemBrowseCapability as D, sleep as Dt, extractNestedAddonId as E, scopeKey as Et, localNetworkCapability as F, readNodePin as G, parseStreamParamsFormPatch as H, logDestinationCapability as I, settingsStoreCapability as J, scoreRuntimes as K, looseSchema as L, isVoidInput as M, kebabToCamel as N, getByPath as O, EventCategory as Ot, lifecycleJobSchema as P, streamQualityLabel as Q, metricsProviderCapability as R, deviceStatusCapability as S, parseJsonObject as St, evaluateLinkExpression as T, resolveCapMount as Tt, platformProbeCapability as U, objectInputDeclaresAddonId as V, procedureAuthKey as W, storageCapability as X, snapshotCapability as Y, storageProviderCapability as Z, authProviderCapability as _, emitDownForOwnedCaps as _t, DeviceStatusSchema as a, DEVICE_SETTINGS_CONTRIBUTION_METHODS as at, deviceManagerCapability as b, hydrateSchema as bt, STREAM_PROFILE_META as c, DeviceRole as ct, UserRecordSchema as d, ReadinessTimeoutError as dt, userManagementCapability as et, addonPagesCapability as f, WELL_KNOWN_TAB_MAP as ft, applyTransform as g, createEvent as gt, alertsCapability as h, asString as ht, CAP_NAMES_WITH_STATUS as i, DATAPLANE_SECRET_HEADER as it, isObjectInput as j, isArrayOutputSchema as k, ScopedTokenSchema as l, DeviceType as lt, addonWidgetsCapability as m, asNumber as mt, AlertSchema as n, errMsg as nt, METHOD_ACCESS_MAP as o, DEVICE_STATUS_METHOD as ot, addonSettingsCapability as p, asJsonObject as pt, setByPath as q, ApiKeyRecordSchema as r, BaseAddon as rt, RUNTIME_DEFAULTS as s, DeviceFeature as st, ALL_CAPABILITY_DEFINITIONS as t, validateExpressionSource as tt, StorageLocationTypeSchema as u, ReadinessRegistry as ut, backupCapability as v, emitReadiness as vt, enumerateSchemaFields as w, readinessKey as wt, deviceStateCapability as x, isDeviceConfigCap as xt, buildStreamParamsConfigSchema as y, expandCapMethods as yt, nodePin as z };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
let zod = require("zod");
|
|
2
|
-
//#region ../types/dist/
|
|
2
|
+
//#region ../types/dist/event-category-CFZs3jI4.mjs
|
|
3
3
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4
4
|
EventCategory["SystemBoot"] = "system.boot";
|
|
5
5
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -17952,7 +17952,15 @@ var webrtcSessionCapability = {
|
|
|
17952
17952
|
*/
|
|
17953
17953
|
disableIpv6: zod.z.boolean().optional(),
|
|
17954
17954
|
/** Subscriber attribution. See `createSession` for the contract. */
|
|
17955
|
-
consumerAttribution: BrokerConsumerAttributionSchema.optional()
|
|
17955
|
+
consumerAttribution: BrokerConsumerAttributionSchema.optional(),
|
|
17956
|
+
/**
|
|
17957
|
+
* Client-side stream hints (viewport, downlink) — same contract as
|
|
17958
|
+
* `createSession.hints`. Client-offer viewers (the RN viewer's
|
|
17959
|
+
* `WebrtcLiveSession`) negotiate via `handleOffer`, so without this
|
|
17960
|
+
* field their hints were silently stripped by the schema and the
|
|
17961
|
+
* adaptive ladder started blind on the client's display size.
|
|
17962
|
+
*/
|
|
17963
|
+
hints: webrtcClientHintsSchema.optional()
|
|
17956
17964
|
}), zod.z.object({
|
|
17957
17965
|
sessionId: zod.z.string(),
|
|
17958
17966
|
sdpAnswer: zod.z.string()
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export { proxyToUpstream } from './http/reverse-proxy.js';
|
|
|
10
10
|
export type { ReverseProxyOptions } from './http/reverse-proxy.js';
|
|
11
11
|
export { createFileDataPlaneHandler } from './http/file-data-plane.js';
|
|
12
12
|
export type { FileDataPlaneOptions } from './http/file-data-plane.js';
|
|
13
|
+
export { createAddonDataPlaneFacility } from './kernel/moleculer/addon-data-plane-facility.js';
|
|
14
|
+
export type { AddonDataPlaneFacility, DataPlaneSink, } from './kernel/moleculer/addon-data-plane-facility.js';
|
|
13
15
|
export { downloadModel, downloadFile, fetchJson, ensureModel, getModelFilePath, isModelDownloaded, deleteModelFromDisk, collectModelFiles, } from './download/model-downloader.js';
|
|
14
16
|
export type { DownloadProgressCallback } from './download/model-downloader.js';
|
|
15
17
|
export { ModelDownloadService } from './download/model-download-service.js';
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
3
|
-
const require_dist = require("./dist-
|
|
3
|
+
const require_dist = require("./dist-C3uHEBtP.js");
|
|
4
4
|
const require_model_download_service = require("./model-download-service-D-Umz4-L.js");
|
|
5
|
+
const require_manifest_python_deps = require("./manifest-python-deps-CVcJ9hDX.js");
|
|
5
6
|
const require_resource_monitor = require("./resource-monitor-DNNomR-i.js");
|
|
6
7
|
const require_builtins_sqlite_storage_filesystem_storage_addon = require("./builtins/sqlite-storage/filesystem-storage.addon.js");
|
|
7
8
|
const require_builtins_sqlite_storage_sqlite_settings_addon = require("./builtins/sqlite-storage/sqlite-settings.addon.js");
|
|
@@ -21,7 +22,6 @@ const require_builtins_local_auth_local_auth_addon = require("./builtins/local-a
|
|
|
21
22
|
require("./builtins/local-auth/index.js");
|
|
22
23
|
const require_builtins_device_manager_device_manager_addon = require("./builtins/device-manager/device-manager.addon.js");
|
|
23
24
|
require("./builtins/device-manager/index.js");
|
|
24
|
-
const require_manifest_python_deps = require("./manifest-python-deps-Wy8dNJpr.js");
|
|
25
25
|
const require_custom_action_registry = require("./custom-action-registry-vLYEFTtv.js");
|
|
26
26
|
let _camstack_types_node = require("@camstack/types/node");
|
|
27
27
|
let zod = require("zod");
|
|
@@ -32,6 +32,7 @@ node_fs = require_chunk.__toESM(node_fs);
|
|
|
32
32
|
let node_path = require("node:path");
|
|
33
33
|
node_path = require_chunk.__toESM(node_path, 1);
|
|
34
34
|
let node_crypto = require("node:crypto");
|
|
35
|
+
let _camstack_types_addon = require("@camstack/types/addon");
|
|
35
36
|
let node_child_process = require("node:child_process");
|
|
36
37
|
let node_util = require("node:util");
|
|
37
38
|
node_util = require_chunk.__toESM(node_util);
|
|
@@ -40,7 +41,6 @@ node_vm = require_chunk.__toESM(node_vm);
|
|
|
40
41
|
let node_os = require("node:os");
|
|
41
42
|
node_os = require_chunk.__toESM(node_os);
|
|
42
43
|
let node_fs_promises = require("node:fs/promises");
|
|
43
|
-
let _camstack_types_addon = require("@camstack/types/addon");
|
|
44
44
|
let node_events = require("node:events");
|
|
45
45
|
let node_stream = require("node:stream");
|
|
46
46
|
node_stream = require_chunk.__toESM(node_stream, 1);
|
|
@@ -3064,6 +3064,24 @@ var AddonInstaller = class AddonInstaller {
|
|
|
3064
3064
|
else this.installSource = "npm";
|
|
3065
3065
|
}
|
|
3066
3066
|
/**
|
|
3067
|
+
* Where a bootstrapped npm lives when the host has none on PATH (packaged
|
|
3068
|
+
* Electron agents ship a bare node binary). Persistent — sibling of the
|
|
3069
|
+
* installed addons, survives restarts, downloaded at most once per host.
|
|
3070
|
+
*/
|
|
3071
|
+
get npmCacheDir() {
|
|
3072
|
+
return node_path.join(this.addonsDir, ".npm-bootstrap");
|
|
3073
|
+
}
|
|
3074
|
+
/** Shared options for every npm invocation this installer performs. */
|
|
3075
|
+
npmRunOptions(cwd, timeout) {
|
|
3076
|
+
return {
|
|
3077
|
+
cacheDir: this.npmCacheDir,
|
|
3078
|
+
registry: this.registry,
|
|
3079
|
+
logger: this.logger,
|
|
3080
|
+
cwd,
|
|
3081
|
+
timeout
|
|
3082
|
+
};
|
|
3083
|
+
}
|
|
3084
|
+
/**
|
|
3067
3085
|
* Derive the bootstrap addon list from a meta-package's runtime dependencies.
|
|
3068
3086
|
* Single source of truth: the meta-package's `package.json` declares which
|
|
3069
3087
|
* `@camstack/addon-*` packages the deployment needs. Replaces previously
|
|
@@ -3247,17 +3265,16 @@ var AddonInstaller = class AddonInstaller {
|
|
|
3247
3265
|
});
|
|
3248
3266
|
const strippedDeps = stripBundledDeps(pkgData);
|
|
3249
3267
|
if (strippedDeps["dependencies"] && typeof strippedDeps["dependencies"] === "object" && Object.keys(strippedDeps["dependencies"]).length > 0) try {
|
|
3250
|
-
await
|
|
3268
|
+
await require_manifest_python_deps.runNpm([
|
|
3251
3269
|
"install",
|
|
3252
3270
|
"--omit=dev",
|
|
3253
3271
|
"--ignore-scripts=false"
|
|
3254
|
-
],
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
} catch {}
|
|
3272
|
+
], this.npmRunOptions(targetDir, 12e4));
|
|
3273
|
+
} catch (err) {
|
|
3274
|
+
this.logger.warn(`${packageName} — npm install failed (continuing)`, { meta: { error: require_dist.errMsg(err) } });
|
|
3275
|
+
}
|
|
3259
3276
|
try {
|
|
3260
|
-
await require_manifest_python_deps.installManifestNativeDeps(targetDir, pkgData, this.logger, this.registry);
|
|
3277
|
+
await require_manifest_python_deps.installManifestNativeDeps(targetDir, pkgData, this.logger, this.registry, this.npmCacheDir);
|
|
3261
3278
|
} catch (err) {
|
|
3262
3279
|
this.logger.warn(`${packageName} — native deps install failed (continuing)`, { meta: { error: require_dist.errMsg(err) } });
|
|
3263
3280
|
}
|
|
@@ -3288,7 +3305,7 @@ var AddonInstaller = class AddonInstaller {
|
|
|
3288
3305
|
tmpDir
|
|
3289
3306
|
];
|
|
3290
3307
|
if (this.registry) args.push("--registry", this.registry);
|
|
3291
|
-
const { stdout } = await
|
|
3308
|
+
const { stdout } = await require_manifest_python_deps.runNpm(args, this.npmRunOptions(tmpDir, 12e4));
|
|
3292
3309
|
const tgzFiles = node_fs.readdirSync(tmpDir).filter((f) => f.endsWith(".tgz"));
|
|
3293
3310
|
if (tgzFiles.length === 0) throw new Error(`npm pack produced no tgz. stdout: ${stdout.trim()}`);
|
|
3294
3311
|
return node_path.join(tmpDir, tgzFiles[0]);
|
|
@@ -3429,7 +3446,7 @@ var AddonInstaller = class AddonInstaller {
|
|
|
3429
3446
|
if (strippedRuntimeDeps != null && typeof strippedRuntimeDeps === "object" && Object.keys(strippedRuntimeDeps).length > 0) {
|
|
3430
3447
|
this.logger.info(`${pkgView.name} — installing runtime dependencies`, { meta: { stagingDir: pkgDir } });
|
|
3431
3448
|
try {
|
|
3432
|
-
await
|
|
3449
|
+
await require_manifest_python_deps.runNpm([
|
|
3433
3450
|
"install",
|
|
3434
3451
|
"--omit=dev",
|
|
3435
3452
|
"--omit=peer",
|
|
@@ -3437,16 +3454,13 @@ var AddonInstaller = class AddonInstaller {
|
|
|
3437
3454
|
"--no-fund",
|
|
3438
3455
|
"--no-package-lock",
|
|
3439
3456
|
...this.registry ? ["--registry", this.registry] : []
|
|
3440
|
-
],
|
|
3441
|
-
cwd: pkgDir,
|
|
3442
|
-
timeout: 24e4
|
|
3443
|
-
});
|
|
3457
|
+
], this.npmRunOptions(pkgDir, 24e4));
|
|
3444
3458
|
} catch (err) {
|
|
3445
|
-
|
|
3459
|
+
throw new Error(`${pkgView.name} — runtime dependency install failed: ${require_dist.errMsg(err)}`, { cause: err });
|
|
3446
3460
|
}
|
|
3447
3461
|
}
|
|
3448
3462
|
try {
|
|
3449
|
-
await require_manifest_python_deps.installManifestNativeDeps(pkgDir, pkgView.raw, this.logger, this.registry);
|
|
3463
|
+
await require_manifest_python_deps.installManifestNativeDeps(pkgDir, pkgView.raw, this.logger, this.registry, this.npmCacheDir);
|
|
3450
3464
|
} catch (nativeErr) {
|
|
3451
3465
|
throw new Error(`${pkgView.name} — native deps install failed: ${require_dist.errMsg(nativeErr)}`, { cause: nativeErr });
|
|
3452
3466
|
}
|
|
@@ -3748,10 +3762,7 @@ var AddonInstaller = class AddonInstaller {
|
|
|
3748
3762
|
if (!(!node_fs.existsSync(distDir) || this.isDistIncomplete(pkgData, sourceDir))) return;
|
|
3749
3763
|
this.logger.info(`${packageName} — building (dist/ missing or incomplete)`);
|
|
3750
3764
|
try {
|
|
3751
|
-
await
|
|
3752
|
-
cwd: sourceDir,
|
|
3753
|
-
timeout: 18e4
|
|
3754
|
-
});
|
|
3765
|
+
await require_manifest_python_deps.runNpm(["run", "build"], this.npmRunOptions(sourceDir, 18e4));
|
|
3755
3766
|
} catch (err) {
|
|
3756
3767
|
const msg = require_dist.errMsg(err);
|
|
3757
3768
|
this.logger.warn(`${packageName} auto-build failed`, { meta: { error: msg } });
|
|
@@ -93515,6 +93526,7 @@ exports.contentTypeFor = require_model_download_service.contentTypeFor;
|
|
|
93515
93526
|
exports.copyDirRecursive = copyDirRecursive;
|
|
93516
93527
|
exports.copyExtraFileDirs = copyExtraFileDirs;
|
|
93517
93528
|
exports.createAddonContext = require_manifest_python_deps.createAddonContext;
|
|
93529
|
+
exports.createAddonDataPlaneFacility = require_manifest_python_deps.createAddonDataPlaneFacility;
|
|
93518
93530
|
exports.createAddonService = require_manifest_python_deps.createAddonService;
|
|
93519
93531
|
exports.createAuthenticatedFileServer = require_model_download_service.createAuthenticatedFileServer;
|
|
93520
93532
|
exports.createBroker = createBroker;
|